1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: monster_human.cpp
5 	Desc: implements all of the human 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 
initHuman(Entity * my,Stat * myStats)24 void initHuman(Entity* my, Stat* myStats)
25 {
26 	int c;
27 	node_t* node;
28 
29 	my->initMonster(113);
30 
31 	if ( multiplayer != CLIENT )
32 	{
33 		MONSTER_SPOTSND = -1;
34 		MONSTER_SPOTVAR = 1;
35 		MONSTER_IDLESND = -1;
36 		MONSTER_IDLEVAR = 1;
37 	}
38 	if ( multiplayer != CLIENT && !MONSTER_INIT )
39 	{
40 		if ( myStats != nullptr )
41 		{
42 			if ( !myStats->leader_uid )
43 			{
44 				myStats->leader_uid = 0;
45 			}
46 
47 			my->createPathBoundariesNPC();
48 
49 			Stat baseStats(HUMAN);
50 			bool isDefaultStats = isMonsterStatsDefault(*myStats);
51 
52 			// apply random stat increases if set in stat_shared.cpp or editor
53 			setRandomMonsterStats(myStats);
54 
55 			// generate 6 items max, less if there are any forced items from boss variants
56 			int customItemsToGenerate = ITEM_CUSTOM_SLOT_LIMIT;
57 
58 			// special human variant (named or Zap Brigadier), do not generate any other items
59 			int specialMonsterVariant = 0;
60 
61 			// boss variants
62 			// generate special loadout
63 			if ( my->monsterSpecialTimer == 0 )
64 			{
65 				if ( rand() % 25 == 0 && !myStats->MISC_FLAGS[STAT_FLAG_DISABLE_MINIBOSS]
66 					&& strcmp(myStats->name, "scriptNPC") && myStats->MISC_FLAGS[STAT_FLAG_NPC] == 0 )
67 				{
68 					specialMonsterVariant = 1;
69 					int specialMonsterType = rand() % 10;
70 					if ( !strncmp(map.name, "Mages Guild", 11) )
71 					{
72 						while ( specialMonsterType == 6 ) // 2 spiders that spawn cause aggro issues in Hamlet.
73 						{
74 							specialMonsterType = rand() % 10;
75 						}
76 					}
77 					switch ( rand() % 10 )
78 					{
79 						case 0:
80 							// red riding hood
81 							strcpy(myStats->name, "Red Riding Hood");
82 							myStats->appearance = 2;
83 							myStats->sex = FEMALE;
84 							myStats->LVL = 1;
85 							myStats->HP = 10;
86 							myStats->MAXHP = myStats->HP;
87 							myStats->MP = 10;
88 							myStats->MAXMP = myStats->MP;
89 							myStats->STR = 0;
90 							myStats->DEX = 0;
91 							myStats->CON = 0;
92 							myStats->INT = -2;
93 							myStats->PER = -2;
94 							myStats->CHR = 4;
95 							myStats->helmet = newItem(HAT_HOOD_RED, EXCELLENT, 1, 1, rand(), false, nullptr);
96 							myStats->cloak = newItem(CLOAK, EXCELLENT, 1, 1, 2, false, nullptr);
97 							myStats->weapon = newItem(QUARTERSTAFF, EXCELLENT, 1, 1, rand(), false, nullptr);
98 							break;
99 						case 1:
100 						{
101 							// king arthur
102 							strcpy(myStats->name, "King Arthur");
103 							myStats->appearance = 0;
104 							myStats->sex = MALE;
105 							myStats->LVL = 10;
106 							myStats->HP = 100;
107 							myStats->MAXHP = myStats->HP;
108 							myStats->MP = 100;
109 							myStats->MAXMP = myStats->MP;
110 							myStats->STR = 10;
111 							myStats->DEX = 5;
112 							myStats->CON = 5;
113 							myStats->INT = 5;
114 							myStats->PER = 5;
115 							myStats->CHR = 5;
116 							myStats->breastplate = newItem(STEEL_BREASTPIECE, EXCELLENT, 1, 1, 1, true, nullptr);
117 							myStats->gloves = newItem(GAUNTLETS, EXCELLENT, 1, 1, 1, true, nullptr);
118 							myStats->shoes = newItem(STEEL_BOOTS, EXCELLENT, 1, 1, 1, true, nullptr);
119 							myStats->cloak = newItem(CLOAK, EXCELLENT, 2, 1, 2, true, nullptr);
120 							int status = DECREPIT + (currentlevel > 5) + (currentlevel > 15) + (currentlevel > 20);
121 							myStats->weapon = newItem(ARTIFACT_SWORD, static_cast<Status>(status), 1, 1, rand(), true, nullptr);
122 							myStats->shield = newItem(STEEL_SHIELD_RESISTANCE, EXCELLENT, 1, 1, 1, true, nullptr);
123 							break;
124 						}
125 						case 2:
126 							// merlin
127 							strcpy(myStats->name, "Merlin");
128 							myStats->appearance = 5;
129 							myStats->sex = MALE;
130 							myStats->LVL = 10;
131 							myStats->HP = 60;
132 							myStats->MAXHP = myStats->HP;
133 							myStats->MP = 200;
134 							myStats->MAXMP = myStats->MP;
135 							myStats->STR = 2;
136 							myStats->DEX = 2;
137 							myStats->CON = 3;
138 							myStats->INT = 11;
139 							myStats->PER = 10;
140 							myStats->CHR = 2;
141 							myStats->helmet = newItem(HAT_WIZARD, EXCELLENT, 2, 1, 2, false, nullptr);
142 							myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 2, 1, 2, false, nullptr);
143 							myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 5, 1, 3, false, nullptr);
144 							myStats->weapon = newItem(MAGICSTAFF_LIGHTNING, EXCELLENT, 2, 1, 2, false, nullptr);
145 							myStats->amulet = newItem(AMULET_MAGICREFLECTION, EXCELLENT, 2, 1, 2, false, nullptr);
146 							break;
147 						case 3:
148 							// robin hood
149 							strcpy(myStats->name, "Robin Hood");
150 							myStats->appearance = 1;
151 							myStats->sex = MALE;
152 							myStats->LVL = 5;
153 							myStats->HP = 70;
154 							myStats->MAXHP = myStats->HP;
155 							myStats->MP = 50;
156 							myStats->MAXMP = myStats->MP;
157 							myStats->STR = 3;
158 							myStats->DEX = 5;
159 							myStats->CON = 3;
160 							myStats->INT = 2;
161 							myStats->PER = 3;
162 							myStats->CHR = 5;
163 							myStats->gloves = newItem(GLOVES, EXCELLENT, 1, 1, 3, true, nullptr);
164 							myStats->shoes = newItem(LEATHER_BOOTS, SERVICABLE, 1, 1, 3, true, nullptr);
165 							myStats->cloak = newItem(CLOAK, EXCELLENT, 1, 1, 0, true, nullptr);
166 							myStats->weapon = newItem(SHORTBOW, EXCELLENT, 1, 1, 3, true, nullptr);
167 							break;
168 						case 4:
169 							// conan
170 							strcpy(myStats->name, "Conan the Barbarian");
171 							myStats->appearance = 7;
172 							myStats->sex = MALE;
173 							myStats->LVL = 10;
174 							myStats->HP = 100;
175 							myStats->MAXHP = myStats->HP;
176 							myStats->MP = 20;
177 							myStats->MAXMP = myStats->MP;
178 							myStats->STR = 10;
179 							myStats->DEX = 5;
180 							myStats->CON = 10;
181 							myStats->INT = 3;
182 							myStats->PER = 3;
183 							myStats->CHR = 20;
184 							myStats->helmet = newItem(LEATHER_HELM, EXCELLENT, 2, 1, rand(), false, nullptr);
185 							myStats->shield = newItem(WOODEN_SHIELD, EXCELLENT, 2, 1, rand(), false, nullptr);
186 							myStats->weapon = newItem(STEEL_AXE, EXCELLENT, 2, 1, rand(), false, nullptr);
187 							break;
188 						case 5:
189 							// othello
190 							strcpy(myStats->name, "Othello");
191 							myStats->appearance = 14;
192 							myStats->sex = MALE;
193 							myStats->LVL = 10;
194 							myStats->HP = 50;
195 							myStats->MAXHP = myStats->HP;
196 							myStats->MP = 20;
197 							myStats->MAXMP = myStats->MP;
198 							myStats->STR = 3;
199 							myStats->DEX = 3;
200 							myStats->CON = 3;
201 							myStats->INT = 3;
202 							myStats->PER = 0;
203 							myStats->CHR = 30;
204 							myStats->gloves = newItem(BRACERS, EXCELLENT, -1, 1, rand(), false, nullptr);
205 							myStats->breastplate = newItem(IRON_BREASTPIECE, EXCELLENT, 1, 1, rand(), false, nullptr);
206 							myStats->weapon = newItem(STEEL_SWORD, EXCELLENT, 2, 1, rand(), false, nullptr);
207 							myStats->cloak = newItem(CLOAK, EXCELLENT, 0, 1, 2, false, nullptr);
208 							break;
209 						case 6:
210 						{
211 							// anansi
212 							strcpy(myStats->name, "Anansi");
213 							myStats->appearance = 15;
214 							myStats->sex = MALE;
215 							myStats->LVL = 20;
216 							myStats->HP = 100;
217 							myStats->MAXHP = myStats->HP;
218 							myStats->MP = 100;
219 							myStats->MAXMP = myStats->MP;
220 							myStats->STR = 10;
221 							myStats->DEX = 8;
222 							myStats->CON = 5;
223 							myStats->INT = 20;
224 							myStats->PER = 20;
225 							myStats->CHR = 10;
226 							myStats->helmet = newItem(HAT_JESTER, EXCELLENT, 5, 1, rand(), false, nullptr);
227 							int status = DECREPIT + (currentlevel > 5) + (currentlevel > 15) + (currentlevel > 20);
228 							myStats->weapon = newItem(ARTIFACT_MACE, static_cast<Status>(status), 1, 1, rand(), false, nullptr);
229 							int c;
230 							for ( c = 0; c < 2; c++ )
231 							{
232 								Entity* entity = summonMonster(SPIDER, my->x, my->y);
233 								if ( entity )
234 								{
235 									entity->parent = my->getUID();
236 									entity->flags[USERFLAG2] = true;
237 								}
238 							}
239 							break;
240 						}
241 						case 7:
242 							// oya
243 							strcpy(myStats->name, "Oya");
244 							myStats->appearance = 13;
245 							myStats->sex = FEMALE;
246 							myStats->LVL = 20;
247 							myStats->HP = 100;
248 							myStats->MAXHP = myStats->HP;
249 							myStats->MP = 100;
250 							myStats->MAXMP = myStats->MP;
251 							myStats->STR = 4;
252 							myStats->DEX = 10;
253 							myStats->CON = 2;
254 							myStats->INT = 20;
255 							myStats->PER = 10;
256 							myStats->CHR = 10;
257 							myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 3, 1, 1, false, nullptr);
258 							myStats->helmet = newItem(HAT_HOOD, EXCELLENT, 3, 1, 1, false, nullptr);
259 							break;
260 						case 8:
261 						{
262 							// vishpala
263 							strcpy(myStats->name, "Vishpala");
264 							myStats->appearance = 17;
265 							myStats->sex = FEMALE;
266 							myStats->LVL = 10;
267 							myStats->HP = 70;
268 							myStats->MAXHP = myStats->HP;
269 							myStats->MP = 20;
270 							myStats->MAXMP = myStats->MP;
271 							myStats->STR = 10;
272 							myStats->DEX = 5;
273 							myStats->CON = 5;
274 							myStats->INT = 5;
275 							myStats->PER = 5;
276 							myStats->CHR = 10;
277 							myStats->cloak = newItem(CLOAK, EXCELLENT, 0, 1, 2, false, nullptr);
278 							myStats->breastplate = newItem(IRON_BREASTPIECE, EXCELLENT, 0, 1, rand(), false, nullptr);
279 							myStats->shoes = newItem(IRON_BOOTS, EXCELLENT, 0, 1, rand(), false, nullptr);
280 							int status = DECREPIT + (currentlevel > 5) + (currentlevel > 15) + (currentlevel > 20);
281 							myStats->weapon = newItem(ARTIFACT_SPEAR, static_cast<Status>(status), 1, 1, rand(), false, nullptr);
282 							myStats->shield = newItem(BRONZE_SHIELD, EXCELLENT, 1, 1, rand(), false, nullptr);
283 							break;
284 						}
285 						case 9:
286 							// kali
287 							strcpy(myStats->name, "Kali");
288 							myStats->appearance = 15;
289 							myStats->sex = FEMALE;
290 							myStats->LVL = 20;
291 							myStats->HP = 200;
292 							myStats->MAXHP = myStats->HP;
293 							myStats->MP = 200;
294 							myStats->MAXMP = myStats->MP;
295 							myStats->STR = 5;
296 							myStats->DEX = 5;
297 							myStats->CON = 5;
298 							myStats->INT = 20;
299 							myStats->PER = 20;
300 							myStats->CHR = 20;
301 							myStats->cloak = newItem(CLOAK_MAGICREFLECTION, EXCELLENT, 1, 1, 2, false, nullptr);
302 							myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 1, 1, rand(), false, nullptr);
303 							myStats->weapon = newItem(SPELLBOOK_FIREBALL, EXCELLENT, 1, 1, rand(), false, nullptr);
304 							break;
305 						default:
306 							break;
307 					}
308 				}
309 			}
310 			else
311 			{
312 				specialMonsterVariant = 1;
313 				// zap brigadier
314 				strcpy(myStats->name, "ZAP Brigadier");
315 				myStats->appearance = 1;
316 				myStats->sex = static_cast<sex_t>(rand() % 2);
317 				myStats->LVL = 10;
318 				myStats->HP = 100;
319 				myStats->MAXHP = myStats->HP;
320 				myStats->MP = 200;
321 				myStats->MAXMP = myStats->MP;
322 				myStats->STR = 3;
323 				myStats->DEX = 3;
324 				myStats->CON = 3;
325 				myStats->INT = 3;
326 				myStats->PER = 10;
327 				myStats->CHR = 10;
328 				myStats->helmet = newItem(HAT_HOOD, EXCELLENT, 2, 1, 3, false, nullptr);
329 				myStats->gloves = newItem(GLOVES, EXCELLENT, 0, 1, 2, false, nullptr);
330 				myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 0, 1, 2, false, nullptr);
331 				myStats->breastplate = newItem(LEATHER_BREASTPIECE, EXCELLENT, 0, 1, 2, false, nullptr);
332 				myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 2, 1, 3, false, nullptr);
333 				myStats->weapon = newItem(MAGICSTAFF_LIGHTNING, EXCELLENT, 1, 1, 2, false, nullptr);
334 				myStats->amulet = newItem(AMULET_MAGICREFLECTION, EXCELLENT, 1, 1, 2, false, nullptr);
335 			}
336 
337 			// random effects
338 			if ( rand() % 10 == 0 && strcmp(myStats->name, "scriptNPC") && myStats->MISC_FLAGS[STAT_FLAG_NPC] == 0 )
339 			{
340 				myStats->EFFECTS[EFF_ASLEEP] = true;
341 				myStats->EFFECTS_TIMERS[EFF_ASLEEP] = 1800 + rand() % 1800;
342 			}
343 
344 			// generates equipment and weapons if available from editor
345 			createMonsterEquipment(myStats);
346 
347 			// create any custom inventory items from editor if available
348 			createCustomInventory(myStats, customItemsToGenerate);
349 
350 			// count if any custom inventory items from editor
351 			int customItems = countCustomItems(myStats);
352 			//max limit of 6 custom items per entity.
353 
354 			// count any inventory items set to default in edtior
355 			int defaultItems = countDefaultItems(myStats);
356 
357 			if ( specialMonsterVariant == 0 && isDefaultStats )
358 			{
359 				if ( my->monsterStoreType == 0 && currentlevel > 5 )
360 				{
361 					my->monsterStoreType = (currentlevel / 5) * 3 + (rand() % 4); // scale humans with depth.  3 LVL each 5 floors, + 0-3.
362 				}
363 				myStats->EXP += 100 * my->monsterStoreType; // apply experience to level up the humans with floor depth.
364 			}
365 
366 			// generate the default inventory items for the monster, provided the editor sprite allowed enough default slots
367 			switch ( defaultItems )
368 			{
369 				case 6:
370 				case 5:
371 				case 4:
372 				case 3:
373 				case 2:
374 				case 1:
375 					break;
376 				default:
377 					break;
378 			}
379 
380 			if ( specialMonsterVariant == 0 )
381 			{
382 				// generate random equipment if not a named special human
383 
384 
385 				//give weapon
386 				if ( myStats->weapon == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_WEAPON] == 1 )
387 				{
388 					switch ( rand() % 10 )
389 					{
390 						case 0:
391 						case 1:
392 							myStats->weapon = newItem(SHORTBOW, WORN, 0, 1, rand(), false, nullptr);
393 							break;
394 						case 2:
395 						case 3:
396 							myStats->weapon = newItem(BRONZE_AXE, WORN, 0, 1, rand(), false, nullptr);
397 							break;
398 						case 4:
399 						case 5:
400 							myStats->weapon = newItem(BRONZE_SWORD, WORN, 0, 1, rand(), false, nullptr);
401 							break;
402 						case 6:
403 							myStats->weapon = newItem(IRON_SPEAR, WORN, 0, 1, rand(), false, nullptr);
404 							break;
405 						case 7:
406 							myStats->weapon = newItem(IRON_AXE, WORN, 0, 1, rand(), false, nullptr);
407 							break;
408 						case 8:
409 							myStats->weapon = newItem(IRON_SWORD, WORN, 0, 1, rand(), false, nullptr);
410 							break;
411 						case 9:
412 							myStats->weapon = newItem(CROSSBOW, WORN, 0, 1, rand(), false, nullptr);
413 							break;
414 					}
415 				}
416 
417 				//give shield
418 				if ( myStats->shield == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_SHIELD] == 1 )
419 				{
420 					if ( myStats->weapon && isRangedWeapon(*myStats->weapon) )
421 					{
422 						my->monsterGenerateQuiverItem(myStats);
423 					}
424 					else
425 					{
426 						switch ( rand() % 10 )
427 						{
428 							case 0:
429 							case 1:
430 							case 2:
431 								myStats->shield = newItem(TOOL_TORCH, SERVICABLE, 0, 1, rand(), false, nullptr);
432 								break;
433 							case 3:
434 							case 4:
435 								break;
436 							case 5:
437 							case 6:
438 								myStats->shield = newItem(WOODEN_SHIELD, WORN, 0, 1, rand(), false, nullptr);
439 								break;
440 							case 7:
441 							case 8:
442 								myStats->shield = newItem(BRONZE_SHIELD, WORN, 0, 1, rand(), false, nullptr);
443 								break;
444 							case 9:
445 								myStats->shield = newItem(IRON_SHIELD, WORN, 0, 1, rand(), false, nullptr);
446 								break;
447 						}
448 					}
449 				}
450 
451 				// give helmet
452 				if ( myStats->helmet == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_HELM] == 1 )
453 				{
454 					switch ( rand() % 10 )
455 					{
456 						case 0:
457 						case 1:
458 						case 2:
459 							break;
460 						case 3:
461 							myStats->helmet = newItem(HAT_HOOD, WORN, 0, 1, rand() % 4, false, nullptr);
462 							break;
463 						case 4:
464 							myStats->helmet = newItem(HAT_PHRYGIAN, WORN, 0, 1, rand(), false, nullptr);
465 							break;
466 						case 5:
467 							myStats->helmet = newItem(HAT_WIZARD, WORN, 0, 1, rand(), false, nullptr);
468 							break;
469 						case 6:
470 						case 7:
471 							myStats->helmet = newItem(LEATHER_HELM, WORN, 0, 1, rand(), false, nullptr);
472 							break;
473 						case 8:
474 						case 9:
475 							myStats->helmet = newItem(IRON_HELM, WORN, 0, 1, rand(), false, nullptr);
476 							break;
477 					}
478 				}
479 
480 				// give cloak
481 				if ( myStats->cloak == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_CLOAK] == 1 )
482 				{
483 					switch ( rand() % 10 )
484 					{
485 						case 0:
486 						case 1:
487 						case 2:
488 						case 3:
489 						case 4:
490 						case 5:
491 							break;
492 						case 6:
493 						case 7:
494 						case 8:
495 							myStats->cloak = newItem(CLOAK, WORN, 0, 1, rand(), false, nullptr);
496 							break;
497 						case 9:
498 							myStats->cloak = newItem(CLOAK_MAGICREFLECTION, WORN, 0, 1, rand(), false, nullptr);
499 							break;
500 					}
501 				}
502 
503 				// give armor
504 				if ( myStats->breastplate == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_ARMOR] == 1 )
505 				{
506 					switch ( rand() % 10 )
507 					{
508 						case 0:
509 						case 1:
510 						case 2:
511 						case 3:
512 						case 4:
513 							break;
514 						case 5:
515 						case 6:
516 						case 7:
517 							myStats->breastplate = newItem(LEATHER_BREASTPIECE, WORN, 0, 1, rand(), false, nullptr);
518 							break;
519 						case 8:
520 						case 9:
521 							myStats->breastplate = newItem(IRON_BREASTPIECE, WORN, 0, 1, rand(), false, nullptr);
522 							break;
523 					}
524 				}
525 
526 				// give gloves
527 				if ( myStats->gloves == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_GLOVES] == 1 )
528 				{
529 					switch ( rand() % 10 )
530 					{
531 						case 0:
532 						case 1:
533 						case 2:
534 						case 3:
535 						case 4:
536 							break;
537 						case 5:
538 						case 6:
539 						case 7:
540 							myStats->gloves = newItem(GLOVES, WORN, 0, 1, rand(), false, nullptr);
541 							break;
542 						case 8:
543 						case 9:
544 							myStats->gloves = newItem(GAUNTLETS, WORN, 0, 1, rand(), false, nullptr);
545 							break;
546 					}
547 				}
548 
549 				// give boots
550 				if ( myStats->shoes == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_BOOTS] == 1 )
551 				{
552 					switch ( rand() % 10 )
553 					{
554 						case 0:
555 						case 1:
556 						case 2:
557 						case 3:
558 						case 4:
559 							break;
560 						case 5:
561 						case 6:
562 						case 7:
563 							myStats->shoes = newItem(LEATHER_BOOTS, WORN, 0, 1, rand(), false, nullptr);
564 							break;
565 						case 8:
566 						case 9:
567 							myStats->shoes = newItem(IRON_BOOTS, WORN, 0, 1, rand(), false, nullptr);
568 							break;
569 					}
570 				}
571 			}
572 		}
573 	}
574 
575 	// torso
576 	Entity* entity = newEntity(106, 0, map.entities, nullptr); //Limb entity.
577 	entity->sizex = 4;
578 	entity->sizey = 4;
579 	entity->skill[2] = my->getUID();
580 	entity->flags[PASSABLE] = true;
581 	entity->flags[NOUPDATE] = true;
582 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
583 	entity->focalx = limbs[HUMAN][1][0]; // 0
584 	entity->focaly = limbs[HUMAN][1][1]; // 0
585 	entity->focalz = limbs[HUMAN][1][2]; // 0
586 	entity->behavior = &actHumanLimb;
587 	entity->parent = my->getUID();
588 	node = list_AddNodeLast(&my->children);
589 	node->element = entity;
590 	node->deconstructor = &emptyDeconstructor;
591 	node->size = sizeof(Entity*);
592 	my->bodyparts.push_back(entity);
593 
594 	// right leg
595 	entity = newEntity(107, 0, map.entities, nullptr); //Limb entity.
596 	entity->sizex = 4;
597 	entity->sizey = 4;
598 	entity->skill[2] = my->getUID();
599 	entity->flags[PASSABLE] = true;
600 	entity->flags[NOUPDATE] = true;
601 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
602 	entity->focalx = limbs[HUMAN][2][0]; // 0
603 	entity->focaly = limbs[HUMAN][2][1]; // 0
604 	entity->focalz = limbs[HUMAN][2][2]; // 2
605 	entity->behavior = &actHumanLimb;
606 	entity->parent = my->getUID();
607 	node = list_AddNodeLast(&my->children);
608 	node->element = entity;
609 	node->deconstructor = &emptyDeconstructor;
610 	node->size = sizeof(Entity*);
611 	my->bodyparts.push_back(entity);
612 
613 	// left leg
614 	entity = newEntity(108, 0, map.entities, nullptr); //Limb entity.
615 	entity->sizex = 4;
616 	entity->sizey = 4;
617 	entity->skill[2] = my->getUID();
618 	entity->flags[PASSABLE] = true;
619 	entity->flags[NOUPDATE] = true;
620 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
621 	entity->focalx = limbs[HUMAN][3][0]; // 0
622 	entity->focaly = limbs[HUMAN][3][1]; // 0
623 	entity->focalz = limbs[HUMAN][3][2]; // 2
624 	entity->behavior = &actHumanLimb;
625 	entity->parent = my->getUID();
626 	node = list_AddNodeLast(&my->children);
627 	node->element = entity;
628 	node->deconstructor = &emptyDeconstructor;
629 	node->size = sizeof(Entity*);
630 	my->bodyparts.push_back(entity);
631 
632 	// right arm
633 	entity = newEntity(109, 0, map.entities, nullptr); //Limb entity.
634 	entity->sizex = 4;
635 	entity->sizey = 4;
636 	entity->skill[2] = my->getUID();
637 	entity->flags[PASSABLE] = true;
638 	entity->flags[NOUPDATE] = true;
639 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
640 	entity->focalx = limbs[HUMAN][4][0]; // 0
641 	entity->focaly = limbs[HUMAN][4][1]; // 0
642 	entity->focalz = limbs[HUMAN][4][2]; // 1.5
643 	entity->behavior = &actHumanLimb;
644 	entity->parent = my->getUID();
645 	node = list_AddNodeLast(&my->children);
646 	node->element = entity;
647 	node->deconstructor = &emptyDeconstructor;
648 	node->size = sizeof(Entity*);
649 	my->bodyparts.push_back(entity);
650 
651 	// left arm
652 	entity = newEntity(110, 0, map.entities, nullptr); //Limb entity.
653 	entity->sizex = 4;
654 	entity->sizey = 4;
655 	entity->skill[2] = my->getUID();
656 	entity->flags[PASSABLE] = true;
657 	entity->flags[NOUPDATE] = true;
658 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
659 	entity->focalx = limbs[HUMAN][5][0]; // 0
660 	entity->focaly = limbs[HUMAN][5][1]; // 0
661 	entity->focalz = limbs[HUMAN][5][2]; // 1.5
662 	entity->behavior = &actHumanLimb;
663 	entity->parent = my->getUID();
664 	node = list_AddNodeLast(&my->children);
665 	node->element = entity;
666 	node->deconstructor = &emptyDeconstructor;
667 	node->size = sizeof(Entity*);
668 	my->bodyparts.push_back(entity);
669 
670 	// world weapon
671 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
672 	entity->sizex = 4;
673 	entity->sizey = 4;
674 	entity->skill[2] = my->getUID();
675 	entity->flags[PASSABLE] = true;
676 	entity->flags[NOUPDATE] = true;
677 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
678 	entity->focalx = limbs[HUMAN][6][0]; // 1.5
679 	entity->focaly = limbs[HUMAN][6][1]; // 0
680 	entity->focalz = limbs[HUMAN][6][2]; // -.5
681 	entity->behavior = &actHumanLimb;
682 	entity->parent = my->getUID();
683 	entity->pitch = .25;
684 	node = list_AddNodeLast(&my->children);
685 	node->element = entity;
686 	node->deconstructor = &emptyDeconstructor;
687 	node->size = sizeof(Entity*);
688 	my->bodyparts.push_back(entity);
689 
690 	// shield
691 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
692 	entity->sizex = 4;
693 	entity->sizey = 4;
694 	entity->skill[2] = my->getUID();
695 	entity->flags[PASSABLE] = true;
696 	entity->flags[NOUPDATE] = true;
697 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
698 	entity->focalx = limbs[HUMAN][7][0]; // 2
699 	entity->focaly = limbs[HUMAN][7][1]; // 0
700 	entity->focalz = limbs[HUMAN][7][2]; // 0
701 	entity->behavior = &actHumanLimb;
702 	entity->parent = my->getUID();
703 	node = list_AddNodeLast(&my->children);
704 	node->element = entity;
705 	node->deconstructor = &emptyDeconstructor;
706 	node->size = sizeof(Entity*);
707 	my->bodyparts.push_back(entity);
708 
709 	// cloak
710 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
711 	entity->sizex = 4;
712 	entity->sizey = 4;
713 	entity->skill[2] = my->getUID();
714 	entity->scalex = 1.01;
715 	entity->scaley = 1.01;
716 	entity->scalez = 1.01;
717 	entity->flags[PASSABLE] = true;
718 	entity->flags[NOUPDATE] = true;
719 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
720 	entity->focalx = limbs[HUMAN][8][0]; // 0
721 	entity->focaly = limbs[HUMAN][8][1]; // 0
722 	entity->focalz = limbs[HUMAN][8][2]; // 4
723 	entity->behavior = &actHumanLimb;
724 	entity->parent = my->getUID();
725 	node = list_AddNodeLast(&my->children);
726 	node->element = entity;
727 	node->deconstructor = &emptyDeconstructor;
728 	node->size = sizeof(Entity*);
729 	my->bodyparts.push_back(entity);
730 
731 	// helmet
732 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
733 	entity->sizex = 4;
734 	entity->sizey = 4;
735 	entity->skill[2] = my->getUID();
736 	entity->scalex = 1.01;
737 	entity->scaley = 1.01;
738 	entity->scalez = 1.01;
739 	entity->flags[PASSABLE] = true;
740 	entity->flags[NOUPDATE] = true;
741 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
742 	entity->focalx = limbs[HUMAN][9][0]; // 0
743 	entity->focaly = limbs[HUMAN][9][1]; // 0
744 	entity->focalz = limbs[HUMAN][9][2]; // -1.75
745 	entity->behavior = &actHumanLimb;
746 	entity->parent = my->getUID();
747 	node = list_AddNodeLast(&my->children);
748 	node->element = entity;
749 	node->deconstructor = &emptyDeconstructor;
750 	node->size = sizeof(Entity*);
751 	my->bodyparts.push_back(entity);
752 
753 	// mask
754 	entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity.
755 	entity->sizex = 4;
756 	entity->sizey = 4;
757 	entity->skill[2] = my->getUID();
758 	entity->scalex = .99;
759 	entity->scaley = .99;
760 	entity->scalez = .99;
761 	entity->flags[PASSABLE] = true;
762 	entity->flags[NOUPDATE] = true;
763 	//entity->flags[USERFLAG2] = my->flags[USERFLAG2];
764 	entity->focalx = limbs[HUMAN][10][0]; // 0
765 	entity->focaly = limbs[HUMAN][10][1]; // 0
766 	entity->focalz = limbs[HUMAN][10][2]; // .5
767 	entity->behavior = &actHumanLimb;
768 	entity->parent = my->getUID();
769 	node = list_AddNodeLast(&my->children);
770 	node->element = entity;
771 	node->deconstructor = &emptyDeconstructor;
772 	node->size = sizeof(Entity*);
773 	my->bodyparts.push_back(entity);
774 
775 	if ( multiplayer == CLIENT )
776 	{
777 		my->sprite = 113; // human head model
778 		return;
779 	}
780 
781 	// set head model
782 	if ( myStats->appearance < 5 )
783 	{
784 		my->sprite = 113 + 12 * myStats->sex + myStats->appearance;
785 	}
786 	else if ( myStats->appearance == 5 )
787 	{
788 		my->sprite = 332 + myStats->sex;
789 	}
790 	else if ( myStats->appearance >= 6 && myStats->appearance < 12 )
791 	{
792 		my->sprite = 341 + myStats->sex * 13 + myStats->appearance - 6;
793 	}
794 	else if ( myStats->appearance >= 12 )
795 	{
796 		my->sprite = 367 + myStats->sex * 13 + myStats->appearance - 12;
797 	}
798 	else
799 	{
800 		my->sprite = 113; // default
801 	}
802 }
803 
actHumanLimb(Entity * my)804 void actHumanLimb(Entity* my)
805 {
806 	my->actMonsterLimb(true);
807 }
808 
humanDie(Entity * my)809 void humanDie(Entity* my)
810 {
811 	int c;
812 	for ( c = 0; c < 5; c++ )
813 	{
814 		Entity* gib = spawnGib(my);
815 		serverSpawnGibForClient(gib);
816 	}
817 
818 	my->spawnBlood();
819 
820 	playSoundEntity(my, 28, 128);
821 
822 	my->removeMonsterDeathNodes();
823 
824 	list_RemoveNode(my->mynode);
825 	return;
826 }
827 
828 #define HUMANWALKSPEED .12
829 
humanMoveBodyparts(Entity * my,Stat * myStats,double dist)830 void humanMoveBodyparts(Entity* my, Stat* myStats, double dist)
831 {
832 	node_t* node;
833 	Entity* entity = nullptr, *entity2 = nullptr;
834 	Entity* rightbody = nullptr;
835 	Entity* weaponarm = nullptr;
836 	int bodypart;
837 	bool wearingring = false;
838 
839 	// set invisibility //TODO: isInvisible()?
840 	if ( multiplayer != CLIENT )
841 	{
842 		if ( myStats->ring != nullptr )
843 			if ( myStats->ring->type == RING_INVISIBILITY )
844 			{
845 				wearingring = true;
846 			}
847 		if ( myStats->cloak != nullptr )
848 			if ( myStats->cloak->type == CLOAK_INVISIBILITY )
849 			{
850 				wearingring = true;
851 			}
852 		if ( myStats->EFFECTS[EFF_INVISIBLE] == true || wearingring == true )
853 		{
854 			my->flags[INVISIBLE] = true;
855 			my->flags[BLOCKSIGHT] = false;
856 			bodypart = 0;
857 			for (node = my->children.first; node != nullptr; node = node->next)
858 			{
859 				if ( bodypart < 2 )
860 				{
861 					bodypart++;
862 					continue;
863 				}
864 				if ( bodypart >= 7 )
865 				{
866 					break;
867 				}
868 				entity = (Entity*)node->element;
869 				if ( !entity->flags[INVISIBLE] )
870 				{
871 					entity->flags[INVISIBLE] = true;
872 					serverUpdateEntityBodypart(my, bodypart);
873 				}
874 				bodypart++;
875 			}
876 		}
877 		else
878 		{
879 			my->flags[INVISIBLE] = false;
880 			my->flags[BLOCKSIGHT] = true;
881 			bodypart = 0;
882 			for (node = my->children.first; node != nullptr; node = node->next)
883 			{
884 				if ( bodypart < 2 )
885 				{
886 					bodypart++;
887 					continue;
888 				}
889 				if ( bodypart >= 7 )
890 				{
891 					break;
892 				}
893 				entity = (Entity*)node->element;
894 				if ( entity->flags[INVISIBLE] )
895 				{
896 					entity->flags[INVISIBLE] = false;
897 					serverUpdateEntityBodypart(my, bodypart);
898 					serverUpdateEntityFlag(my, INVISIBLE);
899 				}
900 				bodypart++;
901 			}
902 		}
903 
904 		// sleeping
905 		if ( myStats->EFFECTS[EFF_ASLEEP] )
906 		{
907 			my->z = 1.5;
908 			my->pitch = PI / 4;
909 		}
910 		else
911 		{
912 			my->z = -1;
913 			if ( my->monsterAttack == 0 )
914 			{
915 				my->pitch = 0;
916 			}
917 		}
918 
919 		// levitation
920 		bool levitating = isLevitating(myStats);
921 		if ( levitating )
922 		{
923 			my->z -= 1; // floating
924 		}
925 	}
926 
927 	Entity* shieldarm = nullptr;
928 	Entity* helmet = nullptr;
929 
930 	// move bodyparts
931 	for (bodypart = 0, node = my->children.first; node != nullptr; node = node->next, bodypart++)
932 	{
933 		if ( bodypart < 2 )
934 		{
935 			if ( multiplayer == CLIENT )
936 			{
937 				for ( int i = LIMB_HUMANOID_TORSO; i <= LIMB_HUMANOID_LEFTARM; i++ )
938 				{
939 					my->humanSetLimbsClient(i);
940 				}
941 			}
942 			continue;
943 		}
944 		entity = (Entity*)node->element;
945 		entity->x = my->x;
946 		entity->y = my->y;
947 		entity->z = my->z;
948 		if ( MONSTER_ATTACK == MONSTER_POSE_MAGIC_WINDUP1 && bodypart == LIMB_HUMANOID_RIGHTARM )
949 		{
950 			// don't let the creatures's yaw move the casting arm
951 		}
952 		else
953 		{
954 			entity->yaw = my->yaw;
955 		}
956 		if ( bodypart == LIMB_HUMANOID_RIGHTLEG || bodypart == LIMB_HUMANOID_LEFTARM )
957 		{
958 			my->humanoidAnimateWalk(entity, node, bodypart, HUMANWALKSPEED, dist, 0.4);
959 		}
960 		else if ( bodypart == LIMB_HUMANOID_LEFTLEG || bodypart == LIMB_HUMANOID_RIGHTARM || bodypart == LIMB_HUMANOID_CLOAK )
961 		{
962 			// left leg, right arm, cloak.
963 			if ( bodypart == LIMB_HUMANOID_RIGHTARM )
964 			{
965 				weaponarm = entity;
966 				if ( my->monsterAttack > 0 )
967 				{
968 					my->handleWeaponArmAttack(weaponarm);
969 				}
970 			}
971 			else if ( bodypart == LIMB_HUMANOID_CLOAK )
972 			{
973 				entity->pitch = entity->fskill[0];
974 			}
975 
976 			my->humanoidAnimateWalk(entity, node, bodypart, HUMANWALKSPEED, dist, 0.4);
977 
978 			if ( bodypart == LIMB_HUMANOID_CLOAK )
979 			{
980 				entity->fskill[0] = entity->pitch;
981 				entity->roll = my->roll - fabs(entity->pitch) / 2;
982 				entity->pitch = 0;
983 			}
984 		}
985 		switch ( bodypart )
986 		{
987 			// torso
988 			case LIMB_HUMANOID_TORSO:
989 				if ( multiplayer != CLIENT )
990 				{
991 					if ( myStats->breastplate == nullptr )
992 					{
993 						switch ( myStats->appearance / 6 )
994 						{
995 							case 1:
996 								entity->sprite = 334 + 13 * myStats->sex;
997 								break;
998 							case 2:
999 								entity->sprite = 360 + 13 * myStats->sex;
1000 								break;
1001 							default:
1002 								entity->sprite = 106 + 12 * myStats->sex;
1003 								break;
1004 						}
1005 					}
1006 					else
1007 					{
1008 						entity->sprite = itemModel(myStats->breastplate);
1009 					}
1010 					if ( multiplayer == SERVER )
1011 					{
1012 						// update sprites for clients
1013 						if ( entity->skill[10] != entity->sprite )
1014 						{
1015 							entity->skill[10] = entity->sprite;
1016 							serverUpdateEntityBodypart(my, bodypart);
1017 						}
1018 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1019 						{
1020 							serverUpdateEntityBodypart(my, bodypart);
1021 						}
1022 					}
1023 				}
1024 
1025 				if ( multiplayer == CLIENT )
1026 				{
1027 					if ( entity->skill[7] == 0 )
1028 					{
1029 						if ( entity->sprite == 106 )
1030 						{
1031 							// this is the default torso
1032 							// chances are they may be wrong if sent by the server,
1033 						}
1034 						else
1035 						{
1036 							// otherwise we're being sent gloves armor etc so it's probably right.
1037 							entity->skill[7] = entity->sprite;
1038 						}
1039 					}
1040 					if ( entity->skill[7] == 0 )
1041 					{
1042 						// we set this ourselves until proper initialisation.
1043 						my->humanSetLimbsClient(bodypart);
1044 					}
1045 					else
1046 					{
1047 						entity->sprite = entity->skill[7];
1048 					}
1049 				}
1050 
1051 				entity->x -= .25 * cos(my->yaw);
1052 				entity->y -= .25 * sin(my->yaw);
1053 				entity->z += 2.5;
1054 				break;
1055 			// right leg
1056 			case LIMB_HUMANOID_RIGHTLEG:
1057 				if ( multiplayer != CLIENT )
1058 				{
1059 					if ( myStats->shoes == nullptr )
1060 					{
1061 						switch ( myStats->appearance / 6 )
1062 						{
1063 							case 1:
1064 								entity->sprite = 335 + 13 * myStats->sex;
1065 								break;
1066 							case 2:
1067 								entity->sprite = 361 + 13 * myStats->sex;
1068 								break;
1069 							default:
1070 								entity->sprite = 107 + 12 * myStats->sex;
1071 								break;
1072 						}
1073 					}
1074 					else
1075 					{
1076 						my->setBootSprite(entity, SPRITE_BOOT_RIGHT_OFFSET);
1077 					}
1078 					if ( multiplayer == SERVER )
1079 					{
1080 						// update sprites for clients
1081 						if ( entity->skill[10] != entity->sprite )
1082 						{
1083 							entity->skill[10] = entity->sprite;
1084 							serverUpdateEntityBodypart(my, bodypart);
1085 						}
1086 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1087 						{
1088 							serverUpdateEntityBodypart(my, bodypart);
1089 						}
1090 					}
1091 				}
1092 
1093 				if ( multiplayer == CLIENT )
1094 				{
1095 					if ( entity->skill[7] == 0 )
1096 					{
1097 						if ( entity->sprite == 108 || entity->sprite == 107 )
1098 						{
1099 							// these are the default legs
1100 							// chances are they may be wrong if sent by the server,
1101 						}
1102 						else
1103 						{
1104 							// otherwise we're being sent gloves armor etc so it's probably right.
1105 							entity->skill[7] = entity->sprite;
1106 						}
1107 					}
1108 					if ( entity->skill[7] == 0 )
1109 					{
1110 						// we set this ourselves until proper initialisation.
1111 						my->humanSetLimbsClient(bodypart);
1112 					}
1113 					else
1114 					{
1115 						entity->sprite = entity->skill[7];
1116 					}
1117 				}
1118 
1119 				entity->x += 1 * cos(my->yaw + PI / 2) + .25 * cos(my->yaw);
1120 				entity->y += 1 * sin(my->yaw + PI / 2) + .25 * sin(my->yaw);
1121 				entity->z += 5;
1122 				if ( my->z >= 1.4 && my->z <= 1.6 )
1123 				{
1124 					entity->yaw += PI / 8;
1125 					entity->pitch = -PI / 2;
1126 				}
1127 				break;
1128 			// left leg
1129 			case LIMB_HUMANOID_LEFTLEG:
1130 				if ( multiplayer != CLIENT )
1131 				{
1132 					if ( myStats->shoes == nullptr )
1133 					{
1134 						switch ( myStats->appearance / 6 )
1135 						{
1136 							case 1:
1137 								entity->sprite = 336 + 13 * myStats->sex;
1138 								break;
1139 							case 2:
1140 								entity->sprite = 362 + 13 * myStats->sex;
1141 								break;
1142 							default:
1143 								entity->sprite = 108 + 12 * myStats->sex;
1144 								break;
1145 						}
1146 					}
1147 					else
1148 					{
1149 						my->setBootSprite(entity, SPRITE_BOOT_LEFT_OFFSET);
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->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1160 						{
1161 							serverUpdateEntityBodypart(my, bodypart);
1162 						}
1163 					}
1164 				}
1165 
1166 				if ( multiplayer == CLIENT )
1167 				{
1168 					if ( entity->skill[7] == 0 )
1169 					{
1170 						if ( entity->sprite == 108 || entity->sprite == 107 )
1171 						{
1172 							// these are the default legs
1173 							// chances are they may be wrong if sent by the server,
1174 						}
1175 						else
1176 						{
1177 							// otherwise we're being sent gloves armor etc so it's probably right.
1178 							entity->skill[7] = entity->sprite;
1179 						}
1180 					}
1181 					if ( entity->skill[7] == 0 )
1182 					{
1183 						// we set this ourselves until proper initialisation.
1184 						my->humanSetLimbsClient(bodypart);
1185 					}
1186 					else
1187 					{
1188 						entity->sprite = entity->skill[7];
1189 					}
1190 				}
1191 
1192 				entity->x -= 1 * cos(my->yaw + PI / 2) - .25 * cos(my->yaw);
1193 				entity->y -= 1 * sin(my->yaw + PI / 2) - .25 * sin(my->yaw);
1194 				entity->z += 5;
1195 				if ( my->z >= 1.4 && my->z <= 1.6 )
1196 				{
1197 					entity->yaw -= PI / 8;
1198 					entity->pitch = -PI / 2;
1199 				}
1200 				break;
1201 			// right arm
1202 			case LIMB_HUMANOID_RIGHTARM:
1203 			{
1204 				if ( multiplayer != CLIENT )
1205 				{
1206 					if ( myStats->gloves == nullptr )
1207 					{
1208 						switch ( myStats->appearance / 6 )
1209 						{
1210 							case 1:
1211 								entity->sprite = 337 + 13 * myStats->sex;
1212 								break;
1213 							case 2:
1214 								entity->sprite = 363 + 13 * myStats->sex;
1215 								break;
1216 							default:
1217 								entity->sprite = 109 + 12 * myStats->sex;
1218 								break;
1219 						}
1220 					}
1221 					else
1222 					{
1223 						if ( setGloveSprite(myStats, entity, SPRITE_GLOVE_RIGHT_OFFSET) != 0 )
1224 						{
1225 							// successfully set sprite for the human model
1226 						}
1227 					}
1228 					if ( multiplayer == SERVER )
1229 					{
1230 						// update sprites for clients
1231 						if ( entity->skill[10] != entity->sprite )
1232 						{
1233 							entity->skill[10] = entity->sprite;
1234 							serverUpdateEntityBodypart(my, bodypart);
1235 						}
1236 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1237 						{
1238 							serverUpdateEntityBodypart(my, bodypart);
1239 						}
1240 					}
1241 				}
1242 
1243 				if ( multiplayer == CLIENT )
1244 				{
1245 					if ( entity->skill[7] == 0 )
1246 					{
1247 						if ( entity->sprite >= 109 && entity->sprite <= 110 )
1248 						{
1249 							// these are the default arms.
1250 							// chances are they may be wrong if sent by the server,
1251 						}
1252 						else
1253 						{
1254 							// otherwise we're being sent gloves armor etc so it's probably right.
1255 							entity->skill[7] = entity->sprite;
1256 						}
1257 					}
1258 					if ( entity->skill[7] == 0 )
1259 					{
1260 						// we set this ourselves until proper initialisation.
1261 						my->humanSetLimbsClient(bodypart);
1262 					}
1263 					else
1264 					{
1265 						entity->sprite = entity->skill[7];
1266 					}
1267 				}
1268 
1269 				node_t* tempNode = list_Node(&my->children, LIMB_HUMANOID_WEAPON);
1270 				if ( tempNode )
1271 				{
1272 					Entity* weapon = (Entity*)tempNode->element;
1273 					if ( MONSTER_ARMBENDED || (weapon->flags[INVISIBLE] && my->monsterState != MONSTER_STATE_ATTACK) )
1274 					{
1275 						// if weapon invisible and I'm not attacking, relax arm.
1276 						entity->focalx = limbs[HUMAN][4][0]; // 0
1277 						entity->focaly = limbs[HUMAN][4][1]; // 0
1278 						entity->focalz = limbs[HUMAN][4][2]; // 1.5
1279 					}
1280 					else
1281 					{
1282 						// else flex arm.
1283 						entity->focalx = limbs[HUMAN][4][0] + 0.75;
1284 						entity->focaly = limbs[HUMAN][4][1];
1285 						entity->focalz = limbs[HUMAN][4][2] - 0.75;
1286 						entity->sprite += 2;
1287 					}
1288 				}
1289 
1290 				entity->x += 2.5 * cos(my->yaw + PI / 2) - .20 * cos(my->yaw);
1291 				entity->y += 2.5 * sin(my->yaw + PI / 2) - .20 * sin(my->yaw);
1292 				entity->z += 1.5;
1293 				entity->yaw += MONSTER_WEAPONYAW;
1294 				if ( my->z >= 1.4 && my->z <= 1.6 )
1295 				{
1296 					entity->pitch = 0;
1297 				}
1298 				break;
1299 			}
1300 			// left arm
1301 			case LIMB_HUMANOID_LEFTARM:
1302 			{
1303 				shieldarm = entity;
1304 				if ( multiplayer != CLIENT )
1305 				{
1306 					if ( myStats->gloves == nullptr )
1307 					{
1308 						switch ( myStats->appearance / 6 )
1309 						{
1310 							case 1:
1311 								entity->sprite = 338 + 13 * myStats->sex;
1312 								break;
1313 							case 2:
1314 								entity->sprite = 364 + 13 * myStats->sex;
1315 								break;
1316 							default:
1317 								entity->sprite = 110 + 12 * myStats->sex;
1318 								break;
1319 						}
1320 					}
1321 					else
1322 					{
1323 						if ( setGloveSprite(myStats, entity, SPRITE_GLOVE_LEFT_OFFSET) != 0 )
1324 						{
1325 							// successfully set sprite for the human model
1326 						}
1327 					}
1328 					if ( multiplayer == SERVER )
1329 					{
1330 						// update sprites for clients
1331 						if ( entity->skill[10] != entity->sprite )
1332 						{
1333 							entity->skill[10] = entity->sprite;
1334 							serverUpdateEntityBodypart(my, bodypart);
1335 						}
1336 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1337 						{
1338 							serverUpdateEntityBodypart(my, bodypart);
1339 						}
1340 					}
1341 				}
1342 
1343 				if ( multiplayer == CLIENT )
1344 				{
1345 					if ( entity->skill[7] == 0 )
1346 					{
1347 						if ( entity->sprite >= 109 && entity->sprite <= 110 )
1348 						{
1349 							// these are the default arms.
1350 							// chances are they may be wrong if sent by the server,
1351 						}
1352 						else
1353 						{
1354 							// otherwise we're being sent gloves armor etc so it's probably right.
1355 							entity->skill[7] = entity->sprite;
1356 						}
1357 					}
1358 					if ( entity->skill[7] == 0 )
1359 					{
1360 						// we set this ourselves until proper initialisation.
1361 						my->humanSetLimbsClient(bodypart);
1362 					}
1363 					else
1364 					{
1365 						entity->sprite = entity->skill[7];
1366 					}
1367 				}
1368 
1369 				node_t* tempNode = list_Node(&my->children, LIMB_HUMANOID_SHIELD);
1370 				if ( tempNode )
1371 				{
1372 					Entity* shield = (Entity*)tempNode->element;
1373 					if ( shield->flags[INVISIBLE] && (my->monsterState != MONSTER_STATE_ATTACK) )
1374 					{
1375 						// if shield invisible and I'm not attacking, relax arm.
1376 						entity->focalx = limbs[HUMAN][5][0]; // 0
1377 						entity->focaly = limbs[HUMAN][5][1]; // 0
1378 						entity->focalz = limbs[HUMAN][5][2]; // 1.5
1379 					}
1380 					else
1381 					{
1382 						// else flex arm.
1383 						entity->focalx = limbs[HUMAN][5][0] + 0.75;
1384 						entity->focaly = limbs[HUMAN][5][1];
1385 						entity->focalz = limbs[HUMAN][5][2] - 0.75;
1386 						entity->sprite += 2;
1387 					}
1388 				}
1389 				entity->x -= 2.5 * cos(my->yaw + PI / 2) + .20 * cos(my->yaw);
1390 				entity->y -= 2.5 * sin(my->yaw + PI / 2) + .20 * sin(my->yaw);
1391 				entity->z += 1.5;
1392 				if ( my->z >= 1.4 && my->z <= 1.6 )
1393 				{
1394 					entity->pitch = 0;
1395 				}
1396 				if ( my->monsterDefend && my->monsterAttack == 0 )
1397 				{
1398 					MONSTER_SHIELDYAW = PI / 5;
1399 				}
1400 				else
1401 				{
1402 					MONSTER_SHIELDYAW = 0;
1403 				}
1404 				entity->yaw += MONSTER_SHIELDYAW;
1405 				break;
1406 			}
1407 			// weapon
1408 			case LIMB_HUMANOID_WEAPON:
1409 				if ( multiplayer != CLIENT )
1410 				{
1411 					if ( myStats->weapon == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1412 					{
1413 						entity->flags[INVISIBLE] = true;
1414 					}
1415 					else
1416 					{
1417 						entity->sprite = itemModel(myStats->weapon);
1418 						if ( itemCategory(myStats->weapon) == SPELLBOOK )
1419 						{
1420 							entity->flags[INVISIBLE] = true;
1421 						}
1422 						else
1423 						{
1424 							entity->flags[INVISIBLE] = false;
1425 						}
1426 					}
1427 					if ( multiplayer == SERVER )
1428 					{
1429 						// update sprites for clients
1430 						if ( entity->skill[10] != entity->sprite )
1431 						{
1432 							entity->skill[10] = entity->sprite;
1433 							serverUpdateEntityBodypart(my, bodypart);
1434 						}
1435 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1436 						{
1437 							entity->skill[11] = entity->flags[INVISIBLE];
1438 							serverUpdateEntityBodypart(my, bodypart);
1439 						}
1440 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1441 						{
1442 							serverUpdateEntityBodypart(my, bodypart);
1443 						}
1444 					}
1445 				}
1446 				else
1447 				{
1448 					if ( entity->sprite <= 0 )
1449 					{
1450 						entity->flags[INVISIBLE] = true;
1451 					}
1452 				}
1453 				if ( weaponarm != nullptr )
1454 				{
1455 					my->handleHumanoidWeaponLimb(entity, weaponarm);
1456 				}
1457 				break;
1458 			// shield
1459 			case LIMB_HUMANOID_SHIELD:
1460 				if ( multiplayer != CLIENT )
1461 				{
1462 					if ( myStats->shield == nullptr )
1463 					{
1464 						entity->flags[INVISIBLE] = true;
1465 						entity->sprite = 0;
1466 					}
1467 					else
1468 					{
1469 						entity->flags[INVISIBLE] = false;
1470 						entity->sprite = itemModel(myStats->shield);
1471 						if ( itemTypeIsQuiver(myStats->shield->type) )
1472 						{
1473 							entity->handleQuiverThirdPersonModel(*myStats);
1474 						}
1475 					}
1476 					if ( myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1477 					{
1478 						entity->flags[INVISIBLE] = true;
1479 					}
1480 					if ( multiplayer == SERVER )
1481 					{
1482 						// update sprites for clients
1483 						if ( entity->skill[10] != entity->sprite )
1484 						{
1485 							entity->skill[10] = entity->sprite;
1486 							serverUpdateEntityBodypart(my, bodypart);
1487 						}
1488 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1489 						{
1490 							entity->skill[11] = entity->flags[INVISIBLE];
1491 							serverUpdateEntityBodypart(my, bodypart);
1492 						}
1493 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1494 						{
1495 							serverUpdateEntityBodypart(my, bodypart);
1496 						}
1497 					}
1498 				}
1499 				else
1500 				{
1501 					if ( entity->sprite <= 0 )
1502 					{
1503 						entity->flags[INVISIBLE] = true;
1504 					}
1505 				}
1506 				my->handleHumanoidShieldLimb(entity, shieldarm);
1507 				break;
1508 			// cloak
1509 			case LIMB_HUMANOID_CLOAK:
1510 				if ( multiplayer != CLIENT )
1511 				{
1512 					if ( myStats->cloak == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1513 					{
1514 						entity->flags[INVISIBLE] = true;
1515 					}
1516 					else
1517 					{
1518 						entity->flags[INVISIBLE] = false;
1519 						entity->sprite = itemModel(myStats->cloak);
1520 					}
1521 					if ( multiplayer == SERVER )
1522 					{
1523 						// update sprites for clients
1524 						if ( entity->skill[10] != entity->sprite )
1525 						{
1526 							entity->skill[10] = entity->sprite;
1527 							serverUpdateEntityBodypart(my, bodypart);
1528 						}
1529 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1530 						{
1531 							entity->skill[11] = entity->flags[INVISIBLE];
1532 							serverUpdateEntityBodypart(my, bodypart);
1533 						}
1534 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1535 						{
1536 							serverUpdateEntityBodypart(my, bodypart);
1537 						}
1538 					}
1539 				}
1540 				else
1541 				{
1542 					if ( entity->sprite <= 0 )
1543 					{
1544 						entity->flags[INVISIBLE] = true;
1545 					}
1546 				}
1547 				entity->x -= cos(my->yaw);
1548 				entity->y -= sin(my->yaw);
1549 				entity->yaw += PI / 2;
1550 				break;
1551 			// helm
1552 			case LIMB_HUMANOID_HELMET:
1553 				helmet = entity;
1554 				entity->focalx = limbs[HUMAN][9][0]; // 0
1555 				entity->focaly = limbs[HUMAN][9][1]; // 0
1556 				entity->focalz = limbs[HUMAN][9][2]; // -1.75
1557 				entity->pitch = my->pitch;
1558 				entity->roll = 0;
1559 				if ( multiplayer != CLIENT )
1560 				{
1561 					entity->sprite = itemModel(myStats->helmet);
1562 					if ( myStats->helmet == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring ) //TODO: isInvisible()?
1563 					{
1564 						entity->flags[INVISIBLE] = true;
1565 					}
1566 					else
1567 					{
1568 						entity->flags[INVISIBLE] = false;
1569 					}
1570 					if ( multiplayer == SERVER )
1571 					{
1572 						// update sprites for clients
1573 						if ( entity->skill[10] != entity->sprite )
1574 						{
1575 							entity->skill[10] = entity->sprite;
1576 							serverUpdateEntityBodypart(my, bodypart);
1577 						}
1578 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1579 						{
1580 							entity->skill[11] = entity->flags[INVISIBLE];
1581 							serverUpdateEntityBodypart(my, bodypart);
1582 						}
1583 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1584 						{
1585 							serverUpdateEntityBodypart(my, bodypart);
1586 						}
1587 					}
1588 				}
1589 				else
1590 				{
1591 					if ( entity->sprite <= 0 )
1592 					{
1593 						entity->flags[INVISIBLE] = true;
1594 					}
1595 				}
1596 				my->setHelmetLimbOffset(entity);
1597 				break;
1598 			// mask
1599 			case LIMB_HUMANOID_MASK:
1600 				entity->focalx = limbs[HUMAN][10][0]; // 0
1601 				entity->focaly = limbs[HUMAN][10][1]; // 0
1602 				entity->focalz = limbs[HUMAN][10][2]; // .5
1603 				entity->pitch = my->pitch;
1604 				entity->roll = PI / 2;
1605 				if ( multiplayer != CLIENT )
1606 				{
1607 					bool hasSteelHelm = false;
1608 					if ( myStats->helmet )
1609 					{
1610 						if ( myStats->helmet->type == STEEL_HELM
1611 							|| myStats->helmet->type == CRYSTAL_HELM
1612 							|| myStats->helmet->type == ARTIFACT_HELM )
1613 						{
1614 							hasSteelHelm = true;
1615 						}
1616 					}
1617 					if ( myStats->mask == nullptr || myStats->EFFECTS[EFF_INVISIBLE] || wearingring || hasSteelHelm ) //TODO: isInvisible()?
1618 					{
1619 						entity->flags[INVISIBLE] = true;
1620 					}
1621 					else
1622 					{
1623 						entity->flags[INVISIBLE] = false;
1624 					}
1625 					if ( myStats->mask != nullptr )
1626 					{
1627 						if ( myStats->mask->type == TOOL_GLASSES )
1628 						{
1629 							entity->sprite = 165; // GlassesWorn.vox
1630 						}
1631 						else
1632 						{
1633 							entity->sprite = itemModel(myStats->mask);
1634 						}
1635 					}
1636 					if ( multiplayer == SERVER )
1637 					{
1638 						// update sprites for clients
1639 						if ( entity->skill[10] != entity->sprite )
1640 						{
1641 							entity->skill[10] = entity->sprite;
1642 							serverUpdateEntityBodypart(my, bodypart);
1643 						}
1644 						if ( entity->skill[11] != entity->flags[INVISIBLE] )
1645 						{
1646 							entity->skill[11] = entity->flags[INVISIBLE];
1647 							serverUpdateEntityBodypart(my, bodypart);
1648 						}
1649 						if ( entity->getUID() % (TICKS_PER_SECOND * 10) == ticks % (TICKS_PER_SECOND * 10) )
1650 						{
1651 							serverUpdateEntityBodypart(my, bodypart);
1652 						}
1653 					}
1654 				}
1655 				else
1656 				{
1657 					if ( entity->sprite <= 0 )
1658 					{
1659 						entity->flags[INVISIBLE] = true;
1660 					}
1661 				}
1662 
1663 				if ( entity->sprite != 165 )
1664 				{
1665 					if ( entity->sprite == items[MASK_SHAMAN].index )
1666 					{
1667 						entity->roll = 0;
1668 						my->setHelmetLimbOffset(entity);
1669 						my->setHelmetLimbOffsetWithMask(helmet, entity);
1670 					}
1671 					else
1672 					{
1673 						entity->focalx = limbs[HUMAN][10][0] + .35; // .35
1674 						entity->focaly = limbs[HUMAN][10][1] - 2; // -2
1675 						entity->focalz = limbs[HUMAN][10][2]; // .5
1676 					}
1677 				}
1678 				else
1679 				{
1680 					entity->focalx = limbs[HUMAN][10][0] + .25; // .25
1681 					entity->focaly = limbs[HUMAN][10][1] - 2.25; // -2.25
1682 					entity->focalz = limbs[HUMAN][10][2]; // .5
1683 				}
1684 				break;
1685 		}
1686 	}
1687 	// rotate shield a bit
1688 	node_t* shieldNode = list_Node(&my->children, LIMB_HUMANOID_SHIELD);
1689 	if ( shieldNode )
1690 	{
1691 		Entity* shieldEntity = (Entity*)shieldNode->element;
1692 		if ( shieldEntity->sprite != items[TOOL_TORCH].index && shieldEntity->sprite != items[TOOL_LANTERN].index && shieldEntity->sprite != items[TOOL_CRYSTALSHARD].index )
1693 		{
1694 			shieldEntity->yaw -= PI / 6;
1695 		}
1696 	}
1697 	if ( MONSTER_ATTACK > 0 && MONSTER_ATTACK <= MONSTER_POSE_MAGIC_CAST3 )
1698 	{
1699 		MONSTER_ATTACKTIME++;
1700 	}
1701 	else if ( MONSTER_ATTACK == 0 )
1702 	{
1703 		MONSTER_ATTACKTIME = 0;
1704 	}
1705 	else
1706 	{
1707 		// do nothing, don't reset attacktime or increment it.
1708 	}
1709 }
1710 
humanCanWieldItem(const Item & item) const1711 bool Entity::humanCanWieldItem(const Item& item) const
1712 {
1713 	Stat* myStats = getStats();
1714 	if ( !myStats )
1715 	{
1716 		return false;
1717 	}
1718 
1719 	if ( monsterAllyIndex >= 0 && (monsterAllyClass != ALLY_CLASS_MIXED || item.interactNPCUid == getUID()) )
1720 	{
1721 		return monsterAllyEquipmentInClass(item);
1722 	}
1723 
1724 	switch ( itemCategory(&item) )
1725 	{
1726 		case WEAPON:
1727 			return true;
1728 		case ARMOR:
1729 			return true;
1730 		case MAGICSTAFF:
1731 			return false;
1732 		case THROWN:
1733 			return false;
1734 		case TOOL:
1735 			if ( itemTypeIsQuiver(item.type) )
1736 			{
1737 				return true;
1738 			}
1739 			break;
1740 		default:
1741 			return false;
1742 	}
1743 
1744 	return false;
1745 }
1746 
humanSetLimbsClient(int bodypart)1747 void Entity::humanSetLimbsClient(int bodypart)
1748 {
1749 	int skinColor = 0;
1750 	int sex = MALE;
1751 
1752 	// get the skinColor/sex from the head sprite.
1753 
1754 	if ( (sprite >= 113 && sprite < 118)
1755 		|| (sprite >= 125 && sprite < 130)
1756 		|| (sprite >= 332 && sprite < 334) )
1757 	{
1758 		skinColor = 0; // light.
1759 		if ( (sprite >= 125 && sprite < 130)
1760 			|| sprite == 333 )
1761 		{
1762 			sex = FEMALE;
1763 		}
1764 	}
1765 	else if ( (sprite >= 341 && sprite < 347)
1766 		|| (sprite >= 354 && sprite < 360) )
1767 	{
1768 		skinColor = 1; // medium.
1769 		if ( sprite >= 354 && sprite < 360 )
1770 		{
1771 			sex = FEMALE;
1772 		}
1773 	}
1774 	else if ( (sprite >= 367 && sprite < 373)
1775 		|| (sprite >= 380 && sprite < 386) )
1776 	{
1777 		skinColor = 2; // dark.
1778 		if ( sprite >= 380 && sprite < 386 )
1779 		{
1780 			sex = FEMALE;
1781 		}
1782 	}
1783 
1784 	node_t* limbNode = list_Node(&this->children, bodypart);
1785 	Entity* limb = nullptr;
1786 	if ( limbNode )
1787 	{
1788 		limb = (Entity*)limbNode->element;
1789 	}
1790 
1791 	if ( !limb )
1792 	{
1793 		return;
1794 	}
1795 
1796 	switch ( bodypart )
1797 	{
1798 		case LIMB_HUMANOID_TORSO:
1799 			switch ( skinColor )
1800 			{
1801 				case 1:
1802 					limb->sprite = 334 + 13 * sex;
1803 					break;
1804 				case 2:
1805 					limb->sprite = 360 + 13 * sex;
1806 					break;
1807 				default:
1808 					limb->sprite = 106 + 12 * sex;
1809 					break;
1810 			}
1811 			break;
1812 		case LIMB_HUMANOID_RIGHTLEG:
1813 			switch ( skinColor )
1814 			{
1815 				case 1:
1816 					limb->sprite = 335 + 13 * sex;
1817 					break;
1818 				case 2:
1819 					limb->sprite = 361 + 13 * sex;
1820 					break;
1821 				default:
1822 					limb->sprite = 107 + 12 * sex;
1823 					break;
1824 			}
1825 			break;
1826 		case LIMB_HUMANOID_LEFTLEG:
1827 			switch ( skinColor )
1828 			{
1829 				case 1:
1830 					limb->sprite = 336 + 13 * sex;
1831 					break;
1832 				case 2:
1833 					limb->sprite = 362 + 13 * sex;
1834 					break;
1835 				default:
1836 					limb->sprite = 108 + 12 * sex;
1837 					break;
1838 			}
1839 			break;
1840 		case LIMB_HUMANOID_RIGHTARM:
1841 			switch ( skinColor )
1842 			{
1843 				case 1:
1844 					limb->sprite = 337 + 13 * sex;
1845 					break;
1846 				case 2:
1847 					limb->sprite = 363 + 13 * sex;
1848 					break;
1849 				default:
1850 					limb->sprite = 109 + 12 * sex;
1851 					break;
1852 			}
1853 			break;
1854 		case LIMB_HUMANOID_LEFTARM:
1855 			switch ( skinColor )
1856 			{
1857 				case 1:
1858 					limb->sprite = 338 + 13 * sex;
1859 					break;
1860 				case 2:
1861 					limb->sprite = 364 + 13 * sex;
1862 					break;
1863 				default:
1864 					limb->sprite = 110 + 12 * sex;
1865 					break;
1866 			}
1867 			break;
1868 	}
1869 }
1870