1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: monster_incubus.cpp
5 	Desc: implements all of the incubus monster's code
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "game.hpp"
14 #include "stat.hpp"
15 #include "entity.hpp"
16 #include "items.hpp"
17 #include "monster.hpp"
18 #include "sound.hpp"
19 #include "net.hpp"
20 #include "collision.hpp"
21 #include "player.hpp"
22 #include "magic/magic.hpp"
23 
initIncubus(Entity * my,Stat * myStats)24 void initIncubus(Entity* my, Stat* myStats)
25 {
26 	int c;
27 	node_t* node;
28 
29 	//Sprite 445 = incubus head sprite
30 	my->initMonster(445);
31 
32 	if ( multiplayer != CLIENT )
33 	{
34 		MONSTER_SPOTSND = 282;
35 		MONSTER_SPOTVAR = 3;
36 		MONSTER_IDLESND = 276;
37 		MONSTER_IDLEVAR = 3;
38 	}
39 	if ( multiplayer != CLIENT && !MONSTER_INIT )
40 	{
41 		if ( myStats != nullptr )
42 		{
43 			if ( !myStats->leader_uid )
44 			{
45 				myStats->leader_uid = 0;
46 			}
47 
48 			if ( !strncmp(myStats->name, "inner demon", strlen("inner demon")) )
49 			{
50 				Entity* parent = uidToEntity(my->parent);
51 				if ( !parent )
52 				{
53 					myStats->HP = 0;
54 				}
55 				else
56 				{
57 					Stat* parentStats = parent->getStats();
58 					if ( !parentStats )
59 					{
60 						myStats->HP = 0;
61 					}
62 					else
63 					{
64 						myStats->HP = parentStats->HP;
65 						myStats->MAXHP = myStats->HP;
66 						myStats->OLDHP = myStats->HP;
67 						myStats->STR = -999;
68 						myStats->DEX = std::min(parentStats->DEX, 15);
69 						// pretend the parent wasn't defending as this gets added in AC() call.
70 						bool wasDefending = parentStats->defending;
71 						parentStats->defending = false;
72 						myStats->CON = AC(parentStats);
73 						parentStats->defending = wasDefending;
74 
75 						myStats->INT = parentStats->INT;
76 						myStats->PER = parentStats->PER;
77 						myStats->CHR = parentStats->CHR;
78 						myStats->LVL = parentStats->LVL;
79 						myStats->GOLD = 0;
80 
81 						myStats->weapon = newItem(TOOL_WHIP, EXCELLENT, 0, 1, MONSTER_ITEM_UNDROPPABLE_APPEARANCE, true, nullptr);
82 						/*if ( parentStats->shield )
83 						{
84 							myStats->shield = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
85 							copyItem(myStats->shield, parentStats->shield);
86 							myStats->shield->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
87 						}
88 						if ( parentStats->helmet )
89 						{
90 							myStats->helmet = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
91 							copyItem(myStats->helmet, parentStats->helmet);
92 							myStats->helmet->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
93 						}
94 						if ( parentStats->breastplate )
95 						{
96 							myStats->breastplate = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
97 							copyItem(myStats->breastplate, parentStats->breastplate);
98 							myStats->breastplate->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
99 						}
100 						if ( parentStats->shoes )
101 						{
102 							myStats->shoes = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
103 							copyItem(myStats->shoes, parentStats->shoes);
104 							myStats->shoes->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
105 						}
106 						if ( parentStats->gloves )
107 						{
108 							myStats->gloves = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
109 							copyItem(myStats->gloves, parentStats->gloves);
110 							myStats->gloves->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
111 						}
112 						if ( parentStats->cloak )
113 						{
114 							myStats->cloak = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
115 							copyItem(myStats->cloak, parentStats->cloak);
116 							myStats->cloak->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
117 						}
118 						if ( parentStats->ring )
119 						{
120 							myStats->ring = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
121 							copyItem(myStats->ring, parentStats->ring);
122 							myStats->ring->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
123 						}
124 						if ( parentStats->amulet )
125 						{
126 							myStats->amulet = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
127 							copyItem(myStats->amulet, parentStats->amulet);
128 							myStats->amulet->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
129 						}
130 						if ( parentStats->mask )
131 						{
132 							myStats->mask = newItem(BRONZE_SWORD, EXCELLENT, 0, 1, 0, true, nullptr);
133 							copyItem(myStats->mask, parentStats->mask);
134 							myStats->mask->appearance = MONSTER_ITEM_UNDROPPABLE_APPEARANCE;
135 						}*/
136 					}
137 				}
138 			}
139 			else
140 			{
141 				bool lesserMonster = false;
142 				if ( !strncmp(myStats->name, "lesser incubus", strlen("lesser incubus")) )
143 				{
144 					lesserMonster = true;
145 					myStats->HP = 80;
146 					myStats->MAXHP = myStats->HP;
147 					myStats->OLDHP = myStats->HP;
148 					myStats->STR = 12;
149 					myStats->DEX = 6;
150 					myStats->CON = 3;
151 					myStats->INT = -2;
152 					myStats->PER = 5;
153 					myStats->CHR = 5;
154 					myStats->EXP = 0;
155 					myStats->LVL = 15;
156 				}
157 				// apply random stat increases if set in stat_shared.cpp or editor
158 				setRandomMonsterStats(myStats);
159 
160 				// generate 6 items max, less if there are any forced items from boss variants
161 				int customItemsToGenerate = ITEM_CUSTOM_SLOT_LIMIT;
162 
163 				// boss variants
164 				if ( rand() % 50 || my->flags[USERFLAG2] || myStats->MISC_FLAGS[STAT_FLAG_DISABLE_MINIBOSS] )
165 				{
166 
167 				}
168 				else
169 				{
170 					/*myStats->DEX = 10;
171 					strcpy(myStats->name, "Lilith");
172 					for ( c = 0; c < 2; c++ )
173 					{
174 						Entity* entity = summonMonster(SUCCUBUS, my->x, my->y);
175 						if ( entity )
176 						{
177 							entity->parent = my->getUID();
178 						}
179 					}*/
180 				}
181 
182 				// random effects
183 
184 				// generates equipment and weapons if available from editor
185 				createMonsterEquipment(myStats);
186 
187 				// create any custom inventory items from editor if available
188 				createCustomInventory(myStats, customItemsToGenerate);
189 
190 				// count if any custom inventory items from editor
191 				int customItems = countCustomItems(myStats); //max limit of 6 custom items per entity.
192 
193 															 // count any inventory items set to default in edtior
194 				int defaultItems = countDefaultItems(myStats);
195 
196 				my->setHardcoreStats(*myStats);
197 
198 				// always give special spell to incubus, undroppable.
199 				newItem(SPELLBOOK_STEAL_WEAPON, DECREPIT, 0, 1, MONSTER_ITEM_UNDROPPABLE_APPEARANCE, false, &myStats->inventory);
200 				newItem(SPELLBOOK_CHARM_MONSTER, DECREPIT, 0, 1, MONSTER_ITEM_UNDROPPABLE_APPEARANCE, false, &myStats->inventory);
201 
202 				if ( rand() % 4 == 0 ) // 1 in 4
203 				{
204 					newItem(POTION_CONFUSION, SERVICABLE, 0, 0 + rand() % 3, MONSTER_ITEM_UNDROPPABLE_APPEARANCE, false, &myStats->inventory);
205 				}
206 				else // 3 in 4
207 				{
208 					newItem(POTION_BOOZE, SERVICABLE, 0, 1 + rand() % 3, MONSTER_ITEM_UNDROPPABLE_APPEARANCE, false, &myStats->inventory);
209 				}
210 
211 
212 				// generate the default inventory items for the monster, provided the editor sprite allowed enough default slots
213 				switch ( defaultItems )
214 				{
215 					case 6:
216 					case 5:
217 					case 4:
218 					case 3:
219 						if ( rand() % 2 == 0 && !lesserMonster ) // 1 in 2
220 						{
221 							newItem(MAGICSTAFF_COLD, SERVICABLE, 0, 1, rand(), false, &myStats->inventory);
222 						}
223 					case 2:
224 						if ( rand() % 5 == 0 ) // 1 in 5
225 						{
226 							newItem(POTION_CONFUSION, SERVICABLE, 0, 1 + rand() % 2, rand(), false, &myStats->inventory);
227 						}
228 					case 1:
229 						if ( rand() % 3 == 0 ) // 1 in 3
230 						{
231 							newItem(POTION_BOOZE, SERVICABLE, 0, 1 + rand() % 3, rand(), false, &myStats->inventory);
232 						}
233 						break;
234 					default:
235 						break;
236 				}
237 
238 				//give weapon
239 				if ( lesserMonster )
240 				{
241 					if ( myStats->weapon == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_WEAPON] == 1 )
242 					{
243 						switch ( rand() % 10 )
244 						{
245 							case 0:
246 							case 1:
247 								myStats->weapon = newItem(CROSSBOW, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
248 								break;
249 							case 2:
250 							case 3:
251 							case 4:
252 							case 5:
253 							case 6:
254 							case 7:
255 							case 8:
256 								myStats->weapon = newItem(STEEL_HALBERD, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
257 								break;
258 							case 9:
259 								myStats->weapon = newItem(MAGICSTAFF_COLD, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
260 								break;
261 						}
262 					}
263 				}
264 				else if ( myStats->weapon == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_WEAPON] == 1 )
265 				{
266 					switch ( rand() % 10 )
267 					{
268 						case 0:
269 						case 1:
270 						case 2:
271 						case 3:
272 							myStats->weapon = newItem(CRYSTAL_SPEAR, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
273 							break;
274 						case 4:
275 						case 5:
276 						case 6:
277 							myStats->weapon = newItem(CROSSBOW, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
278 							break;
279 						case 7:
280 						case 8:
281 							myStats->weapon = newItem(STEEL_HALBERD, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
282 							break;
283 						case 9:
284 							myStats->weapon = newItem(MAGICSTAFF_COLD, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
285 							break;
286 					}
287 				}
288 
289 				// give shield
290 				if ( myStats->shield == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_SHIELD] == 1 )
291 				{
292 					if ( myStats->weapon && isRangedWeapon(*myStats->weapon) )
293 					{
294 						my->monsterGenerateQuiverItem(myStats);
295 					}
296 					else
297 					{
298 						switch ( rand() % 10 )
299 						{
300 							case 0:
301 							case 1:
302 							case 2:
303 							case 3:
304 							case 4:
305 							case 5:
306 							case 6:
307 							case 7:
308 								break;
309 							case 8:
310 							case 9:
311 								myStats->shield = newItem(MIRROR_SHIELD, static_cast<Status>(WORN + rand() % 2), -1 + rand() % 3, 1, rand(), false, nullptr);
312 								break;
313 						}
314 					}
315 				}
316 			}
317 		}
318 	}
319 
320 	// torso
321 	Entity* entity = newEntity(446, 0, map.entities, nullptr); //Limb entity.
322 	entity->sizex = 4;
323 	entity->sizey = 4;
324 	entity->skill[2] = my->getUID();
325 	entity->flags[PASSABLE] = true;
326 	entity->flags[NOUPDATE] = true;
327 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
328 	entity->focalx = limbs[INCUBUS][1][0]; // 0
329 	entity->focaly = limbs[INCUBUS][1][1]; // 0
330 	entity->focalz = limbs[INCUBUS][1][2]; // 0
331 	entity->behavior = &actIncubusLimb;
332 	entity->parent = my->getUID();
333 	node = list_AddNodeLast(&my->children);
334 	node->element = entity;
335 	node->deconstructor = &emptyDeconstructor;
336 	node->size = sizeof(Entity*);
337 	my->bodyparts.push_back(entity);
338 
339 	// right leg
340 	entity = newEntity(450, 0, map.entities, nullptr); //Limb entity.
341 	entity->sizex = 4;
342 	entity->sizey = 4;
343 	entity->skill[2] = my->getUID();
344 	entity->flags[PASSABLE] = true;
345 	entity->flags[NOUPDATE] = true;
346 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
347 	entity->focalx = limbs[INCUBUS][2][0]; // 1
348 	entity->focaly = limbs[INCUBUS][2][1]; // 0
349 	entity->focalz = limbs[INCUBUS][2][2]; // 2
350 	entity->behavior = &actIncubusLimb;
351 	entity->parent = my->getUID();
352 	node = list_AddNodeLast(&my->children);
353 	node->element = entity;
354 	node->deconstructor = &emptyDeconstructor;
355 	node->size = sizeof(Entity*);
356 	my->bodyparts.push_back(entity);
357 
358 	// left leg
359 	entity = newEntity(449, 0, map.entities, nullptr); //Limb entity.
360 	entity->sizex = 4;
361 	entity->sizey = 4;
362 	entity->skill[2] = my->getUID();
363 	entity->flags[PASSABLE] = true;
364 	entity->flags[NOUPDATE] = true;
365 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
366 	entity->focalx = limbs[INCUBUS][3][0]; // 1
367 	entity->focaly = limbs[INCUBUS][3][1]; // 0
368 	entity->focalz = limbs[INCUBUS][3][2]; // 2
369 	entity->behavior = &actIncubusLimb;
370 	entity->parent = my->getUID();
371 	node = list_AddNodeLast(&my->children);
372 	node->element = entity;
373 	node->deconstructor = &emptyDeconstructor;
374 	node->size = sizeof(Entity*);
375 	my->bodyparts.push_back(entity);
376 
377 	// right arm
378 	entity = newEntity(448, 0, map.entities, nullptr); //595 //Limb entity.
379 	entity->sizex = 4;
380 	entity->sizey = 4;
381 	entity->skill[2] = my->getUID();
382 	entity->flags[PASSABLE] = true;
383 	entity->flags[NOUPDATE] = true;
384 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
385 	entity->focalx = limbs[INCUBUS][4][0]; // -.25
386 	entity->focaly = limbs[INCUBUS][4][1]; // 0
387 	entity->focalz = limbs[INCUBUS][4][2]; // 1.5
388 	entity->behavior = &actIncubusLimb;
389 	entity->parent = my->getUID();
390 	node = list_AddNodeLast(&my->children);
391 	node->element = entity;
392 	node->deconstructor = &emptyDeconstructor;
393 	node->size = sizeof(Entity*);
394 	my->bodyparts.push_back(entity);
395 
396 	// left arm
397 	entity = newEntity(447, 0, map.entities, nullptr); //447 //Limb entity.
398 	entity->sizex = 4;
399 	entity->sizey = 4;
400 	entity->skill[2] = my->getUID();
401 	entity->flags[PASSABLE] = true;
402 	entity->flags[NOUPDATE] = true;
403 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
404 	entity->focalx = limbs[INCUBUS][5][0]; // -.25
405 	entity->focaly = limbs[INCUBUS][5][1]; // 0
406 	entity->focalz = limbs[INCUBUS][5][2]; // 1.5
407 	entity->behavior = &actIncubusLimb;
408 	entity->parent = my->getUID();
409 	node = list_AddNodeLast(&my->children);
410 	node->element = entity;
411 	node->deconstructor = &emptyDeconstructor;
412 	node->size = sizeof(Entity*);
413 	my->bodyparts.push_back(entity);
414 
415 	// world weapon
416 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
417 	entity->sizex = 4;
418 	entity->sizey = 4;
419 	entity->skill[2] = my->getUID();
420 	entity->flags[PASSABLE] = true;
421 	entity->flags[NOUPDATE] = true;
422 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
423 	entity->focalx = limbs[INCUBUS][6][0]; //
424 	entity->focaly = limbs[INCUBUS][6][1]; //
425 	entity->focalz = limbs[INCUBUS][6][2]; //
426 	entity->behavior = &actIncubusLimb;
427 	entity->parent = my->getUID();
428 	entity->pitch = .25;
429 	node = list_AddNodeLast(&my->children);
430 	node->element = entity;
431 	node->deconstructor = &emptyDeconstructor;
432 	node->size = sizeof(Entity*);
433 	my->bodyparts.push_back(entity);
434 
435 	// shield
436 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
437 	entity->sizex = 4;
438 	entity->sizey = 4;
439 	entity->skill[2] = my->getUID();
440 	entity->flags[PASSABLE] = true;
441 	entity->flags[NOUPDATE] = true;
442 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
443 	entity->focalx = limbs[INCUBUS][7][0]; //
444 	entity->focaly = limbs[INCUBUS][7][1]; //
445 	entity->focalz = limbs[INCUBUS][7][2]; //
446 	entity->behavior = &actIncubusLimb;
447 	entity->parent = my->getUID();
448 	node = list_AddNodeLast(&my->children);
449 	node->element = entity;
450 	node->deconstructor = &emptyDeconstructor;
451 	node->size = sizeof(Entity*);
452 	my->bodyparts.push_back(entity);
453 
454 	// cloak
455 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
456 	entity->sizex = 4;
457 	entity->sizey = 4;
458 	entity->skill[2] = my->getUID();
459 	entity->scalex = 1.01;
460 	entity->scaley = 1.01;
461 	entity->scalez = 1.01;
462 	entity->flags[PASSABLE] = true;
463 	entity->flags[NOUPDATE] = true;
464 	entity->flags[INVISIBLE] = true;
465 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
466 	entity->focalx = limbs[INCUBUS][8][0]; // 0
467 	entity->focaly = limbs[INCUBUS][8][1]; // 0
468 	entity->focalz = limbs[INCUBUS][8][2]; // 4
469 	entity->behavior = &actIncubusLimb;
470 	entity->parent = my->getUID();
471 	node = list_AddNodeLast(&my->children);
472 	node->element = entity;
473 	node->deconstructor = &emptyDeconstructor;
474 	node->size = sizeof(Entity*);
475 	my->bodyparts.push_back(entity);
476 
477 	// helmet
478 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
479 	entity->sizex = 4;
480 	entity->sizey = 4;
481 	entity->skill[2] = my->getUID();
482 	entity->scalex = 1.01;
483 	entity->scaley = 1.01;
484 	entity->scalez = 1.01;
485 	entity->flags[PASSABLE] = true;
486 	entity->flags[NOUPDATE] = true;
487 	entity->flags[INVISIBLE] = true;
488 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
489 	entity->focalx = limbs[INCUBUS][9][0]; // 0
490 	entity->focaly = limbs[INCUBUS][9][1]; // 0
491 	entity->focalz = limbs[INCUBUS][9][2]; // -2
492 	entity->behavior = &actIncubusLimb;
493 	entity->parent = my->getUID();
494 	node = list_AddNodeLast(&my->children);
495 	node->element = entity;
496 	node->deconstructor = &emptyDeconstructor;
497 	node->size = sizeof(Entity*);
498 	my->bodyparts.push_back(entity);
499 
500 	// mask
501 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
502 	entity->sizex = 4;
503 	entity->sizey = 4;
504 	entity->skill[2] = my->getUID();
505 	entity->flags[PASSABLE] = true;
506 	entity->flags[NOUPDATE] = true;
507 	entity->flags[INVISIBLE] = true;
508 	entity->flags[USERFLAG2] = my->flags[USERFLAG2];
509 	entity->focalx = limbs[INCUBUS][10][0]; // 0
510 	entity->focaly = limbs[INCUBUS][10][1]; // 0
511 	entity->focalz = limbs[INCUBUS][10][2]; // .5
512 	entity->behavior = &actIncubusLimb;
513 	entity->parent = my->getUID();
514 	node = list_AddNodeLast(&my->children);
515 	node->element = entity;
516 	node->deconstructor = &emptyDeconstructor;
517 	node->size = sizeof(Entity*);
518 	my->bodyparts.push_back(entity);
519 }
520 
actIncubusLimb(Entity * my)521 void actIncubusLimb(Entity* my)
522 {
523 	my->actMonsterLimb();
524 }
525 
incubusDie(Entity * my)526 void incubusDie(Entity* my)
527 {
528 	int c;
529 
530 	Stat* myStats = my->getStats();
531 	if ( myStats && !strncmp(myStats->name, "inner demon", strlen("inner demon")) )
532 	{
533 		// die, no blood.
534 		//spawnMagicEffectParticles(my->x, my->y, my->z, 171);
535 		createParticleErupt(my, 983);
536 		serverSpawnMiscParticles(my, PARTICLE_EFFECT_ERUPT, 983);
537 		//playSoundEntity(my, 279 + rand() % 3, 128);
538 		playSoundEntity(my, 178, 128);
539 		my->removeMonsterDeathNodes();
540 		list_RemoveNode(my->mynode);
541 		return;
542 	}
543 
544 	for ( c = 0; c < 5; c++ )
545 	{
546 		Entity* gib = spawnGib(my);
547 		serverSpawnGibForClient(gib);
548 	}
549 
550 	my->spawnBlood();
551 
552 	playSoundEntity(my, 279 + rand() % 3, 128);
553 
554 	my->removeMonsterDeathNodes();
555 
556 	list_RemoveNode(my->mynode);
557 	return;
558 }
559 
560 #define INCUBUSWALKSPEED .07
561 
incubusMoveBodyparts(Entity * my,Stat * myStats,double dist)562 void incubusMoveBodyparts(Entity* my, Stat* myStats, double dist)
563 {
564 	node_t* node;
565 	Entity* entity = nullptr, *entity2 = nullptr;
566 	Entity* rightbody = nullptr;
567 	Entity* weaponarm = nullptr;
568 	int bodypart;
569 	bool wearingring = false;
570 
571 	// set invisibility //TODO: isInvisible()?
572 	if ( multiplayer != CLIENT )
573 	{
574 		if ( myStats->ring != nullptr )
575 		{
576 			if ( myStats->ring->type == RING_INVISIBILITY )
577 			{
578 				wearingring = true;
579 			}
580 		}
581 		if ( myStats->cloak != nullptr )
582 		{
583 			if ( myStats->cloak->type == CLOAK_INVISIBILITY )
584 			{
585 				wearingring = true;
586 			}
587 		}
588 		if ( myStats->EFFECTS[EFF_INVISIBLE] == true )
589 		{
590 			my->flags[INVISIBLE] = true;
591 			my->flags[BLOCKSIGHT] = false;
592 			bodypart = 0;
593 			for (node = my->children.first; node != nullptr; node = node->next)
594 			{
595 				if ( bodypart < 2 )
596 				{
597 					bodypart++;
598 					continue;
599 				}
600 				if ( bodypart >= 7 )
601 				{
602 					break;
603 				}
604 				entity = (Entity*)node->element;
605 				if ( !entity->flags[INVISIBLE] )
606 				{
607 					entity->flags[INVISIBLE] = true;
608 					serverUpdateEntityBodypart(my, bodypart);
609 				}
610 				bodypart++;
611 			}
612 		}
613 		else
614 		{
615 			my->flags[INVISIBLE] = false;
616 			my->flags[BLOCKSIGHT] = true;
617 			bodypart = 0;
618 			for (node = my->children.first; node != nullptr; node = node->next)
619 			{
620 				if ( bodypart < 2 )
621 				{
622 					bodypart++;
623 					continue;
624 				}
625 				if ( bodypart >= 7 )
626 				{
627 					break;
628 				}
629 				entity = (Entity*)node->element;
630 				if ( entity->flags[INVISIBLE] )
631 				{
632 					entity->flags[INVISIBLE] = false;
633 					serverUpdateEntityBodypart(my, bodypart);
634 					serverUpdateEntityFlag(my, INVISIBLE);
635 				}
636 				bodypart++;
637 			}
638 		}
639 
640 		if ( !strncmp(myStats->name, "inner demon", strlen("inner demon")) )
641 		{
642 			Entity* parent = uidToEntity(my->parent);
643 			if ( !parent )
644 			{
645 				myStats->HP = 0;
646 			}
647 			else if ( my->ticks > TICKS_PER_SECOND * 5 )
648 			{
649 				myStats->HP = 0;
650 			}
651 		}
652 
653 		// sleeping
654 		if ( myStats->EFFECTS[EFF_ASLEEP] )
655 		{
656 			my->z = 1.5;
657 		}
658 		else
659 		{
660 			my->z = -1;
661 		}
662 	}
663 
664 	Entity* shieldarm = nullptr;
665 	Entity* helmet = nullptr;
666 
667 	//Move bodyparts
668 	for (bodypart = 0, node = my->children.first; node != nullptr; node = node->next, bodypart++)
669 	{
670 		if ( bodypart < LIMB_HUMANOID_TORSO )
671 		{
672 			// post-swing head animation. client doesn't need to adjust the entity pitch, server will handle.
673 			if ( multiplayer != CLIENT && bodypart == 1 )
674 			{
675 				if ( my->monsterAttack != MONSTER_POSE_MAGIC_WINDUP3
676 					&& my->monsterAttack != MONSTER_POSE_INCUBUS_TELEPORT
677 					&& my->monsterAttack != MONSTER_POSE_INCUBUS_TAUNT )
678 				{
679 					limbAnimateToLimit(my, ANIMATE_PITCH, 0.1, 0, false, 0.0);
680 				}
681 			}
682 			continue;
683 		}
684 		entity = (Entity*)node->element;
685 		entity->x = my->x;
686 		entity->y = my->y;
687 		entity->z = my->z;
688 		if ( MONSTER_ATTACK == MONSTER_POSE_MAGIC_WINDUP1 && bodypart == LIMB_HUMANOID_RIGHTARM )
689 		{
690 			// don't let the creatures's yaw move the casting arm
691 		}
692 		else
693 		{
694 			entity->yaw = my->yaw;
695 		}
696 		if ( bodypart == LIMB_HUMANOID_RIGHTLEG || bodypart == LIMB_HUMANOID_LEFTARM )
697 		{
698 			if ( bodypart == LIMB_HUMANOID_LEFTARM &&
699 				((my->monsterSpecialState == INCUBUS_STEAL && my->monsterAttack != 0 ) ||
700 				my->monsterAttack == MONSTER_POSE_INCUBUS_TELEPORT
701 					|| my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT) )
702 			{
703 				// leftarm follows the right arm during special steal state/teleport attack
704 				// will not work when shield is visible
705 				// else animate normally.
706 				node_t* shieldNode = list_Node(&my->children, 8);
707 				if ( shieldNode )
708 				{
709 					Entity* shield = (Entity*)shieldNode->element;
710 					if ( shield->flags[INVISIBLE] )
711 					{
712 						Entity* weaponarm = nullptr;
713 						node_t* weaponarmNode = list_Node(&my->children, LIMB_HUMANOID_RIGHTARM);
714 						if ( weaponarmNode )
715 						{
716 							weaponarm = (Entity*)weaponarmNode->element;
717 						}
718 						else
719 						{
720 							return;
721 						}
722 						entity->pitch = weaponarm->pitch;
723 						entity->roll = -weaponarm->roll;
724 					}
725 				}
726 			}
727 			else
728 			{
729 				my->humanoidAnimateWalk(entity, node, bodypart, INCUBUSWALKSPEED, dist, 0.4);
730 			}
731 		}
732 		else if ( bodypart == LIMB_HUMANOID_LEFTLEG || bodypart == LIMB_HUMANOID_RIGHTARM || bodypart == LIMB_HUMANOID_CLOAK )
733 		{
734 			// left leg, right arm, cloak.
735 			if ( bodypart == LIMB_HUMANOID_RIGHTARM )
736 			{
737 				weaponarm = entity;
738 				if ( my->monsterAttack > 0 )
739 				{
740 					Entity* rightbody = nullptr;
741 					// set rightbody to left leg.
742 					node_t* rightbodyNode = list_Node(&my->children, LIMB_HUMANOID_LEFTLEG);
743 					if ( rightbodyNode )
744 					{
745 						rightbody = (Entity*)rightbodyNode->element;
746 					}
747 					else
748 					{
749 						return;
750 					}
751 
752 					// potion special throw
753 					if ( my->monsterAttack == MONSTER_POSE_SPECIAL_WINDUP1 )
754 					{
755 						if ( my->monsterAttackTime == 0 )
756 						{
757 							// init rotations
758 							weaponarm->pitch = 0;
759 							my->monsterArmbended = 0;
760 							my->monsterWeaponYaw = 0;
761 							weaponarm->roll = 0;
762 							createParticleDot(my);
763 						}
764 
765 						limbAnimateToLimit(weaponarm, ANIMATE_PITCH, -0.25, 5 * PI / 4, false, 0.0);
766 
767 						if ( my->monsterAttackTime >= ANIMATE_DURATION_WINDUP * 4 / (monsterGlobalAnimationMultiplier / 10.0) )
768 						{
769 							if ( multiplayer != CLIENT )
770 							{
771 								my->attack(1, 0, nullptr);
772 							}
773 						}
774 						++my->monsterAttackTime;
775 					}
776 					else if ( my->monsterAttack == MONSTER_POSE_MAGIC_WINDUP3 )
777 					{
778 						if ( my->monsterAttackTime == 0 )
779 						{
780 							// init rotations
781 							weaponarm->pitch = 0;
782 							my->monsterArmbended = 0;
783 							my->monsterWeaponYaw = 0;
784 							weaponarm->roll = 0;
785 							weaponarm->skill[1] = 0;
786 							createParticleDot(my);
787 							// play casting sound
788 							playSoundEntityLocal(my, 170, 64);
789 							// monster scream
790 							playSoundEntityLocal(my, MONSTER_SPOTSND + 1, 128);
791 						}
792 
793 						limbAnimateToLimit(weaponarm, ANIMATE_PITCH, -0.25, 5 * PI / 4, false, 0.0);
794 						if ( multiplayer != CLIENT )
795 						{
796 							// move the head and weapon yaw
797 							limbAnimateToLimit(my, ANIMATE_PITCH, -0.1, 14 * PI / 8, true, 0.1);
798 							limbAnimateToLimit(my, ANIMATE_WEAPON_YAW, 0.25, 1 * PI / 8, false, 0.0);
799 						}
800 
801 						if ( my->monsterAttackTime >= 3 * ANIMATE_DURATION_WINDUP / (monsterGlobalAnimationMultiplier / 10.0) )
802 						{
803 							if ( multiplayer != CLIENT )
804 							{
805 								// throw the spell
806 								my->attack(MONSTER_POSE_MELEE_WINDUP1, 0, nullptr);
807 							}
808 						}
809 					}
810 					// teleport animation
811 					else if( my->monsterAttack == MONSTER_POSE_INCUBUS_TELEPORT
812 						|| my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT )
813 					{
814 						if ( my->monsterAttackTime == 0 )
815 						{
816 							// init rotations
817 							weaponarm->pitch = 0;
818 							my->monsterArmbended = 0;
819 							my->monsterWeaponYaw = 0;
820 							weaponarm->roll = 0;
821 							weaponarm->skill[1] = 0; // use this for direction of animation
822 							// monster scream
823 							if ( my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT )
824 							{
825 								playSoundEntityLocal(my, 276 + rand() % 3, 128);
826 							}
827 							else
828 							{
829 								playSoundEntityLocal(my, 282 + 2, 128);
830 							}
831 							if ( multiplayer != CLIENT )
832 							{
833 								// set overshoot for head, freeze incubus in place
834 								my->monsterAnimationLimbOvershoot = ANIMATE_OVERSHOOT_TO_SETPOINT;
835 								myStats->EFFECTS[EFF_PARALYZED] = true;
836 								if ( my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT )
837 								{
838 									myStats->EFFECTS_TIMERS[EFF_PARALYZED] = 250;
839 								}
840 								else
841 								{
842 									myStats->EFFECTS_TIMERS[EFF_PARALYZED] = 100;
843 								}
844 							}
845 						}
846 
847 						if ( weaponarm->skill[1] == 0 )
848 						{
849 							// wind up arm, change direction when setpoint reached.
850 							if ( limbAnimateToLimit(weaponarm, ANIMATE_PITCH, -0.2, 13 * PI / 8, false, 0.0) )
851 							{
852 								weaponarm->skill[1] = 1;
853 							}
854 						}
855 						else
856 						{
857 							// swing and flare out arm.
858 							limbAnimateToLimit(weaponarm, ANIMATE_PITCH, 0.1, 2 * PI / 16, false, 0.0);
859 							limbAnimateToLimit(weaponarm, ANIMATE_ROLL, -0.1, 31 * PI / 16, false, 0.0);
860 						}
861 
862 						if ( multiplayer != CLIENT )
863 						{
864 							// move the head back and forth.
865 							// keeps between PI and 0 (2PI) so we can lower the head at completion to 0 (2PI).
866 							if ( my->monsterAnimationLimbOvershoot >= ANIMATE_OVERSHOOT_TO_SETPOINT )
867 							{
868 								if ( my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT )
869 								{
870 									limbAnimateWithOvershoot(my, ANIMATE_PITCH, -0.05, 7 * PI / 4, -0.05, 15 * PI / 8, ANIMATE_DIR_POSITIVE);
871 								}
872 								else
873 								{
874 									limbAnimateWithOvershoot(my, ANIMATE_PITCH, -0.1, 7 * PI / 4, -0.1, 15 * PI / 8, ANIMATE_DIR_POSITIVE);
875 								}
876 							}
877 							else
878 							{
879 								// after 1 cycle is complete, reset the overshoot flag and repeat the animation.
880 								my->monsterAnimationLimbOvershoot = ANIMATE_OVERSHOOT_TO_SETPOINT;
881 							}
882 						}
883 
884 						// animation takes roughly 2 seconds.
885 						int duration = 10;
886 						if ( my->monsterAttack == MONSTER_POSE_INCUBUS_TAUNT )
887 						{
888 							duration = 50;
889 						}
890 						if ( my->monsterAttackTime >= ANIMATE_DURATION_WINDUP * duration / (monsterGlobalAnimationMultiplier / 10.0) )
891 						{
892 							weaponarm->skill[0] = rightbody->skill[0];
893 							weaponarm->pitch = rightbody->pitch;
894 							weaponarm->roll = -PI / 32;
895 							my->monsterArmbended = 0;
896 							my->monsterAttack = 0;
897 							Entity* leftarm = nullptr;
898 							node_t* leftarmNode = list_Node(&my->children, LIMB_HUMANOID_LEFTARM);
899 							if ( leftarmNode )
900 							{
901 								leftarm = (Entity*)leftarmNode->element;
902 								leftarm->roll = PI / 32;
903 							}
904 							else
905 							{
906 								return;
907 							}
908 							if ( multiplayer != CLIENT )
909 							{
910 								my->monsterAnimationLimbOvershoot = ANIMATE_OVERSHOOT_NONE;
911 							}
912 						}
913 						++my->monsterAttackTime; // manually increment timer
914 					}
915 					else
916 					{
917 						my->handleWeaponArmAttack(weaponarm);
918 						if ( my->monsterAttack != MONSTER_POSE_MELEE_WINDUP2 && my->monsterAttack != 2 )
919 						{
920 							// flare out the weapon arm to match neutral arm position.
921 							// breaks the horizontal chop attack animation so we skip it.
922 							weaponarm->roll = -PI / 32;
923 						}
924 					}
925 				}
926 			}
927 			else if ( bodypart == LIMB_HUMANOID_CLOAK )
928 			{
929 				entity->pitch = entity->fskill[0];
930 			}
931 
932 			my->humanoidAnimateWalk(entity, node, bodypart, INCUBUSWALKSPEED, dist, 0.4);
933 
934 			if ( bodypart == LIMB_HUMANOID_CLOAK )
935 			{
936 				entity->fskill[0] = entity->pitch;
937 				entity->roll = my->roll - fabs(entity->pitch) / 2;
938 				entity->pitch = 0;
939 			}
940 		}
941 		switch ( bodypart )
942 		{
943 			// torso
944 			case LIMB_HUMANOID_TORSO:
945 				my->setHumanoidLimbOffset(entity, INCUBUS, LIMB_HUMANOID_TORSO);
946 				break;
947 			// right leg
948 			case LIMB_HUMANOID_RIGHTLEG:
949 				if ( multiplayer != CLIENT )
950 				{
951 					if ( myStats->shoes == nullptr )
952 					{
953 						entity->sprite = 450;
954 					}
955 					else
956 					{
957 						my->setBootSprite(entity, SPRITE_BOOT_RIGHT_OFFSET);
958 					}
959 					if ( multiplayer == SERVER )
960 					{
961 						// update sprites for clients
962 						if ( entity->skill[10] != entity->sprite )
963 						{
964 							entity->skill[10] = entity->sprite;
965 							serverUpdateEntityBodypart(my, bodypart);
966 						}
967 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
968 						{
969 							serverUpdateEntityBodypart(my, bodypart);
970 						}
971 					}
972 				}
973 				my->setHumanoidLimbOffset(entity, INCUBUS, LIMB_HUMANOID_RIGHTLEG);
974 				break;
975 			// left leg
976 			case LIMB_HUMANOID_LEFTLEG:
977 				if ( multiplayer != CLIENT )
978 				{
979 					if ( myStats->shoes == nullptr )
980 					{
981 						entity->sprite = 449;
982 					}
983 					else
984 					{
985 						my->setBootSprite(entity, SPRITE_BOOT_LEFT_OFFSET);
986 					}
987 					if ( multiplayer == SERVER )
988 					{
989 						// update sprites for clients
990 						if ( entity->skill[10] != entity->sprite )
991 						{
992 							entity->skill[10] = entity->sprite;
993 							serverUpdateEntityBodypart(my, bodypart);
994 						}
995 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
996 						{
997 							serverUpdateEntityBodypart(my, bodypart);
998 						}
999 					}
1000 				}
1001 				my->setHumanoidLimbOffset(entity, INCUBUS, LIMB_HUMANOID_LEFTLEG);
1002 				break;
1003 			// right arm
1004 			case LIMB_HUMANOID_RIGHTARM:
1005 			{
1006 				node_t* weaponNode = list_Node(&my->children, LIMB_HUMANOID_WEAPON);
1007 				if ( weaponNode )
1008 				{
1009 					Entity* weapon = (Entity*)weaponNode->element;
1010 					if ( MONSTER_ARMBENDED || (weapon->flags[INVISIBLE] && my->monsterState != MONSTER_STATE_ATTACK) )
1011 					{
1012 						// if weapon invisible and I'm not attacking, relax arm.
1013 						entity->focalx = limbs[INCUBUS][4][0] - 0.25; // 0
1014 						entity->focaly = limbs[INCUBUS][4][1] - 0.25; // 0
1015 						entity->focalz = limbs[INCUBUS][4][2]; // 2
1016 						entity->sprite = 448;
1017 						if ( my->monsterAttack == 0 )
1018 						{
1019 							entity->roll = -PI / 32;
1020 						}
1021 					}
1022 					else
1023 					{
1024 						// else flex arm.
1025 						entity->focalx = limbs[INCUBUS][4][0];
1026 						entity->focaly = limbs[INCUBUS][4][1];
1027 						entity->focalz = limbs[INCUBUS][4][2];
1028 						entity->sprite = 595;
1029 					}
1030 				}
1031 				my->setHumanoidLimbOffset(entity, INCUBUS, LIMB_HUMANOID_RIGHTARM);
1032 				entity->yaw += MONSTER_WEAPONYAW;
1033 				break;
1034 			}
1035 			// left arm
1036 			case LIMB_HUMANOID_LEFTARM:
1037 			{
1038 				shieldarm = entity;
1039 				node_t* shieldNode = list_Node(&my->children, 8);
1040 				if ( shieldNode )
1041 				{
1042 					Entity* shield = (Entity*)shieldNode->element;
1043 					if ( shield->flags[INVISIBLE] && (my->monsterState != MONSTER_STATE_ATTACK) )
1044 					{
1045 						// if weapon invisible and I'm not attacking, relax arm.
1046 						entity->focalx = limbs[INCUBUS][5][0] - 0.25; // 0
1047 						entity->focaly = limbs[INCUBUS][5][1] + 0.25; // 0
1048 						entity->focalz = limbs[INCUBUS][5][2]; // 2
1049 						entity->sprite = 447;
1050 						if ( my->monsterAttack == 0 )
1051 						{
1052 							entity->roll = PI / 32;
1053 						}
1054 					}
1055 					else
1056 					{
1057 						// else flex arm.
1058 						entity->focalx = limbs[INCUBUS][5][0];
1059 						entity->focaly = limbs[INCUBUS][5][1];
1060 						entity->focalz = limbs[INCUBUS][5][2];
1061 						entity->sprite = 594;
1062 						if ( my->monsterSpecialState == INCUBUS_STEAL )
1063 						{
1064 							entity->yaw -= MONSTER_WEAPONYAW;
1065 						}
1066 					}
1067 				}
1068 				my->setHumanoidLimbOffset(entity, INCUBUS, LIMB_HUMANOID_LEFTARM);
1069 				if ( my->monsterDefend && my->monsterAttack == 0 )
1070 				{
1071 					MONSTER_SHIELDYAW = PI / 5;
1072 				}
1073 				else
1074 				{
1075 					MONSTER_SHIELDYAW = 0;
1076 				}
1077 				entity->yaw += MONSTER_SHIELDYAW;
1078 				break;
1079 			}
1080 			// weapon
1081 			case LIMB_HUMANOID_WEAPON:
1082 			{
1083 				if ( multiplayer != CLIENT )
1084 				{
1085 					if ( myStats->weapon == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1086 					{
1087 						entity->flags[INVISIBLE] = true;
1088 					}
1089 					else
1090 					{
1091 						entity->sprite = itemModel(myStats->weapon);
1092 						if ( itemCategory(myStats->weapon) == SPELLBOOK )
1093 						{
1094 							entity->flags[INVISIBLE] = true;
1095 						}
1096 						else
1097 						{
1098 							entity->flags[INVISIBLE] = false;
1099 						}
1100 					}
1101 					if ( multiplayer == SERVER )
1102 					{
1103 						// update sprites for clients
1104 						if ( entity->skill[10] != entity->sprite )
1105 						{
1106 							entity->skill[10] = entity->sprite;
1107 							serverUpdateEntityBodypart(my, bodypart);
1108 						}
1109 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1110 						{
1111 							entity->skill[11] = entity->flags[INVISIBLE];
1112 							serverUpdateEntityBodypart(my, bodypart);
1113 						}
1114 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1115 						{
1116 							serverUpdateEntityBodypart(my, bodypart);
1117 						}
1118 					}
1119 				}
1120 				else
1121 				{
1122 					if ( entity->sprite <= 0 )
1123 					{
1124 						entity->flags[INVISIBLE] = true;
1125 					}
1126 				}
1127 				if ( weaponarm != nullptr )
1128 				{
1129 					my->handleHumanoidWeaponLimb(entity, weaponarm);
1130 				}
1131 				break;
1132 			}
1133 			// shield
1134 			case LIMB_HUMANOID_SHIELD:
1135 			{
1136 				if ( multiplayer != CLIENT )
1137 				{
1138 					if ( myStats->shield == nullptr )
1139 					{
1140 						entity->flags[INVISIBLE] = true;
1141 						entity->sprite = 0;
1142 					}
1143 					else
1144 					{
1145 						entity->flags[INVISIBLE] = false;
1146 						entity->sprite = itemModel(myStats->shield);
1147 						if ( itemTypeIsQuiver(myStats->shield->type) )
1148 						{
1149 							entity->handleQuiverThirdPersonModel(*myStats);
1150 						}
1151 					}
1152 					if ( myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1153 					{
1154 						entity->flags[INVISIBLE] = true;
1155 					}
1156 					if ( multiplayer == SERVER )
1157 					{
1158 						// update sprites for clients
1159 						if ( entity->skill[10] != entity->sprite )
1160 						{
1161 							entity->skill[10] = entity->sprite;
1162 							serverUpdateEntityBodypart(my, bodypart);
1163 						}
1164 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1165 						{
1166 							entity->skill[11] = entity->flags[INVISIBLE];
1167 							serverUpdateEntityBodypart(my, bodypart);
1168 						}
1169 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1170 						{
1171 							serverUpdateEntityBodypart(my, bodypart);
1172 						}
1173 					}
1174 				}
1175 				else
1176 				{
1177 					if ( entity->sprite <= 0 )
1178 					{
1179 						entity->flags[INVISIBLE] = true;
1180 					}
1181 				}
1182 				my->handleHumanoidShieldLimb(entity, shieldarm);
1183 				break;
1184 				// cloak
1185 			case LIMB_HUMANOID_CLOAK:
1186 				if ( multiplayer != CLIENT )
1187 				{
1188 					if ( myStats->cloak == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1189 					{
1190 						entity->flags[INVISIBLE] = true;
1191 					}
1192 					else
1193 					{
1194 						entity->flags[INVISIBLE] = false;
1195 						entity->sprite = itemModel(myStats->cloak);
1196 					}
1197 					if ( multiplayer == SERVER )
1198 					{
1199 						// update sprites for clients
1200 						if ( entity->skill[10] != entity->sprite )
1201 						{
1202 							entity->skill[10] = entity->sprite;
1203 							serverUpdateEntityBodypart(my, bodypart);
1204 						}
1205 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1206 						{
1207 							entity->skill[11] = entity->flags[INVISIBLE];
1208 							serverUpdateEntityBodypart(my, bodypart);
1209 						}
1210 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1211 						{
1212 							serverUpdateEntityBodypart(my, bodypart);
1213 						}
1214 					}
1215 				}
1216 				else
1217 				{
1218 					if ( entity->sprite <= 0 )
1219 					{
1220 						entity->flags[INVISIBLE] = true;
1221 					}
1222 				}
1223 				entity->x -= cos(my->yaw);
1224 				entity->y -= sin(my->yaw);
1225 				entity->yaw += PI / 2;
1226 				break;
1227 				// helm
1228 			case LIMB_HUMANOID_HELMET:
1229 				helmet = entity;
1230 				entity->focalx = limbs[INCUBUS][9][0]; // 0
1231 				entity->focaly = limbs[INCUBUS][9][1]; // 0
1232 				entity->focalz = limbs[INCUBUS][9][2]; // -2
1233 				entity->pitch = my->pitch;
1234 				entity->roll = 0;
1235 				if ( multiplayer != CLIENT )
1236 				{
1237 					entity->sprite = itemModel(myStats->helmet);
1238 					if ( myStats->helmet == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1239 					{
1240 						entity->flags[INVISIBLE] = true;
1241 					}
1242 					else
1243 					{
1244 						entity->flags[INVISIBLE] = false;
1245 					}
1246 					if ( multiplayer == SERVER )
1247 					{
1248 						// update sprites for clients
1249 						if ( entity->skill[10] != entity->sprite )
1250 						{
1251 							entity->skill[10] = entity->sprite;
1252 							serverUpdateEntityBodypart(my, bodypart);
1253 						}
1254 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1255 						{
1256 							entity->skill[11] = entity->flags[INVISIBLE];
1257 							serverUpdateEntityBodypart(my, bodypart);
1258 						}
1259 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1260 						{
1261 							serverUpdateEntityBodypart(my, bodypart);
1262 						}
1263 					}
1264 				}
1265 				else
1266 				{
1267 					if ( entity->sprite <= 0 )
1268 					{
1269 						entity->flags[INVISIBLE] = true;
1270 					}
1271 				}
1272 				my->setHelmetLimbOffset(entity);
1273 				break;
1274 				// mask
1275 			case LIMB_HUMANOID_MASK:
1276 				entity->focalx = limbs[INCUBUS][10][0]; // 0
1277 				entity->focaly = limbs[INCUBUS][10][1]; // 0
1278 				entity->focalz = limbs[INCUBUS][10][2]; // .5
1279 				entity->pitch = my->pitch;
1280 				entity->roll = PI / 2;
1281 				if ( multiplayer != CLIENT )
1282 				{
1283 					bool hasSteelHelm = false;
1284 					if ( myStats->helmet )
1285 					{
1286 						if ( myStats->helmet->type == STEEL_HELM
1287 							|| myStats->helmet->type == CRYSTAL_HELM
1288 							|| myStats->helmet->type == ARTIFACT_HELM )
1289 						{
1290 							hasSteelHelm = true;
1291 						}
1292 					}
1293 					if ( myStats->mask == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring || hasSteelHelm ) //TODO: isInvisible()?
1294 					{
1295 						entity->flags[INVISIBLE] = true;
1296 					}
1297 					else
1298 					{
1299 						entity->flags[INVISIBLE] = false;
1300 					}
1301 					if ( myStats->mask != nullptr )
1302 					{
1303 						if ( myStats->mask->type == TOOL_GLASSES )
1304 						{
1305 							entity->sprite = 165; // GlassesWorn.vox
1306 						}
1307 						else
1308 						{
1309 							entity->sprite = itemModel(myStats->mask);
1310 						}
1311 					}
1312 					if ( multiplayer == SERVER )
1313 					{
1314 						// update sprites for clients
1315 						if ( entity->skill[10] != entity->sprite )
1316 						{
1317 							entity->skill[10] = entity->sprite;
1318 							serverUpdateEntityBodypart(my, bodypart);
1319 						}
1320 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1321 						{
1322 							entity->skill[11] = entity->flags[INVISIBLE];
1323 							serverUpdateEntityBodypart(my, bodypart);
1324 						}
1325 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1326 						{
1327 							serverUpdateEntityBodypart(my, bodypart);
1328 						}
1329 					}
1330 				}
1331 				else
1332 				{
1333 					if ( entity->sprite <= 0 )
1334 					{
1335 						entity->flags[INVISIBLE] = true;
1336 					}
1337 				}
1338 				if ( entity->sprite != 165 )
1339 				{
1340 					if ( entity->sprite == items[MASK_SHAMAN].index )
1341 					{
1342 						entity->roll = 0;
1343 						my->setHelmetLimbOffset(entity);
1344 						my->setHelmetLimbOffsetWithMask(helmet, entity);
1345 					}
1346 					else
1347 					{
1348 						entity->focalx = limbs[INCUBUS][10][0] + .35; // .35
1349 						entity->focaly = limbs[INCUBUS][10][1] - 2; // -2
1350 						entity->focalz = limbs[INCUBUS][10][2]; // .5
1351 					}
1352 				}
1353 				else
1354 				{
1355 					entity->focalx = limbs[INCUBUS][10][0] + .25; // .25
1356 					entity->focaly = limbs[INCUBUS][10][1] - 2.25; // -2.25
1357 					entity->focalz = limbs[INCUBUS][10][2]; // .5
1358 				}
1359 				break;
1360 			}
1361 		}
1362 	}
1363 	// rotate shield a bit
1364 	node_t* shieldNode = list_Node(&my->children, LIMB_HUMANOID_SHIELD);
1365 	if ( shieldNode )
1366 	{
1367 		Entity* shieldEntity = (Entity*)shieldNode->element;
1368 		if ( shieldEntity->sprite != items[TOOL_TORCH].index && shieldEntity->sprite != items[TOOL_LANTERN].index && shieldEntity->sprite != items[TOOL_CRYSTALSHARD].index )
1369 		{
1370 			shieldEntity->yaw -= PI / 6;
1371 		}
1372 	}
1373 	if ( MONSTER_ATTACK > 0 && MONSTER_ATTACK <= MONSTER_POSE_MAGIC_CAST3 )
1374 	{
1375 		MONSTER_ATTACKTIME++;
1376 	}
1377 	else if ( MONSTER_ATTACK == 0 )
1378 	{
1379 		MONSTER_ATTACKTIME = 0;
1380 	}
1381 	else
1382 	{
1383 		// do nothing, don't reset attacktime or increment it.
1384 	}
1385 }
1386 
incubusChooseWeapon(const Entity * target,double dist)1387 void Entity::incubusChooseWeapon(const Entity* target, double dist)
1388 {
1389 	if ( monsterSpecialState != 0 )
1390 	{
1391 		//Holding a weapon assigned from the special attack. Don't switch weapons.
1392 		if ( monsterSpecialState == INCUBUS_TELEPORT_STEAL && monsterSpecialTimer == 0 )
1393 		{
1394 			// handle steal weapon random teleportation
1395 			incubusTeleportRandom();
1396 			monsterSpecialState = 0;
1397 			serverUpdateEntitySkill(this, 33); // for clients to keep track of animation
1398 			attack(MONSTER_POSE_INCUBUS_TELEPORT, 0, nullptr);
1399 		}
1400 		else if ( monsterSpecialState == INCUBUS_TELEPORT && monsterSpecialTimer == 0 )
1401 		{
1402 			// handle idle teleporting to target
1403 			monsterSpecialState = 0;
1404 			serverUpdateEntitySkill(this, 33); // for clients to keep track of animation
1405 		}
1406 		return;
1407 	}
1408 
1409 	Stat *myStats = getStats();
1410 	if ( !myStats )
1411 	{
1412 		return;
1413 	}
1414 
1415 	if ( !strncmp(myStats->name, "inner demon", strlen("inner demon")) )
1416 	{
1417 		return;
1418 	}
1419 
1420 	int specialRoll = -1;
1421 	int bonusFromHP = 0;
1422 
1423 	if ( ticks % 10 == 0 && monsterSpecialState != INCUBUS_TELEPORT_STEAL )
1424 	{
1425 		// teleport to target, higher chance at greater distance or lower HP
1426 		specialRoll = rand() % 50;
1427 		if ( specialRoll < (1 + (dist > 80 ? 4 : 0) + (myStats->HP <= myStats->MAXHP * 0.8 ? 4 : 0)) )
1428 		{
1429 			monsterSpecialState = INCUBUS_TELEPORT;
1430 			incubusTeleportToTarget(target);
1431 			return;
1432 		}
1433 	}
1434 
1435 	if ( monsterSpecialTimer == 0 && (ticks % 10 == 0) && monsterAttack == 0 )
1436 	{
1437 		Stat* targetStats = target->getStats();
1438 		if ( !targetStats )
1439 		{
1440 			return;
1441 		}
1442 
1443 		bool tryCharm = true;
1444 		bool trySteal = true;
1445 		if ( targetStats->EFFECTS[EFF_PACIFY] )
1446 		{
1447 			tryCharm = false;
1448 		}
1449 		if ( !targetStats->weapon )
1450 		{
1451 			trySteal = false;
1452 		}
1453 
1454 		if ( trySteal || tryCharm )
1455 		{
1456 			if ( myStats->HP <= myStats->MAXHP * 0.8 )
1457 			{
1458 				bonusFromHP += 1; // +2.5% chance if on low health
1459 			}
1460 			if ( myStats->HP <= myStats->MAXHP * 0.4 )
1461 			{
1462 				bonusFromHP += 1; // +extra 2.5% chance if on lower health
1463 			}
1464 
1465 			int requiredRoll = (1 + bonusFromHP + (targetStats->EFFECTS[EFF_CONFUSED] ? 4 : 0)
1466 				+ (targetStats->EFFECTS[EFF_DRUNK] ? 2 : 0)
1467 				+ (targetStats->EFFECTS[EFF_PACIFY] ? 2 : 0)); // +2.5% base, + extra if target is inebriated
1468 
1469 			if ( trySteal && tryCharm )
1470 			{
1471 				if ( rand() % 8 == 0 )
1472 				{
1473 					trySteal = false; // try charm 12.5% of the time.
1474 				}
1475 				else
1476 				{
1477 					tryCharm = false;
1478 				}
1479 			}
1480 
1481 			if ( trySteal )
1482 			{
1483 				// try to steal weapon if target is holding.
1484 				// occurs less often against fellow monsters.
1485 				specialRoll = rand() % (40 + 40 * (target->behavior == &actMonster));
1486 			}
1487 			else if ( tryCharm )
1488 			{
1489 				specialRoll = rand() % 40;
1490 			}
1491 
1492 			if ( trySteal )
1493 			{
1494 				requiredRoll += (myStats->weapon == nullptr ? 3 : 0); // bonus if no weapon held
1495 			}
1496 
1497 			if ( specialRoll < requiredRoll )
1498 			{
1499 				node_t* node = nullptr;
1500 				if ( trySteal )
1501 				{
1502 					node = itemNodeInInventory(myStats, SPELLBOOK_STEAL_WEAPON, static_cast<Category>(-1));
1503 					if ( node != nullptr )
1504 					{
1505 						swapMonsterWeaponWithInventoryItem(this, myStats, node, true, true);
1506 						monsterSpecialState = INCUBUS_STEAL;
1507 						serverUpdateEntitySkill(this, 33); // for clients to keep track of animation
1508 						return;
1509 					}
1510 				}
1511 				else if ( tryCharm )
1512 				{
1513 					node = itemNodeInInventory(myStats, SPELLBOOK_CHARM_MONSTER, static_cast<Category>(-1));
1514 					if ( node != nullptr )
1515 					{
1516 						swapMonsterWeaponWithInventoryItem(this, myStats, node, true, true);
1517 						monsterSpecialState = INCUBUS_CHARM;
1518 						serverUpdateEntitySkill(this, 33); // for clients to keep track of animation
1519 						return;
1520 					}
1521 				}
1522 			}
1523 		}
1524 
1525 		// try new roll for alternate potion throw special.
1526 		// occurs less often against fellow monsters.
1527 		specialRoll = rand() % (30 + 30 * (target->behavior == &actMonster));
1528 		if ( specialRoll < (2 + bonusFromHP) ) // +5% base
1529 		{
1530 			node_t* node = nullptr;
1531 			node = itemNodeInInventory(myStats, static_cast<ItemType>(-1), POTION);
1532 			if ( node != nullptr )
1533 			{
1534 				swapMonsterWeaponWithInventoryItem(this, myStats, node, true, true);
1535 				monsterSpecialState = INCUBUS_CONFUSION;
1536 				return;
1537 			}
1538 		}
1539 	}
1540 
1541 	bool inMeleeRange = monsterInMeleeRange(target, dist);
1542 
1543 	if ( inMeleeRange )
1544 	{
1545 		//Switch to a melee weapon if not already wielding one. Unless monster special state is overriding the AI.
1546 		if ( !myStats->weapon || !isMeleeWeapon(*myStats->weapon) )
1547 		{
1548 			node_t* weaponNode = getMeleeWeaponItemNodeInInventory(myStats);
1549 			if ( !weaponNode )
1550 			{
1551 				return; //Resort to fists.
1552 			}
1553 
1554 			bool swapped = swapMonsterWeaponWithInventoryItem(this, myStats, weaponNode, false, false);
1555 			if ( !swapped )
1556 			{
1557 				//Don't return so that monsters will at least equip ranged weapons in melee range if they don't have anything else.
1558 			}
1559 			else
1560 			{
1561 				return;
1562 			}
1563 		}
1564 		else
1565 		{
1566 			return;
1567 		}
1568 	}
1569 
1570 	//Switch to a thrown weapon or a ranged weapon.
1571 	if ( !myStats->weapon || isMeleeWeapon(*myStats->weapon) )
1572 	{
1573 		node_t *weaponNode = getRangedWeaponItemNodeInInventory(myStats, true);
1574 		if ( !weaponNode )
1575 		{
1576 			return; //Nothing available
1577 		}
1578 		bool swapped = swapMonsterWeaponWithInventoryItem(this, myStats, weaponNode, false, false);
1579 		return;
1580 	}
1581 	return;
1582 }
1583 
incubusTeleportToTarget(const Entity * target)1584 void Entity::incubusTeleportToTarget(const Entity* target)
1585 {
1586 	Entity* spellTimer = createParticleTimer(this, 40, 593);
1587 	spellTimer->particleTimerEndAction = PARTICLE_EFFECT_INCUBUS_TELEPORT_TARGET; // teleport behavior of timer.
1588 	spellTimer->particleTimerEndSprite = 593; // sprite to use for end of timer function.
1589 	spellTimer->particleTimerCountdownAction = PARTICLE_TIMER_ACTION_SHOOT_PARTICLES;
1590 	spellTimer->particleTimerCountdownSprite = 593;
1591 	if ( target != nullptr )
1592 	{
1593 		spellTimer->particleTimerTarget = static_cast<Sint32>(target->getUID()); // get the target to teleport around.
1594 	}
1595 	spellTimer->particleTimerVariable1 = 3; // distance of teleport in tiles
1596 	if ( multiplayer == SERVER )
1597 	{
1598 		serverSpawnMiscParticles(this, PARTICLE_EFFECT_INCUBUS_TELEPORT_TARGET, 593);
1599 	}
1600 }
1601 
incubusTeleportRandom()1602 void Entity::incubusTeleportRandom()
1603 {
1604 	Entity* spellTimer = createParticleTimer(this, 80, 593);
1605 	spellTimer->particleTimerEndAction = PARTICLE_EFFECT_INCUBUS_TELEPORT_STEAL; // teleport behavior of timer.
1606 	spellTimer->particleTimerEndSprite = 593; // sprite to use for end of timer function.
1607 	spellTimer->particleTimerCountdownAction = PARTICLE_TIMER_ACTION_SHOOT_PARTICLES;
1608 	spellTimer->particleTimerCountdownSprite = 593;
1609 	spellTimer->particleTimerPreDelay = 40;
1610 	if ( multiplayer == SERVER )
1611 	{
1612 		serverSpawnMiscParticles(this, PARTICLE_EFFECT_INCUBUS_TELEPORT_STEAL, 593);
1613 	}
1614 }
1615