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