]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/enemies.cpp
Update copyrights to 2011.
[quix0rs-blobwars.git] / src / enemies.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "enemies.h"
22
23 Entity *getDefinedEnemy(const char *name)
24 {
25         for (int i = 0 ; i < MAX_ENEMIES ; i++)
26         {
27                 if (strcmp(name, defEnemy[i].name) == 0)
28                 {
29                         return &defEnemy[i];
30                 }
31         }
32
33         debug(("No Such Enemy '%s'\n", name));
34
35         return NULL;
36 }
37
38 Entity *getEnemy(const char *name)
39 {
40         Entity *enemy = (Entity*)map.enemyList.getHead();
41
42         while (enemy->next != NULL)
43         {
44                 enemy = (Entity*)enemy->next;
45
46                 if (strcmp(name, enemy->name) == 0)
47                 {
48                         return enemy;
49                 }
50         }
51         
52         debug(("No Such Enemy '%s'\n", name));
53
54         return NULL;
55 }
56
57 void addEnemy(const char *name, int x, int y, int flags)
58 {
59         Entity *enemy = new Entity();
60         Entity *defEnemy = getDefinedEnemy(name);
61
62         if (defEnemy == NULL)
63         {
64                 debug(("ERROR : COULDN'T FIND ENEMY '%s'!\n", name));
65                 return;
66         }
67
68         enemy->setName(defEnemy->name);
69         enemy->setSprites(defEnemy->sprite[0], defEnemy->sprite[1], defEnemy->sprite[2]);
70         enemy->currentWeapon = defEnemy->currentWeapon;
71         enemy->value = defEnemy->value;
72         enemy->health = defEnemy->health;
73         enemy->flags = defEnemy->flags;
74
75         enemy->place(x, y);
76         enemy->setVelocity(0, 0);
77         enemy->baseThink = 60;
78
79         enemy->flags += flags;
80         
81         enemy->reload = 120; // Wait about seconds seconds before attacking
82
83         if (map.data[(int)(enemy->x) >> BRICKSHIFT][(int)(enemy->y) >> BRICKSHIFT] == MAP_WATER)
84         {
85                 enemy->environment = ENV_WATER;
86         }
87
88         map.addEnemy(enemy);
89 }
90
91 bool hasClearShot(Entity *enemy)
92 {
93         int mx, my;
94         float x = enemy->x;
95         float y = enemy->y;
96         float dx, dy;
97
98         Math::calculateSlope(player.x, player.y, enemy->x, enemy->y, &dx, &dy);
99
100         if ((dx == 0) && (dy == 0))
101                 return true;
102
103         while (true)
104         {
105                 x += dx;
106                 y += dy;
107
108                 //graphics.blit(graphics.getSprite("AimedShot", true)->getCurrentFrame(), (int)(x - engine.playerPosX), (int)(y - engine.playerPosY), graphics.screen, true);
109
110                 mx = (int)(x) >> BRICKSHIFT;
111                 my = (int)(y) >> BRICKSHIFT;
112
113                 if ((mx < 0) || (my < 0))
114                         return false;
115
116                 if (map.isSolid(mx, my))
117                         return false;
118
119                 if (Collision::collision(x, y, 3, 3, (int)player.x, (int)player.y, player.height, player.width))
120                         break;
121         }
122
123         return true;
124 }
125
126 void lookForPlayer(Entity *enemy)
127 {
128         // player is dead
129         if (player.health <= -60)
130                 return;
131         
132         if (game.missionOverReason == MIS_COMPLETE)
133                 return;
134
135         // can't fire anyway!
136         if (enemy->reload > 0)
137                 return;
138
139         int x = (int)fabs(enemy->x - player.x);
140         int y = (int)fabs(enemy->y - player.y);
141
142         // out of range
143         if (x > 480)
144                 return;
145
146         // can't even jump that high!
147         if (y > 100)
148                 return;
149
150         // Player is in range... go for them!
151         if (enemy->flags & ENT_ALWAYSCHASE)
152         {
153                 enemy->owner->tx = (int)(player.x);
154                 enemy->owner->ty = (int)(player.y);
155         }
156         else if ((Math::prand() % (35 - game.skill)) == 0)
157         {
158                 enemy->owner->tx = (int)(player.x);
159                 enemy->owner->ty = (int)(player.y);
160         }
161
162         // facing the wrong way
163         if ((enemy->face == 0) && (player.x < enemy->x))
164         {
165                 return;
166         }
167
168         // still facing the wrong way
169         if ((enemy->face == 1) && (player.x > enemy->x))
170         {
171                 return;
172         }
173
174         if (hasClearShot(enemy))
175         {
176                 if (enemy->flags & ENT_ALWAYSFIRES)
177                 {
178                         addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), 0);
179                         if (enemy->currentWeapon == &weapon[WP_ALIENSPREAD])
180                         {
181                                 addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), 2);
182                                 addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), -2);
183                         }
184                 }
185                 else if ((Math::prand() % 850) <= (game.skill * 5))
186                 {
187                         addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), 0);
188                         if (enemy->currentWeapon == &weapon[WP_ALIENSPREAD])
189                         {
190                                 addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), 2);
191                                 addBullet(enemy, enemy->currentWeapon->getSpeed(enemy->face), -2);
192                         }
193                 }
194
195                 if (enemy->flags & ENT_RAPIDFIRE)
196                 {
197                         if (enemy->flags & ENT_ALWAYSFIRES)
198                         {
199                                 if ((Math::prand() % 25) > game.skill * 3)
200                                         Math::removeBit(&enemy->flags, ENT_ALWAYSFIRES);
201                         }
202                         else
203                         {
204                                 if ((Math::prand() % 50) < game.skill * 2)
205                                         Math::addBit(&enemy->flags, ENT_ALWAYSFIRES);
206                         }
207                 }
208         }
209         else
210         {
211                 if (enemy->flags & ENT_RAPIDFIRE)
212                         Math::removeBit(&enemy->flags, ENT_ALWAYSFIRES);
213         }
214
215         if ((enemy->flags & ENT_FLIES) || (enemy->flags & ENT_SWIMS) || (enemy->flags & ENT_NOJUMP))
216                 return;
217                 
218         if (enemy->flags & ENT_JUMPS)
219         {
220                 if (!enemy->falling)
221                 {
222                         if ((Math::prand() % 25) == 0)
223                         {
224                                 int distance = Math::rrand(1, 4);
225                                 enemy->setVelocity(distance - ((distance * 2) * enemy->face), Math::rrand(-12, -10));
226                         }
227                 }
228                 
229                 return;
230         }
231
232         // Jump to try and reach player (even if they are approximately level with you!)
233         if (player.y - 5 < enemy->y)
234         {
235                 if (!enemy->falling)
236                 {
237                         if ((Math::prand() % 100) == 0)
238                         {
239                                 enemy->dy = -12;
240                         }
241                 }
242         }
243 }
244
245 void doAI(Entity *enemy)
246 {
247         if (enemy->flags & ENT_GALDOV)
248         {
249                 doGaldovAI(enemy);
250         }
251         else if (enemy->flags & ENT_BOSS)
252         {
253                 return;
254         }
255
256         int x = (int)enemy->x;
257         int y = (int)enemy->y + enemy->height;
258         
259         if (enemy->dx > 0)
260                 x += enemy->width;
261
262         x = x >> BRICKSHIFT;
263         y = y >> BRICKSHIFT;
264
265         if (enemy->dx == 0)
266                 enemy->tx = (int)enemy->x;
267
268         // Don't enter areas you're not supposed to
269         if (enemy->tx != (int)enemy->x)
270         {
271                 if (!(enemy->flags & (ENT_FLIES|ENT_SWIMS)))
272                 {
273                         if (!map.isSolid(x, y))
274                         {
275                                 enemy->tx = (int)enemy->x;
276                         }
277                 }
278         }
279
280         if ((int)enemy->x == enemy->tx)
281         {
282                 if ((Math::prand() % 100) == 0)
283                 {
284                         enemy->tx = (int)(enemy->x + Math::rrand(-640, 640));
285                         enemy->ty = (int)(enemy->y);
286                         if ((enemy->flags & ENT_FLIES) || (enemy->flags & ENT_SWIMS))
287                         {
288                                 enemy->ty = (int)(enemy->y + Math::rrand(-320, 320));
289                         }
290                 }
291
292                 Math::limitInt(&enemy->tx, 15, (MAPWIDTH * BRICKSIZE)- 20);
293                 Math::limitInt(&enemy->ty, 15, (MAPHEIGHT * BRICKSIZE)- 20);
294
295                 if (map.isSolid((enemy->tx >> BRICKSHIFT), (enemy->ty >> BRICKSHIFT)))
296                 {
297                         enemy->tx = (int)enemy->x;
298                         enemy->ty = (int)enemy->y;
299                 }
300         }
301
302         // Don't enter areas you're not supposed to
303         if (enemy->ty != (int)enemy->y)
304         {
305                 if (enemy->flags & ENT_FLIES)
306                 {
307                         if (map.isLiquid(x, y + 1))
308                         {
309                                 enemy->ty = (int)enemy->y;
310                         }
311                 }
312         }
313
314         if ((int)enemy->y == enemy->ty)
315         {
316                 enemy->y = enemy->ty;
317                 enemy->dx = 0;
318         }
319
320         if (!enemy->falling)
321                 enemy->dx = 0;
322
323         if ((enemy->flags & ENT_FLIES) || (enemy->flags & ENT_SWIMS))
324         {
325                 enemy->dx = enemy->dy = 0;
326
327                 if ((int)enemy->y < enemy->ty) enemy->dy = 1;
328                 if ((int)enemy->y > enemy->ty) enemy->dy = -1;
329         }
330
331         if ((int)enemy->x == enemy->tx) {enemy->dx = 0;}
332         if ((int)enemy->x < enemy->tx) {enemy->dx = 1; enemy->face = 0;}
333         if ((int)enemy->x > enemy->tx) {enemy->dx = -1; enemy->face = 1;}
334
335         if ((enemy->flags & ENT_SWIMS) && (enemy->environment == ENV_WATER))
336         {
337                 enemy->dy = 0;
338
339                 if ((int)enemy->y < enemy->ty) enemy->dy = 1;
340                 if ((int)enemy->y > enemy->ty) enemy->dy = -1;
341         }
342
343         lookForPlayer(enemy);
344 }
345
346 void checkCombo()
347 {
348         int old = game.currentComboHits;
349         
350         game.doCombo();
351         
352         if (old == 24 && game.currentComboHits == 25)
353         {
354                 presentPlayerMedal("25_Hit_Combo");
355         }
356 }
357
358 void enemyBulletCollisions(Entity *bullet)
359 {
360         if (bullet->health < 1)
361         {
362                 return;
363         }
364
365         Entity *enemy = (Entity*)map.enemyList.getHead();
366
367         while (enemy->next != NULL)
368         {
369                 enemy = (Entity*)enemy->next;
370
371                 if ((enemy->flags & ENT_TELEPORTING) || (enemy->dead == DEAD_DYING))
372                 {
373                         continue;
374                 }
375
376                 char comboString[100];
377
378                 if ((bullet->owner == &player) || (bullet->owner == &engine.world) || (bullet->flags & ENT_BOSS))
379                 {
380                         if (Collision::collision(enemy, bullet))
381                         {
382                                 if (bullet->id != WP_LASER)
383                                 {
384                                         bullet->health = 0;
385                                 }
386                                 
387                                 Math::removeBit(&bullet->flags, ENT_SPARKS);
388                                 Math::removeBit(&bullet->flags, ENT_PUFFS);
389
390                                 if ((enemy->flags & ENT_IMMUNE) && (!(enemy->flags & ENT_STATIC)))
391                                 {
392                                         bullet->health = 0; // include the Laser for this one!
393                                         enemy->owner->tx = (int)bullet->owner->x;
394                                         enemy->owner->ty = (int)bullet->owner->y;
395                                         if (enemy->x < enemy->tx) {enemy->owner->dx = 1; enemy->owner->face = 0;}
396                                         if (enemy->x > enemy->tx) {enemy->owner->dx = -1; enemy->owner->face = 1;}
397                                         return;
398                                 }
399
400                                 /*
401                                         Increment the bullet hits counter. The laser can only do this
402                                         if the target has more than 0 health. Overwise the stats screen
403                                         can show an accurracy of 800%. Which is just plain silly.
404                                 */
405                                 if (bullet->owner == &player)
406                                 {
407                                         enemy->tx = (int)player.x;
408                                         enemy->ty = (int)player.y;
409                                         enemy->face = 0;
410                                         
411                                         if (player.x < enemy->x)
412                                         {
413                                                 enemy->face = 1;
414                                         }
415
416                                         if ((bullet->id != WP_LASER) || (enemy->health > 0))
417                                         {
418                                                 game.incBulletsHit();
419                                         }
420                                 }
421
422                                 if (!(enemy->flags & ENT_EXPLODES))
423                                 {
424                                         audio.playSound(SND_HIT, CH_ANY);
425                                         if (game.gore)
426                                         {
427                                                 addBlood(enemy, bullet->dx / 4, Math::rrand(-6, -3), 1);
428                                         }
429                                         else
430                                         {
431                                                 addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
432                                         }
433                                 }
434                                 else
435                                 {
436                                         audio.playSound(SND_CLANG, CH_ANY);
437                                         addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
438                                 }
439
440                                 if (enemy->health > 0)
441                                 {
442                                         if (!(enemy->flags & ENT_IMMUNE))
443                                         {
444                                                 enemy->health -= bullet->damage;
445                                         }
446                                         
447                                         if (enemy->health <= 0)
448                                         {       
449                                                 if (bullet->owner == &player)
450                                                 {
451                                                         addPlayerScore(enemy->value);
452                                                         game.currentMissionEnemiesDefeated++;
453         
454                                                         if (player.currentWeapon != &weapon[WP_LASER])
455                                                         {
456                                                                 checkCombo();
457                                                         }
458                                                         
459                                                         snprintf(comboString, sizeof comboString, "Combo-%s", bullet->name);
460                                                         checkObjectives(comboString, false);
461                                                         checkObjectives("Enemy", false);
462                                                         checkObjectives(enemy->name, false);
463                                                 }
464         
465                                                 if (!(enemy->flags & ENT_STATIC))
466                                                 {
467                                                         enemy->dx = (bullet->dx / 4);
468                                                         enemy->dy = -10;
469                                                         
470                                                         if (enemy->flags & ENT_EXPLODES)
471                                                         {
472                                                                 audio.playSound(SND_ELECDEATH1 + Math::prand() % 3, CH_DEATH);
473                                                         }
474                                                         else if (game.gore)
475                                                         {
476                                                                 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
477                                                         }
478                                                 }
479                                         }
480                                         
481                                 }
482                                 
483                                 if (enemy->flags & ENT_STATIC)
484                                 {
485                                         return;
486                                 }
487
488                                 if (enemy->health < 0)
489                                 {
490                                         enemy->dx = Math::rrand(-3, 3);
491                                         enemy->dy = 5 - Math::prand() % 15;
492                                         enemy->health = -1;
493                                         
494                                         if (enemy->flags & ENT_EXPLODES)
495                                         {
496                                                 audio.playSound(SND_ELECDEATH1 + Math::prand() % 3, CH_DEATH);
497                                         }
498                                         else if (game.gore)
499                                         {
500                                                 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
501                                         }
502
503                                         if (bullet->owner == &player)
504                                         {
505                                                 if (player.currentWeapon != &weapon[WP_LASER])
506                                                 {
507                                                         snprintf(comboString, sizeof comboString, "Combo-%s", bullet->name);
508                                                         checkCombo();
509                                                         checkObjectives(comboString, false);
510                                                 }
511                                         }
512                                 }
513
514                                 if (game.currentComboHits >= 3)
515                                 {
516                                         char message[50];
517                                         snprintf(message, sizeof message, _("%d Hit Combo!"), game.currentComboHits);
518                                         engine.setInfoMessage(message, 0, INFO_NORMAL);
519                                 }
520
521                                 return;
522                         }
523                 }
524         }
525 }
526
527 int getNonGoreParticleColor(const char *name)
528 {
529         int rtn = graphics.yellow;
530         
531         if (strcmp(name, "Pistol Blob") == 0)
532         {
533                 rtn = graphics.green;
534         }
535         else if (strcmp(name, "Grenade Blob") == 0)
536         {
537                 rtn = graphics.skyBlue;
538         }
539         else if (strcmp(name, "Aqua Blob") == 0)
540         {
541                 rtn = graphics.cyan;
542         }
543         else if (strcmp(name, "Laser Blob") == 0)
544         {
545                 rtn = SDL_MapRGB(graphics.screen->format, 255, 0, 255);
546         }
547         else if (strcmp(name, "Machine Gun Blob") == 0)
548         {
549                 rtn = SDL_MapRGB(graphics.screen->format, 200, 64, 24);
550         }
551         
552         return rtn;
553 }
554
555 void gibEnemy(Entity *enemy)
556 {
557         if (enemy->flags & ENT_GALDOV)
558         {
559                 addTeleportParticles(enemy->x, enemy->y, 75, SND_TELEPORT3);
560                 checkObjectives("Galdov", true);
561         }
562
563         if (enemy->flags & ENT_EXPLODES)
564         {
565                 addExplosion(enemy->x + (enemy->width / 2), enemy->y + (enemy->height / 2), 10 + (20 * game.skill), enemy);
566                 addSmokeAndFire(enemy, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
567                 return;
568         }
569
570         float x, y, dx, dy;
571         int amount = (game.gore) ? 25 : 150;
572         int color = getNonGoreParticleColor(enemy->name);
573
574         for (int i = 0 ; i < amount ; i++)
575         {
576                 x = enemy->x + Math::rrand(-3, 3);
577                 y = enemy->y + Math::rrand(-3, 3);
578                 
579                 if (game.gore)
580                 {
581                         dx = Math::rrand(-5, 5);
582                         dy = Math::rrand(-15, -5);
583                         addEffect(x, y, dx, dy, EFF_BLEEDS);
584                 }
585                 else
586                 {
587                         dx = Math::rrand(-5, 5);
588                         dy = Math::rrand(-5, 5);
589                         addColoredEffect(x, y, dx, dy, color, EFF_COLORED + EFF_WEIGHTLESS);
590                 }
591         }
592         
593         (game.gore) ? audio.playSound(SND_SPLAT, CH_ANY) : audio.playSound(SND_POP, CH_ANY);
594 }
595
596 void doEnemies()
597 {
598         Entity *enemy = (Entity*)map.enemyList.getHead();
599         Entity *previous = enemy;
600         
601         map.fightingGaldov = false;
602
603         int x, y, absX, absY;
604
605         while (enemy->next != NULL)
606         {
607                 enemy = (Entity*)enemy->next;
608                 
609                 if (!engine.cheatBlood)
610                 {
611                         if (enemy->dead == DEAD_DYING)
612                         {
613                                 if (!enemy->referenced)
614                                 {
615                                         debug(("Removing unreferenced enemy '%s'\n", enemy->name));
616                                         map.enemyList.remove(previous, enemy);
617                                         enemy = previous;
618                                 }
619                                 else
620                                 {
621                                         previous = enemy;
622                                 }
623                                 
624                                 enemy->referenced = false;
625                                 continue;
626                         }
627                 }
628
629                 x = (int)(enemy->x - engine.playerPosX);
630                 y = (int)(enemy->y - engine.playerPosY);
631
632                 absX = abs(x);
633                 absY = abs(y);
634
635                 if ((absX < 800) && (absY < 600))
636                 {
637                         // Fly forever
638                         if (enemy->flags & ENT_FLIES)
639                         {
640                                 enemy->fuel = 7;
641                         }
642
643                         if (enemy->owner->flags & ENT_TELEPORTING)
644                         {
645                                 moveEntity(enemy);
646                         }
647                         else
648                         {
649                                 if ((enemy->health > 0) && (!(enemy->flags & ENT_STATIC)))
650                                 {
651                                         enemy->think();
652
653                                         if (enemy->owner == enemy)
654                                         {
655                                                 doAI(enemy);
656                                         }
657                                         else
658                                         {
659                                                 lookForPlayer(enemy);
660                                         }
661                                 }
662                                 
663                                 if (map.isBlizzardLevel)
664                                 {
665                                         enemy->dx += map.windPower * 0.1;
666                                 }
667
668                                 if (enemy->flags & ENT_NOMOVE)
669                                 {
670                                         enemy->dx = 0;
671                                 }
672
673                                 moveEntity(enemy);
674
675                                 if ((absX < 700) && (absY < 500))
676                                 {
677                                         if (enemy->flags & ENT_FIRETRAIL)
678                                         {
679                                                 addFireTrailParticle(enemy->x + (enemy->face * 16) + Math::rrand(-1, 1), enemy->y + Math::rrand(-1, 1));
680                                         }
681                                         
682                                         graphics.blit(enemy->getFaceImage(), x, y, graphics.screen, false);
683                                         
684                                         if ((enemy->dx != 0) || (enemy->flags & ENT_FLIES) || (enemy->flags & ENT_STATIC))
685                                         {
686                                                 enemy->animate();
687                                         }
688                                 }
689                         }
690                 }
691                 else
692                 {
693                         if (enemy->flags & ENT_SPAWNED)
694                         {
695                                 if ((absX > 1920) || (absY > 1440))
696                                 {
697                                         enemy->health = -100;
698                                 }
699                         }
700                 }
701
702                 if (enemy->health > 0)
703                 {
704                         previous = enemy;
705                         
706                         if ((enemy->environment == ENV_SLIME) || (enemy->environment == ENV_LAVA))
707                         {
708                                 checkObjectives(enemy->name, false);
709                                 enemy->health = -1;
710                         }
711                 }
712                 else
713                 {
714                         if (enemy->flags & ENT_GALDOV)
715                         {
716                                 enemy->health = -99;
717                         }
718
719                         if (enemy->health == 0)
720                         {
721                                 Math::removeBit(&enemy->flags, ENT_WEIGHTLESS);
722                                 Math::removeBit(&enemy->flags, ENT_SWIMS);
723                                 Math::removeBit(&enemy->flags, ENT_FLIES);
724                                 Math::addBit(&enemy->flags, ENT_INANIMATE);
725                                 Math::addBit(&enemy->flags, ENT_BOUNCES);
726                                 enemy->health = -1 - Math::prand() % 25;
727                         }
728                         
729                         if (engine.cheatBlood)
730                         {
731                                 if (!(enemy->flags & ENT_EXPLODES))
732                                 {
733                                         if ((enemy->health % 4) == 0)
734                                         {
735                                                 addBlood(enemy, Math::rrand(-2, 2), Math::rrand(-6, -3), 1);
736                                         }
737                                         else if ((enemy->health % 10) == 0)
738                                         {
739                                                 if (game.gore)
740                                                 {
741                                                         audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
742                                                 }
743                                         }
744                                 }
745                         }
746
747                         enemy->health--;
748
749                         if (enemy->flags & ENT_MULTIEXPLODE)
750                         {
751                                 if (enemy->health < -30)
752                                 {
753                                         if ((enemy->health % 3) == 0)
754                                         {
755                                                 addExplosion(enemy->x + Math::prand() % 25, enemy->y + Math::prand() % 25,  10 + (20 * game.skill), enemy);
756                                                 addSmokeAndFire(enemy, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
757                                         }
758                                 }
759                         }
760
761                         if (enemy->health > -50)
762                         {
763                                 previous = enemy;
764                         }
765                         else
766                         {
767                                 if (enemy->flags & ENT_GALDOVFINAL)
768                                 {
769                                         enemy->health = -30;
770                                         enemy->dx = Math::rrand(-10, 10);
771                                         enemy->dy = Math::rrand(-10, 10);
772                                 }
773                                 else
774                                 {
775                                         if (enemy->dead == DEAD_ALIVE)
776                                         {
777                                                 if ((absX < 800) && (absY < 600))
778                                                 {
779                                                         gibEnemy(enemy);
780                                                         
781                                                         if (enemy->value)
782                                                         {
783                                                                 dropRandomItems((int)enemy->x, (int)enemy->y);
784                                                         }
785                                                 }
786                                                 
787                                                 enemy->dead = DEAD_DYING;
788                                         }
789                                         
790                                         if (enemy->dead == DEAD_DYING)
791                                         {
792                                                 if (!enemy->referenced)
793                                                 {
794                                                         if ((absX < 800) && (absY < 600))
795                                                         {
796                                                                 gibEnemy(enemy);
797                                                                 
798                                                                 if (enemy->value)
799                                                                 {
800                                                                         dropRandomItems((int)enemy->x, (int)enemy->y);
801                                                                 }
802                                                         }
803                                                         
804                                                         debug(("Removing unreferenced enemy '%s'\n", enemy->name));
805                                                         map.enemyList.remove(previous, enemy);
806                                                         enemy = previous;
807                                                 }
808                                         }
809                                 }
810                         }
811                 }
812                 
813                 // default the enemy to not referenced.
814                 // doBullets() will change this if required.
815                 enemy->referenced = false;
816         }
817 }
818
819 void loadEnemy(const char *token)
820 {
821         int enemy = -1;
822
823         for (int i = MAX_ENEMIES ; i > -1 ; i--)
824                 if (strcmp(defEnemy[i].name, "") == 0)
825                         enemy = i;
826
827         if (enemy == -1)
828         {
829                 printf("Out of enemy define space!\n");
830                 exit(1);
831         }
832
833         char name[50], sprite[3][100], weapon[100], flags[1024];
834         int health, value;
835
836         sscanf(token, "%*c %[^\"] %*c %s %s %s %*c %[^\"] %*c %d %d %s", name, sprite[0], sprite[1], sprite[2], weapon, &health, &value, flags);
837
838         defEnemy[enemy].setName(name);
839         defEnemy[enemy].setSprites(graphics.getSprite(sprite[0], true), graphics.getSprite(sprite[1], true), graphics.getSprite(sprite[2], true));
840         defEnemy[enemy].currentWeapon = getWeaponByName(weapon);
841         defEnemy[enemy].health = health;
842         defEnemy[enemy].value = value;
843
844         defEnemy[enemy].flags = engine.getValueOfFlagTokens(flags);
845 }
846
847 void loadDefEnemies()
848 {
849         for (int i = 0 ; i < MAX_ENEMIES ; i++)
850         {
851                 defEnemy[i].name[0] = 0;
852         }
853
854         int enemy = 0;
855
856         if (!engine.loadData("data/defEnemies"))
857         {
858                 graphics.showErrorAndExit("Couldn't load enemy definitions file (%s)", "data/defEnemies");
859         }
860
861         char *token = strtok((char*)engine.dataBuffer, "\n");
862
863         char name[50], sprite[3][100], weapon[100], flags[1024];
864         int health, value;
865
866         while (true)
867         {
868                 if (strcmp(token, "@EOF@") == 0)
869                 {
870                         break;
871                 }
872
873                 sscanf(token, "%*c %[^\"] %*c %s %s %s %*c %[^\"] %*c %d %d %s", name, sprite[0], sprite[1], sprite[2], weapon, &health, &value, flags);
874
875                 defEnemy[enemy].setName(name);
876                 defEnemy[enemy].setSprites(graphics.getSprite(sprite[0], true), graphics.getSprite(sprite[1], true), graphics.getSprite(sprite[2], true));
877                 defEnemy[enemy].currentWeapon = getWeaponByName(weapon);
878                 defEnemy[enemy].health = health;
879                 defEnemy[enemy].value = value;
880                 defEnemy[enemy].flags = engine.getValueOfFlagTokens(flags);
881
882                 enemy++;
883
884                 token = strtok(NULL, "\n");
885         }
886 }