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