]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/enemies.cpp
Use UNIX line endings everywhere.
[quix0rs-blobwars.git] / src / enemies.cpp
1 /*
2 Copyright (C) 2004 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))
272                 {
273                         //if ((map.data[x][y] == MAP_AIR) || (map.data[x][y] >= MAP_DECORATION))
274                         if (!map.isSolid(x, y))
275                         {
276                                 enemy->tx = (int)enemy->x;
277                         }
278                 }
279         }
280
281         if ((int)enemy->x == enemy->tx)
282         {
283                 if ((Math::prand() % 100) == 0)
284                 {
285                         enemy->tx = (int)(enemy->x + Math::rrand(-640, 640));
286                         enemy->ty = (int)(enemy->y);
287                         if ((enemy->flags & ENT_FLIES) || (enemy->flags & ENT_SWIMS))
288                         {
289                                 enemy->ty = (int)(enemy->y + Math::rrand(-320, 320));
290                         }
291                 }
292
293                 Math::limitInt(&enemy->tx, 15, (MAPWIDTH * BRICKSIZE)- 20);
294                 Math::limitInt(&enemy->ty, 15, (MAPHEIGHT * BRICKSIZE)- 20);
295
296                 if (map.isSolid((enemy->tx >> BRICKSHIFT), (enemy->ty >> BRICKSHIFT)))
297                 {
298                         enemy->tx = (int)enemy->x;
299                         enemy->ty = (int)enemy->y;
300                 }
301         }
302
303         // Don't enter areas you're not supposed to
304         if (enemy->ty != (int)enemy->y)
305         {
306                 if (enemy->flags & ENT_FLIES)
307                 {
308                         if (map.isLiquid(x, y + 1))
309                         {
310                                 enemy->ty = (int)enemy->y;
311                         }
312                 }
313         }
314
315         if ((int)enemy->y == enemy->ty)
316         {
317                 enemy->y = enemy->ty;
318                 enemy->dx = 0;
319         }
320
321         if (!enemy->falling)
322                 enemy->dx = 0;
323
324         if ((enemy->flags & ENT_FLIES) || (enemy->flags & ENT_SWIMS))
325         {
326                 enemy->dx = enemy->dy = 0;
327
328                 if ((int)enemy->y < enemy->ty) enemy->dy = 1;
329                 if ((int)enemy->y > enemy->ty) enemy->dy = -1;
330         }
331
332         if ((int)enemy->x == enemy->tx) {enemy->dx = 0;}
333         if ((int)enemy->x < enemy->tx) {enemy->dx = 1; enemy->face = 0;}
334         if ((int)enemy->x > enemy->tx) {enemy->dx = -1; enemy->face = 1;}
335
336         if ((enemy->flags & ENT_SWIMS) && (enemy->environment == ENV_WATER))
337         {
338                 enemy->dy = 0;
339
340                 if ((int)enemy->y < enemy->ty) enemy->dy = 1;
341                 if ((int)enemy->y > enemy->ty) enemy->dy = -1;
342         }
343
344         lookForPlayer(enemy);
345 }
346
347 void enemyBulletCollisions(Entity *bullet)
348 {
349         if (bullet->health < 1)
350         {
351                 return;
352         }
353
354         Entity *enemy = (Entity*)map.enemyList.getHead();
355
356         while (enemy->next != NULL)
357         {
358                 enemy = (Entity*)enemy->next;
359
360                 if ((enemy->flags & ENT_TELEPORTING) || (enemy->dead == DEAD_DYING))
361                 {
362                         continue;
363                 }
364
365                 char comboString[100];
366
367                 if ((bullet->owner == &player) || (bullet->owner == &engine.world) || (bullet->flags & ENT_BOSS))
368                 {
369                         sprintf(comboString, "Combo-%s", bullet->name);
370
371                         if (Collision::collision(enemy, bullet))
372                         {
373                                 if (bullet->id != WP_LASER)
374                                 {
375                                         bullet->health = 0;
376                                 }
377                                 
378                                 Math::removeBit(&bullet->flags, ENT_SPARKS);
379                                 Math::removeBit(&bullet->flags, ENT_PUFFS);
380
381                                 if ((enemy->flags & ENT_IMMUNE) && (!(enemy->flags & ENT_STATIC)))
382                                 {
383                                         bullet->health = 0; // include the Laser for this one!
384                                         enemy->owner->tx = (int)bullet->owner->x;
385                                         enemy->owner->ty = (int)bullet->owner->y;
386                                         if (enemy->x < enemy->tx) {enemy->owner->dx = 1; enemy->owner->face = 0;}
387                                         if (enemy->x > enemy->tx) {enemy->owner->dx = -1; enemy->owner->face = 1;}
388                                         return;
389                                 }
390
391                                 /*
392                                         Increment the bullet hits counter. The laser can only do this
393                                         if the target has more than 0 health. Overwise the stats screen
394                                         can show an accurracy of 800%. Which is just plain silly.
395                                 */
396                                 if (bullet->owner == &player)
397                                 {
398                                         enemy->tx = (int)player.x;
399                                         enemy->ty = (int)player.y;
400                                         enemy->face = 0;
401                                         
402                                         if (player.x < enemy->x)
403                                         {
404                                                 enemy->face = 1;
405                                         }
406
407                                         if ((bullet->id != WP_LASER) || (enemy->health > 0))
408                                         {
409                                                 game.incBulletsHit();
410                                         }
411                                 }
412
413                                 if (!(enemy->flags & ENT_EXPLODES))
414                                 {
415                                         audio.playSound(SND_HIT, CH_ANY);
416                                         if (game.gore)
417                                         {
418                                                 addBlood(enemy, bullet->dx / 4, Math::rrand(-6, -3), 1);
419                                         }
420                                         else
421                                         {
422                                                 addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
423                                         }
424                                 }
425                                 else
426                                 {
427                                         audio.playSound(SND_CLANG, CH_ANY);
428                                         addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
429                                 }
430
431                                 if (enemy->health > 0)
432                                 {
433                                         if (!(enemy->flags & ENT_IMMUNE))
434                                         {
435                                                 enemy->health -= bullet->damage;
436                                         }
437                                         
438                                         if (enemy->health <= 0)
439                                         {       
440                                                 if (bullet->owner == &player)
441                                                 {
442                                                         game.score += enemy->value;
443                                                         game.currentMissionEnemiesDefeated++;
444         
445                                                         if (player.currentWeapon != &weapon[WP_LASER])
446                                                         {
447                                                                 game.doCombo();
448                                                         }
449                                                         
450                                                         checkObjectives(comboString, false);
451                                                         checkObjectives("Enemy", false);
452                                                         checkObjectives(enemy->name, false);
453                                                 }
454         
455                                                 if (!(enemy->flags & ENT_STATIC))
456                                                 {
457                                                         enemy->dx = (bullet->dx / 4);
458                                                         enemy->dy = -10;
459                                                         
460                                                         if (enemy->flags & ENT_EXPLODES)
461                                                         {
462                                                                 audio.playSound(SND_ELECDEATH1 + Math::prand() % 3, CH_DEATH);
463                                                         }
464                                                         else if (game.gore)
465                                                         {
466                                                                 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
467                                                         }
468                                                 }
469                                         }
470                                         
471                                 }
472                                 
473                                 if (enemy->flags & ENT_STATIC)
474                                 {
475                                         return;
476                                 }
477
478                                 if (enemy->health < 0)
479                                 {
480                                         enemy->dx = Math::rrand(-3, 3);
481                                         enemy->dy = 5 - Math::prand() % 15;
482                                         enemy->health = -1;
483                                         
484                                         if (enemy->flags & ENT_EXPLODES)
485                                         {
486                                                 audio.playSound(SND_ELECDEATH1 + Math::prand() % 3, CH_DEATH);
487                                         }
488                                         else if (game.gore)
489                                         {
490                                                 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
491                                         }
492
493                                         if (bullet->owner == &player)
494                                         {
495                                                 if (player.currentWeapon != &weapon[WP_LASER])
496                                                 {
497                                                         game.doCombo();
498                                                         checkObjectives(comboString, false);
499                                                 }
500                                         }
501                                 }
502
503                                 if (game.currentComboHits >= 3)
504                                 {
505                                         char message[50];
506                                         sprintf(message, _("%d Hit Combo!"), game.currentComboHits);
507                                         engine.setInfoMessage(message, 0, INFO_NORMAL);
508                                 }
509
510                                 return;
511                         }
512                 }
513         }
514 }
515
516 int getNonGoreParticleColor(const char *name)
517 {
518         int rtn = graphics.yellow;
519         
520         if (strcmp(name, "Pistol Blob") == 0)
521         {
522                 rtn = graphics.green;
523         }
524         else if (strcmp(name, "Grenade Blob") == 0)
525         {
526                 rtn = graphics.skyBlue;
527         }
528         else if (strcmp(name, "Aqua Blob") == 0)
529         {
530                 rtn = graphics.cyan;
531         }
532         else if (strcmp(name, "Laser Blob") == 0)
533         {
534                 rtn = SDL_MapRGB(graphics.screen->format, 255, 0, 255);
535         }
536         else if (strcmp(name, "Machine Gun Blob") == 0)
537         {
538                 rtn = SDL_MapRGB(graphics.screen->format, 200, 64, 24);
539         }
540         
541         return rtn;
542 }
543
544 void gibEnemy(Entity *enemy)
545 {
546         if (enemy->flags & ENT_GALDOV)
547         {
548                 addTeleportParticles(enemy->x, enemy->y, 75, SND_TELEPORT3);
549                 checkObjectives("Galdov", true);
550         }
551
552         if (enemy->flags & ENT_EXPLODES)
553         {
554                 addExplosion(enemy->x + (enemy->width / 2), enemy->y + (enemy->height / 2), 10 + (20 * game.skill), enemy);
555                 addSmokeAndFire(enemy, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
556                 return;
557         }
558
559         float x, y, dx, dy;
560         int amount = (game.gore) ? 25 : 150;
561         int color = getNonGoreParticleColor(enemy->name);
562
563         for (int i = 0 ; i < amount ; i++)
564         {
565                 x = enemy->x + Math::rrand(-3, 3);
566                 y = enemy->y + Math::rrand(-3, 3);
567                 
568                 if (game.gore)
569                 {
570                         dx = Math::rrand(-5, 5);
571                         dy = Math::rrand(-15, -5);
572                         addEffect(x, y, dx, dy, EFF_BLEEDS);
573                 }
574                 else
575                 {
576                         dx = Math::rrand(-5, 5);
577                         dy = Math::rrand(-5, 5);
578                         addColoredEffect(x, y, dx, dy, color, EFF_COLORED + EFF_WEIGHTLESS);
579                 }
580         }
581         
582         (game.gore) ? audio.playSound(SND_SPLAT, CH_ANY) : audio.playSound(SND_POP, CH_ANY);
583 }
584
585 void doEnemies()
586 {
587         Entity *enemy = (Entity*)map.enemyList.getHead();
588         Entity *previous = enemy;
589         
590         map.fightingGaldov = false;
591
592         int x, y, absX, absY;
593
594         while (enemy->next != NULL)
595         {
596                 enemy = (Entity*)enemy->next;
597                 
598                 if (!engine.cheatBlood)
599                 {
600                         if (enemy->dead == DEAD_DYING)
601                         {
602                                 if (!enemy->referenced)
603                                 {
604                                         debug(("Removing unreferenced enemy '%s'\n", enemy->name));
605                                         map.enemyList.remove(previous, enemy);
606                                         enemy = previous;
607                                 }
608                                 else
609                                 {
610                                         previous = enemy;
611                                 }
612                                 
613                                 enemy->referenced = false;
614                                 continue;
615                         }
616                 }
617
618                 x = (int)(enemy->x - engine.playerPosX);
619                 y = (int)(enemy->y - engine.playerPosY);
620
621                 absX = abs(x);
622                 absY = abs(y);
623
624                 if ((absX < 800) && (absY < 600))
625                 {
626                         // Fly forever
627                         if (enemy->flags & ENT_FLIES)
628                         {
629                                 enemy->fuel = 7;
630                         }
631
632                         if (enemy->owner->flags & ENT_TELEPORTING)
633                         {
634                                 moveEntity(enemy);
635                         }
636                         else
637                         {
638                                 if ((enemy->health > 0) && (!(enemy->flags & ENT_STATIC)))
639                                 {
640                                         enemy->think();
641
642                                         if (enemy->owner == enemy)
643                                         {
644                                                 doAI(enemy);
645                                         }
646                                         else
647                                         {
648                                                 lookForPlayer(enemy);
649                                         }
650                                 }
651                                 
652                                 if (map.isBlizzardLevel)
653                                 {
654                                         enemy->dx += map.windPower * 0.1;
655                                 }
656
657                                 if (enemy->flags & ENT_NOMOVE)
658                                 {
659                                         enemy->dx = 0;
660                                 }
661
662                                 moveEntity(enemy);
663
664                                 if ((absX < 700) && (absY < 500))
665                                 {
666                                         if (enemy->flags & ENT_FIRETRAIL)
667                                         {
668                                                 addFireTrailParticle(enemy->x + (enemy->face * 16) + Math::rrand(-1, 1), enemy->y + Math::rrand(-1, 1));
669                                         }
670                                         
671                                         graphics.blit(enemy->getFaceImage(), x, y, graphics.screen, false);
672                                         
673                                         if ((enemy->dx != 0) || (enemy->flags & ENT_FLIES) || (enemy->flags & ENT_STATIC))
674                                         {
675                                                 enemy->animate();
676                                         }
677                                 }
678                         }
679                 }
680                 else
681                 {
682                         if (enemy->flags & ENT_SPAWNED)
683                         {
684                                 if ((absX > 1920) || (absY > 1440))
685                                 {
686                                         enemy->health = -100;
687                                 }
688                         }
689                 }
690
691                 if (enemy->health > 0)
692                 {
693                         previous = enemy;
694                         
695                         if ((enemy->environment == ENV_SLIME) || (enemy->environment == ENV_LAVA))
696                         {
697                                 checkObjectives(enemy->name, false);
698                                 enemy->health = -1;
699                         }
700                 }
701                 else
702                 {
703                         if (enemy->flags & ENT_GALDOV)
704                         {
705                                 enemy->health = -99;
706                         }
707
708                         if (enemy->health == 0)
709                         {
710                                 Math::removeBit(&enemy->flags, ENT_WEIGHTLESS);
711                                 Math::removeBit(&enemy->flags, ENT_SWIMS);
712                                 Math::removeBit(&enemy->flags, ENT_FLIES);
713                                 Math::addBit(&enemy->flags, ENT_INANIMATE);
714                                 Math::addBit(&enemy->flags, ENT_BOUNCES);
715                                 enemy->health = -1 - Math::prand() % 25;
716                         }
717                         
718                         if (engine.cheatBlood)
719                         {
720                                 if (!(enemy->flags & ENT_EXPLODES))
721                                 {
722                                         if ((enemy->health % 4) == 0)
723                                         {
724                                                 addBlood(enemy, Math::rrand(-2, 2), Math::rrand(-6, -3), 1);
725                                         }
726                                         else if ((enemy->health % 10) == 0)
727                                         {
728                                                 if (game.gore)
729                                                 {
730                                                         audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
731                                                 }
732                                         }
733                                 }
734                         }
735
736                         enemy->health--;
737
738                         if (enemy->flags & ENT_MULTIEXPLODE)
739                         {
740                                 if (enemy->health < -30)
741                                 {
742                                         if ((enemy->health % 3) == 0)
743                                         {
744                                                 addExplosion(enemy->x + Math::prand() % 25, enemy->y + Math::prand() % 25,  10 + (20 * game.skill), enemy);
745                                                 addSmokeAndFire(enemy, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
746                                         }
747                                 }
748                         }
749
750                         if (enemy->health > -50)
751                         {
752                                 previous = enemy;
753                         }
754                         else
755                         {
756                                 if (enemy->flags & ENT_GALDOVFINAL)
757                                 {
758                                         enemy->health = -30;
759                                         enemy->dx = Math::rrand(-10, 10);
760                                         enemy->dy = Math::rrand(-10, 10);
761                                 }
762                                 else
763                                 {
764                                         if (enemy->dead == DEAD_ALIVE)
765                                         {
766                                                 if ((absX < 800) && (absY < 600))
767                                                 {
768                                                         gibEnemy(enemy);
769                                                         
770                                                         if (enemy->value)
771                                                         {
772                                                                 dropRandomItems((int)enemy->x, (int)enemy->y);
773                                                         }
774                                                 }
775                                                 
776                                                 enemy->dead = DEAD_DYING;
777                                         }
778                                         
779                                         if (enemy->dead == DEAD_DYING)
780                                         {
781                                                 if (!enemy->referenced)
782                                                 {
783                                                         if ((absX < 800) && (absY < 600))
784                                                         {
785                                                                 gibEnemy(enemy);
786                                                                 
787                                                                 if (enemy->value)
788                                                                 {
789                                                                         dropRandomItems((int)enemy->x, (int)enemy->y);
790                                                                 }
791                                                         }
792                                                         
793                                                         debug(("Removing unreferenced enemy '%s'\n", enemy->name));
794                                                         map.enemyList.remove(previous, enemy);
795                                                         enemy = previous;
796                                                 }
797                                         }
798                                 }
799                         }
800                 }
801                 
802                 // default the enemy to not referenced.
803                 // doBullets() will change this if required.
804                 enemy->referenced = false;
805         }
806 }
807
808 void loadEnemy(const char *token)
809 {
810         int enemy = -1;
811
812         for (int i = MAX_ENEMIES ; i > -1 ; i--)
813                 if (strcmp(defEnemy[i].name, "") == 0)
814                         enemy = i;
815
816         if (enemy == -1)
817         {
818                 printf("Out of enemy define space!\n");
819                 exit(1);
820         }
821
822         char name[50], sprite[3][100], weapon[100], flags[1024];
823         int health, value;
824
825         sscanf(token, "%*c %[^\"] %*c %s %s %s %*c %[^\"] %*c %d %d %s", name, sprite[0], sprite[1], sprite[2], weapon, &health, &value, flags);
826
827         defEnemy[enemy].setName(name);
828         defEnemy[enemy].setSprites(graphics.getSprite(sprite[0], true), graphics.getSprite(sprite[1], true), graphics.getSprite(sprite[2], true));
829         defEnemy[enemy].currentWeapon = getWeaponByName(weapon);
830         defEnemy[enemy].health = health;
831         defEnemy[enemy].value = value;
832
833         defEnemy[enemy].flags = engine.getValueOfFlagTokens(flags);
834 }
835
836 void loadDefEnemies()
837 {
838         for (int i = 0 ; i < MAX_ENEMIES ; i++)
839         {
840                 strcpy(defEnemy[i].name, "");
841         }
842
843         int enemy = 0;
844
845         if (!engine.loadData("data/defEnemies"))
846         {
847                 graphics.showErrorAndExit("Couldn't load enemy definitions file (%s)", "data/defEnemies");
848         }
849
850         char *token = strtok((char*)engine.dataBuffer, "\n");
851
852         char name[50], sprite[3][100], weapon[100], flags[1024];
853         int health, value;
854
855         while (true)
856         {
857                 if (strcmp(token, "@EOF@") == 0)
858                 {
859                         break;
860                 }
861
862                 sscanf(token, "%*c %[^\"] %*c %s %s %s %*c %[^\"] %*c %d %d %s", name, sprite[0], sprite[1], sprite[2], weapon, &health, &value, flags);
863
864                 defEnemy[enemy].setName(name);
865                 defEnemy[enemy].setSprites(graphics.getSprite(sprite[0], true), graphics.getSprite(sprite[1], true), graphics.getSprite(sprite[2], true));
866                 defEnemy[enemy].currentWeapon = getWeaponByName(weapon);
867                 defEnemy[enemy].health = health;
868                 defEnemy[enemy].value = value;
869                 defEnemy[enemy].flags = engine.getValueOfFlagTokens(flags);
870
871                 enemy++;
872
873                 token = strtok(NULL, "\n");
874         }
875 }