1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: monster_shared.cpp
5 	Desc: contains shared monster implementation and helper functions
6 
7 	Copyright 2013-2017 (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 "collision.hpp"
15 #include "player.hpp"
16 #include "entity.hpp"
17 
initMonster(int mySprite)18 void Entity::initMonster(int mySprite)
19 {
20 	sprite = mySprite;
21 
22 	//Common flags.
23 	flags[UPDATENEEDED] = true;
24 	flags[BLOCKSIGHT] = true;
25 	flags[INVISIBLE] = false;
26 
27 	int monsterType = this->getMonsterTypeFromSprite();
28 
29 	switch ( monsterType )
30 	{
31 		case GNOME:
32 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
33 			monsterSpellAnimation = MONSTER_SPELLCAST_SMALL_HUMANOID;
34 			break;
35 		case KOBOLD:
36 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
37 			monsterSpellAnimation = MONSTER_SPELLCAST_SMALL_HUMANOID;
38 			break;
39 		case HUMAN:
40 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
41 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
42 			break;
43 		case RAT:
44 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
45 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
46 			break;
47 		case GOBLIN:
48 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
49 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
50 			break;
51 		case SLIME:
52 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
53 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
54 			break;
55 		case TROLL:
56 			monsterFootstepType = MONSTER_FOOTSTEP_STOMP;
57 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
58 			break;
59 		case OCTOPUS:
60 			// unused
61 			break;
62 		case SPIDER:
63 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
64 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
65 			break;
66 		case GHOUL:
67 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
68 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
69 			break;
70 		case SKELETON:
71 			monsterFootstepType = MONSTER_FOOTSTEP_SKELETON;
72 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
73 			break;
74 		case SCORPION:
75 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
76 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
77 			break;
78 		case CREATURE_IMP:
79 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
80 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
81 			break;
82 		case BUGBEAR:
83 			// unused
84 			break;
85 		case DEMON:
86 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
87 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
88 			break;
89 		case SUCCUBUS:
90 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
91 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
92 			break;
93 		case MIMIC:
94 			// unused
95 			break;
96 		case LICH:
97 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
98 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
99 			break;
100 		case MINOTAUR:
101 			monsterFootstepType = MONSTER_FOOTSTEP_STOMP;
102 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
103 			break;
104 		case DEVIL:
105 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
106 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
107 			break;
108 		case SHOPKEEPER:
109 			monsterFootstepType = MONSTER_FOOTSTEP_LEATHER;
110 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
111 			break;
112 		case SCARAB:
113 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
114 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
115 			break;
116 		case CRYSTALGOLEM:
117 			monsterFootstepType = MONSTER_FOOTSTEP_STOMP;
118 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
119 			break;
120 		case INCUBUS:
121 			monsterFootstepType = MONSTER_FOOTSTEP_LEATHER;
122 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
123 			break;
124 		case VAMPIRE:
125 			monsterFootstepType = MONSTER_FOOTSTEP_LEATHER;
126 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
127 			break;
128 		case SHADOW:
129 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
130 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
131 			break;
132 		case COCKATRICE:
133 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
134 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
135 			break;
136 		case INSECTOID:
137 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
138 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
139 			break;
140 		case GOATMAN:
141 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
142 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
143 			break;
144 		case AUTOMATON:
145 			monsterFootstepType = MONSTER_FOOTSTEP_USE_BOOTS;
146 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
147 			break;
148 		case LICH_ICE:
149 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
150 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
151 			break;
152 		case LICH_FIRE:
153 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
154 			monsterSpellAnimation = MONSTER_SPELLCAST_HUMANOID;
155 			break;
156 		case SENTRYBOT:
157 		case SPELLBOT:
158 		case GYROBOT:
159 		case DUMMYBOT:
160 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
161 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
162 			break;
163 		default:
164 			monsterFootstepType = MONSTER_FOOTSTEP_NONE;
165 			monsterSpellAnimation = MONSTER_SPELLCAST_NONE;
166 			break;
167 	}
168 	return;
169 }
170 
getMonsterTypeFromSprite()171 int Entity::getMonsterTypeFromSprite()
172 {
173 	int mySprite = this->sprite;
174 
175 	if ( (mySprite >= 113 && mySprite < 118) ||
176 		(mySprite >= 125 && mySprite < 130) ||
177 		(mySprite >= 332 && mySprite < 334) ||
178 		(mySprite >= 341 && mySprite < 347) ||
179 		(mySprite >= 354 && mySprite < 360) ||
180 		(mySprite >= 367 && mySprite < 373) ||
181 		(mySprite >= 380 && mySprite < 386) )   // human heads
182 	{
183 		return HUMAN;
184 	}
185 	else if ( mySprite == 131 || mySprite == 265 || mySprite == 814 )     // rat
186 	{
187 		return RAT;
188 	}
189 	else if ( mySprite == 180 || mySprite == 694 || mySprite == 752 )     // goblin head
190 	{
191 		return GOBLIN;
192 	}
193 	else if ( mySprite == 196 || mySprite == 266 )     // scorpion body
194 	{
195 		return SCORPION;
196 	}
197 	else if ( mySprite == 190 || mySprite == 710 )     // succubus head
198 	{
199 		return SUCCUBUS;
200 	}
201 	else if ( mySprite == 204 || mySprite == 817 )     // troll head
202 	{
203 		return TROLL;
204 	}
205 	else if ( mySprite == 217 )     // shopkeeper head
206 	{
207 		return SHOPKEEPER;
208 	}
209 	else if ( mySprite == 229 || mySprite == 686 )     // skeleton head
210 	{
211 		return SKELETON;
212 	}
213 	else if ( mySprite == 239 )     // minotaur waist
214 	{
215 		return MINOTAUR;
216 	}
217 	else if ( mySprite == 246 )     // ghoul head
218 	{
219 		return GHOUL;
220 	}
221 	else if ( mySprite == 258 )     // demon head
222 	{
223 		return DEMON;
224 	}
225 	else if ( mySprite == 267 || mySprite == 823 )     // spider body
226 	{
227 		return SPIDER;
228 	}
229 	else if ( mySprite == 274 )     // lich body
230 	{
231 		return LICH;
232 	}
233 	else if ( mySprite == 289 || mySprite == 827 )     // imp head
234 	{
235 		return CREATURE_IMP;
236 	}
237 	else if ( mySprite == 295 )     // gnome head
238 	{
239 		return GNOME;
240 	}
241 	else if ( mySprite == 304 )     // devil torso
242 	{
243 		return DEVIL;
244 	}
245 	else if ( mySprite == 475 )     // crystal golem head
246 	{
247 		return CRYSTALGOLEM;
248 	}
249 	else if ( mySprite == 413 )     // cockatrice head
250 	{
251 		return COCKATRICE;
252 	}
253 	else if ( mySprite == 467 || mySprite == 742 || mySprite == 770 )     // automaton head
254 	{
255 		return AUTOMATON;
256 	}
257 	else if ( mySprite == 429 || mySprite == 430 )     // scarab
258 	{
259 		return SCARAB;
260 	}
261 	else if ( mySprite == 421 )     // kobold head
262 	{
263 		return KOBOLD;
264 	}
265 	else if ( mySprite == 481 )     // shadow head
266 	{
267 		return SHADOW;
268 	}
269 	else if ( mySprite == 437 || mySprite == 718 || mySprite == 756 )     // vampire head
270 	{
271 		return VAMPIRE;
272 	}
273 	else if ( mySprite == 445 || mySprite == 702 )     // incubus head
274 	{
275 		return INCUBUS;
276 	}
277 	else if ( mySprite == 455 || mySprite == 726 || mySprite == 760 )     // insectoid head
278 	{
279 		return INSECTOID;
280 	}
281 	else if ( mySprite == 463 || mySprite == 734 || mySprite == 768 )     // goatman head
282 	{
283 		return GOATMAN;
284 	}
285 	else if ( mySprite == 646 )     // lich body
286 	{
287 		return LICH_FIRE;
288 	}
289 	else if ( mySprite == 650 )     // lich body
290 	{
291 		return LICH_ICE;
292 	}
293 	else if ( mySprite == 189 || mySprite == 210 )
294 	{
295 		return SLIME;
296 	}
297 	else if ( mySprite == 872 )     // sentrybot
298 	{
299 		return SENTRYBOT;
300 	}
301 	else if ( mySprite == 885 )
302 	{
303 		return SPELLBOT;
304 	}
305 	else if ( mySprite == 886 )
306 	{
307 		return GYROBOT;
308 	}
309 	else if ( mySprite == 889 )
310 	{
311 		return DUMMYBOT;
312 	}
313 	return NOTHING;
314 }
315 
actMonsterLimb(bool processLight)316 void Entity::actMonsterLimb(bool processLight)
317 {
318 	//If no longer part of a monster, delete the limb.
319 	Entity *parentEnt = nullptr;
320 	if ( (parentEnt = uidToEntity(skill[2])) == nullptr )
321 	{
322 		if ( multiplayer == CLIENT )
323 		{
324 			if ( light )
325 			{
326 				list_RemoveNode(light->node);
327 				light = nullptr;
328 			}
329 		}
330 		list_RemoveNode(mynode);
331 		return;
332 	}
333 
334 	//Do something magical beyond my comprehension.
335 	if ( multiplayer != CLIENT )
336 	{
337 		for ( int i = 0; i < MAXPLAYERS; ++i )
338 		{
339 			if ( inrange[i] )
340 			{
341 				if ( i == 0 && selectedEntity == this )
342 				{
343 					parentEnt->skill[13] = i + 1;
344 				}
345 				else if ( client_selected[i] == this )
346 				{
347 					parentEnt->skill[13] = i + 1;
348 				}
349 			}
350 		}
351 	}
352 
353 	if ( processLight )
354 	{
355 		//Only run by monsters who can carry stuff (like torches). Sorry, rats.
356 		if ( light != nullptr )
357 		{
358 			list_RemoveNode(light->node);
359 			light = nullptr;
360 		}
361 
362 		int carryingLightSource = 0;
363 		if ( flags[INVISIBLE] == false )
364 		{
365 			if ( sprite == 93 )   // torch
366 			{
367 				carryingLightSource = 6;
368 			}
369 			else if ( sprite == 94 )     // lantern
370 			{
371 				carryingLightSource = 9;
372 			}
373 			else if ( sprite == 529 )	// crystal shard
374 			{
375 				carryingLightSource = 4;
376 			}
377 		}
378 
379 		if ( carryingLightSource != 0 )
380 		{
381 			light = lightSphereShadow(x / 16, y / 16, carryingLightSource, 50 + 15 * carryingLightSource);
382 		}
383 	}
384 
385 	if ( parentEnt && parentEnt->behavior == &actMonster && parentEnt->monsterEntityRenderAsTelepath == 1 )
386 	{
387 		monsterEntityRenderAsTelepath = 1;
388 	}
389 	else
390 	{
391 		monsterEntityRenderAsTelepath = 0;
392 	}
393 }
394 
removeMonsterDeathNodes()395 void Entity::removeMonsterDeathNodes()
396 {
397 	int i = 0;
398 	node_t *nextnode = nullptr;
399 	for ( node_t *node = children.first; node != nullptr; node = nextnode )
400 	{
401 		nextnode = node->next;
402 		if ( node->element != nullptr && i >= 2 )
403 		{
404 			Entity* entity = (Entity*)node->element;
405 			if ( entity->light != nullptr )
406 			{
407 				list_RemoveNode(entity->light->node);
408 			}
409 			entity->light = nullptr;
410 			entity->flags[UPDATENEEDED] = false; //TODO: Do only demon & baphy need this?
411 			list_RemoveNode(entity->mynode);
412 		}
413 		list_RemoveNode(node);
414 		++i;
415 	}
416 }
417 
spawnBlood(int bloodSprite)418 void Entity::spawnBlood(int bloodSprite)
419 {
420 	if ( spawn_blood )
421 	{
422 		int tileX = std::min<unsigned int>(std::max<int>(0, this->x / 16), map.width - 1);
423 		int tileY = std::min<unsigned int>(std::max<int>(0, this->y / 16), map.height - 1);
424 		if ( map.tiles[tileY * MAPLAYERS + tileX * MAPLAYERS * map.height] )
425 		{
426 			if ( !checkObstacle(this->x, this->y, this, nullptr) )
427 			{
428 				Entity* entity = newEntity(bloodSprite, 1, map.entities, nullptr); //Blood/gib entity.
429 				entity->x = this->x;
430 				entity->y = this->y;
431 				entity->z = 8 + (rand() % 20) / 100.0;
432 				entity->parent = getUID();
433 				entity->sizex = 2;
434 				entity->sizey = 2;
435 				entity->yaw = (rand() % 360) * PI / 180.0;
436 				entity->flags[UPDATENEEDED] = true;
437 				entity->flags[PASSABLE] = true;
438 			}
439 		}
440 	}
441 }
442