2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 // this is used exclusively by the bosses
29 if (player.health < 1)
32 if (map.bossNextThink > 0)
40 switch (Math::prand() % 4)
49 r = ITEM_DOUBLECHERRY;
52 r = ITEM_TRIPLECHERRY;
59 switch (Math::prand() % 4)
75 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
77 Entity *enemy = (Entity*)map.enemyList.getHead();
84 if ((Math::prand() % 3) == 0)
86 addEnemy("Red Blob", Math::rrand(525, 800), 8100, 0);
91 addEnemy("Red Blob", Math::rrand(525, 800), 8100, 0);
95 while (enemy->next != NULL)
97 enemy = (Entity*)enemy->next;
99 if (strcmp(enemy->name, "Red Blob 1") == 0)
102 if (strcmp(enemy->name, "Red Blob 2") == 0)
108 addEnemy("Red Blob 1", 1100, 8352, 0);
109 debug(("Added Red Blob #1\n"));
114 addEnemy("Red Blob 2", 120, 8352, 0);
115 debug(("Added Red Blob #2\n"));
118 map.bossNextThink = Math::rrand(10, 15) * 60;
123 if (player.health < 1)
126 if (map.bossNextThink > 0)
132 switch (Math::prand() % 4)
135 addEnemy("Aqua Blob", 1600, 530, 0);
138 addEnemy("Aqua Blob", 1600, 690, 0);
141 addEnemy("Aqua Blob", 1600, 820, 0);
144 addEnemy("Aqua Blob", 1600, 940, 0);
148 map.bossNextThink = Math::rrand(5, 10) * 60;
150 map.bossNextThink = Math::rrand(2, 6) * 60;
153 void droidBossLevel()
155 if (player.health < 1)
158 if (map.bossNextThink > 0)
164 Entity *item = (Entity*)map.itemList.getHead();
166 bool addPistol, addMachineGun, addLaser, addSpread;
167 addPistol = addMachineGun = addLaser = addSpread = true;
169 while (item->next != NULL)
171 item = (Entity*)item->next;
173 if (item->flags & ENT_DYING)
181 case ITEM_MACHINEGUN:
182 addMachineGun = false;
194 addItem(defItem[ITEM_PISTOL].id, defItem[ITEM_PISTOL].name, 2432, 4576, defItem[ITEM_PISTOL].sprite[0]->name, 240, defItem[ITEM_PISTOL].value, 0, false);
197 addItem(defItem[ITEM_MACHINEGUN].id, defItem[ITEM_MACHINEGUN].name, 2432, 4224, defItem[ITEM_MACHINEGUN].sprite[0]->name, 240, defItem[ITEM_MACHINEGUN].value, 0, false);
200 addItem(defItem[ITEM_LASER].id, defItem[ITEM_LASER].name, 3552, 4384, defItem[ITEM_LASER].sprite[0]->name, 240, defItem[ITEM_LASER].value, 0, false);
203 addItem(defItem[ITEM_SPREAD].id, defItem[ITEM_SPREAD].name, 3552, 4800, defItem[ITEM_SPREAD].sprite[0]->name, 240, defItem[ITEM_SPREAD].value, 0, false);
205 int r = Math::prand() % 6;
207 r = Math::prand() % 4;
214 addEnemy("Eye Droid V4.0", 3648, 4704, 0);
217 addEnemy("Eye Droid V4.0", 3648, 4224, 0);
220 addEnemy("Eye Droid V4.0", 2336, 4128, 0);
223 addEnemy("Eye Droid V4.0", 2336, 4736, 0);
229 for (int i = 0 ; i < 2 ; i++)
231 r = Math::rrand(ITEM_CHERRY, ITEM_DOUBLECHERRY);
232 x = (int)player.x >> BRICKSHIFT;
233 y = (int)player.y >> BRICKSHIFT;
234 x += Math::rrand(-10, 10);
235 y += Math::rrand(-10, 10);
236 if (map.data[x][y] == MAP_AIR)
240 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
244 map.bossNextThink = Math::rrand(10, 15) * 60;
251 void galdovFinalLevel()
253 if (player.health < 1)
256 if (map.bossNextThink > 0)
262 map.bossNextThink = Math::rrand(10, 15) * 60;
264 if ((map.boss[0]->health > 30 * game.skill) || (map.boss[0]->health <= 15 * game.skill))
271 for (int i = 6 ; i < 10 ; i++)
273 if (map.boss[i] == NULL)
276 if (map.boss[i]->health <= -60)
286 int x = Math::rrand(23, 62);
287 int y = Math::rrand(42, 61);
289 if (map.data[x][y] == MAP_AIR)
293 map.boss[bossIndex]->active = true;
294 map.boss[bossIndex]->place(x, y);
295 map.boss[bossIndex]->dx = 0;
296 map.boss[bossIndex]->dy = 0;
297 map.boss[bossIndex]->health = 3 * game.skill;
298 map.boss[bossIndex]->maxHealth = 3 * game.skill;
299 Math::addBit(&map.boss[bossIndex]->flags, ENT_FLIES);
300 addTeleportParticles(map.boss[bossIndex]->x + (map.boss[bossIndex]->width / 2), map.boss[bossIndex]->y + (map.boss[bossIndex]->height / 2), 50, SND_TELEPORT2);
304 void createBoss(const char *stageName)
306 map.mainBossPart = NULL;
308 if (!map.isBossMission)
313 debug(("createBoss()\n"));
315 if (strcmp(stageName, "BioMech Supply Depot") == 0)
319 map.bossNextThink = 0;
320 map.doBossLevelAction = &tankBossLevel;
322 else if (strcmp(stageName, "BioMech Communications") == 0)
325 map.bossNextThink = 0;
326 map.doBossLevelAction = &aquaBossLevel;
328 else if (strcmp(stageName, "BioMech Assimilator") == 0)
331 map.bossNextThink = 0;
332 map.doBossLevelAction = &droidBossLevel;
334 else if (strcmp(stageName, "BioMech HQ") == 0)
337 map.bossNextThink = 0;
338 map.doBossLevelAction = &galdovLevel;
340 else if (strcmp(stageName, "Final Battle") == 0)
343 map.bossNextThink = 0;
344 map.doBossLevelAction = &galdovFinalLevel;
347 debug(("createBoss(): Done\n"));
352 int x, y, absX, absY;
356 for (int i = 0 ; i < 10 ; i++)
358 if (map.boss[i] == NULL)
365 moveEntity((Entity*)self);
367 if (self->flags & ENT_TELEPORTING)
370 x = (int)(self->x - engine.playerPosX);
371 y = (int)(self->y - engine.playerPosY);
376 if ((absX < 700) && (absY < 500))
378 if (self->flags & ENT_FIRETRAIL)
380 addFireTrailParticle(self->x + (self->face * 16) + Math::rrand(-1, 1), self->y + Math::rrand(-1, 1));
382 graphics.blit(self->getFaceImage(), x, y, graphics.screen, false);
391 if (self->health <= 0)
393 if (self->health > -100)
399 checkObjectives(self->name, false);
401 if (!self->referenced)
403 debug(("Deleting unreferenced Boss...\n"));
405 if(map.mainBossPart == map.boss[i])
406 map.mainBossPart = NULL;
410 self->referenced = false;
413 else if (self->actionFinished())
415 if (self->readyForThink())
422 map.doBossLevelAction();
425 bool isCorrectShieldFrequency(Entity *bullet)
427 if (bullet->id != self->shieldFrequency)
429 bullet->owner = self;
430 bullet->dx = -bullet->dx;
434 bullet->x += bullet->dx;
435 bullet->y += bullet->dy;
437 bullet->health += 60;
439 bullet->owner = self;
441 Math::removeBit(&bullet->flags, ENT_WEIGHTLESS);
442 Math::removeBit(&bullet->flags, ENT_BOUNCES);
444 audio.playSound(SND_RICO1, CH_ANY, bullet->x);
452 void checkBossBulletCollisions(Entity *bullet)
454 if ((bullet->health < 1) || (player.health <= -60))
459 if (game.missionOver > 0)
466 if (bullet->owner == &player)
468 for (int i = 0 ; i < 10 ; i++)
470 if (map.boss[i] == NULL)
477 if (Collision::collision((Entity*)self, bullet))
480 if (map.boss[i]->shieldFrequency != 999)
482 if (!isCorrectShieldFrequency(bullet))
488 if (!(self->flags & ENT_IMMUNE))
490 self->health -= bullet->damage;
491 audio.playSound(SND_CLANG, CH_ANY, bullet->x);
492 addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
493 Math::removeBit(&bullet->flags, ENT_SPARKS);
494 Math::removeBit(&bullet->flags, ENT_PUFFS);
497 if (self->react != NULL && self->health > 0)
502 if (bullet->id != WP_LASER)
511 void doGaldovAI(Entity *galdov)
513 map.fightingGaldov = true;
515 if (SDL_GetTicks() < map.bossNextThink)
518 map.bossNextThink = SDL_GetTicks() + Math::rrand(250, 1500);
520 switch (Math::prand() % 4)
523 if ((Math::prand() % 5) == 0)
525 if (galdov->flags & ENT_FLIES)
527 Math::removeBit(&galdov->flags, ENT_FLIES);
528 Math::removeBit(&galdov->flags, ENT_FIRETRAIL);
532 Math::addBit(&galdov->flags, ENT_FLIES);
533 Math::addBit(&galdov->flags, ENT_FIRETRAIL);
538 if (galdov->flags & ENT_JUMPS)
540 Math::removeBit(&galdov->flags, ENT_JUMPS);
544 Math::addBit(&galdov->flags, ENT_JUMPS);
548 galdov->currentWeapon = getRandomGaldovWeapon();
551 if (galdov->flags & ENT_RAPIDFIRE)
553 Math::removeBit(&galdov->flags, ENT_RAPIDFIRE);
557 Math::addBit(&galdov->flags, ENT_RAPIDFIRE);
562 if ((Math::prand() % 25) == 0)
564 switch (Math::prand() % 5)
567 engine.setInfoMessage("Galdov: Stupid creature!! Give up and join us!", 0, INFO_HINT);
570 engine.setInfoMessage("Galdov: Why do you persist in fighting us?!", 0, INFO_HINT);
573 engine.setInfoMessage("Galdov: And this is the best the Blob Army can offer?", 0, INFO_HINT);
576 engine.setInfoMessage("Galdov: We WILL have the crystals! NOTHING will stop us!!", 0, INFO_HINT);
579 engine.setInfoMessage("Galdov: You're mine now!!!", 0, INFO_HINT);