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