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