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.
26 if (player.health < 1)
29 if (map.bossNextThink > 0)
37 switch (Math::prand() % 4)
46 r = ITEM_DOUBLECHERRY;
49 r = ITEM_TRIPLECHERRY;
56 switch (Math::prand() % 4)
72 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
74 Entity *enemy = (Entity*)map.enemyList.getHead();
81 if ((Math::prand() % 3) == 0)
83 addEnemy("Red Blob", Math::rrand(525, 800), 8100, 0);
88 addEnemy("Red Blob", Math::rrand(525, 800), 8100, 0);
92 while (enemy->next != NULL)
94 enemy = (Entity*)enemy->next;
96 if (strcmp(enemy->name, "Red Blob 1") == 0)
99 if (strcmp(enemy->name, "Red Blob 2") == 0)
105 addEnemy("Red Blob 1", 1100, 8352, 0);
106 debug(("Added Red Blob #1\n"));
111 addEnemy("Red Blob 2", 120, 8352, 0);
112 debug(("Added Red Blob #2\n"));
115 map.bossNextThink = Math::rrand(10, 15) * 60;
120 if (player.health < 1)
123 if (map.bossNextThink > 0)
129 switch (Math::prand() % 4)
132 addEnemy("Aqua Blob", 1600, 530, 0);
135 addEnemy("Aqua Blob", 1600, 690, 0);
138 addEnemy("Aqua Blob", 1600, 820, 0);
141 addEnemy("Aqua Blob", 1600, 940, 0);
145 map.bossNextThink = Math::rrand(5, 10) * 60;
147 map.bossNextThink = Math::rrand(2, 6) * 60;
150 void droidBossLevel()
152 if (player.health < 1)
155 if (map.bossNextThink > 0)
161 Entity *item = (Entity*)map.itemList.getHead();
163 bool addPistol, addMachineGun, addLaser, addSpread;
164 addPistol = addMachineGun = addLaser = addSpread = true;
166 while (item->next != NULL)
168 item = (Entity*)item->next;
170 if (item->flags & ENT_DYING)
178 case ITEM_MACHINEGUN:
179 addMachineGun = false;
191 addItem(defItem[ITEM_PISTOL].id, defItem[ITEM_PISTOL].name, 2432, 4576, defItem[ITEM_PISTOL].sprite[0]->name, 240, defItem[ITEM_PISTOL].value, 0, false);
194 addItem(defItem[ITEM_MACHINEGUN].id, defItem[ITEM_MACHINEGUN].name, 2432, 4224, defItem[ITEM_MACHINEGUN].sprite[0]->name, 240, defItem[ITEM_MACHINEGUN].value, 0, false);
197 addItem(defItem[ITEM_LASER].id, defItem[ITEM_LASER].name, 3552, 4384, defItem[ITEM_LASER].sprite[0]->name, 240, defItem[ITEM_LASER].value, 0, false);
200 addItem(defItem[ITEM_SPREAD].id, defItem[ITEM_SPREAD].name, 3552, 4800, defItem[ITEM_SPREAD].sprite[0]->name, 240, defItem[ITEM_SPREAD].value, 0, false);
202 int r = Math::prand() % 6;
204 r = Math::prand() % 4;
211 addEnemy("Eye Droid V4.0", 3648, 4704, 0);
214 addEnemy("Eye Droid V4.0", 3648, 4224, 0);
217 addEnemy("Eye Droid V4.0", 2336, 4128, 0);
220 addEnemy("Eye Droid V4.0", 2336, 4736, 0);
226 for (int i = 0 ; i < 2 ; i++)
228 r = Math::rrand(ITEM_CHERRY, ITEM_DOUBLECHERRY);
229 x = (int)player.x >> BRICKSHIFT;
230 y = (int)player.y >> BRICKSHIFT;
231 x += Math::rrand(-10, 10);
232 y += Math::rrand(-10, 10);
233 if (map.data[x][y] == MAP_AIR)
237 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
241 map.bossNextThink = Math::rrand(10, 15) * 60;
248 void galdovFinalLevel()
250 if (player.health < 1)
253 if (map.bossNextThink > 0)
259 map.bossNextThink = Math::rrand(10, 15) * 60;
261 if ((map.boss[0]->health > 30 * game.skill) || (map.boss[0]->health <= 15 * game.skill))
268 for (int i = 6 ; i < 10 ; i++)
270 if (map.boss[i] == NULL)
273 if (map.boss[i]->health <= -60)
283 int x = Math::rrand(23, 62);
284 int y = Math::rrand(42, 61);
286 if (map.data[x][y] == MAP_AIR)
290 map.boss[bossIndex]->active = true;
291 map.boss[bossIndex]->place(x, y);
292 map.boss[bossIndex]->dx = 0;
293 map.boss[bossIndex]->dy = 0;
294 map.boss[bossIndex]->health = 3 * game.skill;
295 map.boss[bossIndex]->maxHealth = 3 * game.skill;
296 Math::addBit(&map.boss[bossIndex]->flags, ENT_FLIES);
297 addTeleportParticles(map.boss[bossIndex]->x + (map.boss[bossIndex]->width / 2), map.boss[bossIndex]->y + (map.boss[bossIndex]->height / 2), 50, SND_TELEPORT2);
301 void createBoss(const char *stageName)
303 map.mainBossPart = NULL;
305 if (!map.isBossMission)
310 debug(("createBoss()\n"));
312 if (strcmp(stageName, "BioMech Supply Depot") == 0)
316 map.bossNextThink = 0;
317 map.doBossLevelAction = &tankBossLevel;
319 else if (strcmp(stageName, "BioMech Communications") == 0)
322 map.bossNextThink = 0;
323 map.doBossLevelAction = &aquaBossLevel;
325 else if (strcmp(stageName, "BioMech Assimilator") == 0)
328 map.bossNextThink = 0;
329 map.doBossLevelAction = &droidBossLevel;
331 else if (strcmp(stageName, "BioMech HQ") == 0)
334 map.bossNextThink = 0;
335 map.doBossLevelAction = &galdovLevel;
337 else if (strcmp(stageName, "Final Battle") == 0)
340 map.bossNextThink = 0;
341 map.doBossLevelAction = &galdovFinalLevel;
344 debug(("createBoss(): Done\n"));
349 int x, y, absX, absY;
353 for (int i = 0 ; i < 10 ; i++)
355 if (map.boss[i] == NULL)
362 moveEntity((Entity*)self);
364 if (self->flags & ENT_TELEPORTING)
367 x = (int)(self->x - engine.playerPosX);
368 y = (int)(self->y - engine.playerPosY);
373 if ((absX < 700) && (absY < 500))
375 if (self->flags & ENT_FIRETRAIL)
377 addFireTrailParticle(self->x + (self->face * 16) + Math::rrand(-1, 1), self->y + Math::rrand(-1, 1));
379 graphics.blit(self->getFaceImage(), x, y, graphics.screen, false);
388 if (self->health <= 0)
390 if (self->health > -100)
396 checkObjectives(self->name, false);
398 if (!self->referenced)
400 debug(("Deleting unreferenced Boss...\n"));
402 if(map.mainBossPart == map.boss[i])
403 map.mainBossPart = NULL;
407 self->referenced = false;
410 else if (self->actionFinished())
412 if (self->readyForThink())
419 map.doBossLevelAction();
422 bool isCorrectShieldFrequency(Entity *bullet)
424 if (bullet->id != self->shieldFrequency)
426 bullet->owner = self;
427 bullet->dx = -bullet->dx;
431 bullet->x += bullet->dx;
432 bullet->y += bullet->dy;
434 bullet->health += 60;
436 bullet->owner = self;
438 Math::removeBit(&bullet->flags, ENT_WEIGHTLESS);
439 Math::removeBit(&bullet->flags, ENT_BOUNCES);
441 audio.playSound(SND_RICO1, CH_ANY);
449 void checkBossBulletCollisions(Entity *bullet)
451 if ((bullet->health < 1) || (player.health <= -60))
456 if (game.missionOver > 0)
463 if (bullet->owner == &player)
465 for (int i = 0 ; i < 10 ; i++)
467 if (map.boss[i] == NULL)
474 if (Collision::collision((Entity*)self, bullet))
477 if (map.boss[i]->shieldFrequency != 999)
479 if (!isCorrectShieldFrequency(bullet))
485 if (!(self->flags & ENT_IMMUNE))
487 self->health -= bullet->damage;
488 audio.playSound(SND_CLANG, CH_ANY);
489 addColorParticles(bullet->x, bullet->y, Math::rrand(25, 75), -1);
490 Math::removeBit(&bullet->flags, ENT_SPARKS);
491 Math::removeBit(&bullet->flags, ENT_PUFFS);
494 if (self->react != NULL && self->health > 0)
499 if (bullet->id != WP_LASER)
508 void doGaldovAI(Entity *galdov)
510 map.fightingGaldov = true;
512 if (SDL_GetTicks() < map.bossNextThink)
515 map.bossNextThink = SDL_GetTicks() + Math::rrand(250, 1500);
517 switch (Math::prand() % 4)
520 if ((Math::prand() % 5) == 0)
522 if (galdov->flags & ENT_FLIES)
524 Math::removeBit(&galdov->flags, ENT_FLIES);
525 Math::removeBit(&galdov->flags, ENT_FIRETRAIL);
529 Math::addBit(&galdov->flags, ENT_FLIES);
530 Math::addBit(&galdov->flags, ENT_FIRETRAIL);
535 if (galdov->flags & ENT_JUMPS)
537 Math::removeBit(&galdov->flags, ENT_JUMPS);
541 Math::addBit(&galdov->flags, ENT_JUMPS);
545 galdov->currentWeapon = getRandomGaldovWeapon();
548 if (galdov->flags & ENT_RAPIDFIRE)
550 Math::removeBit(&galdov->flags, ENT_RAPIDFIRE);
554 Math::addBit(&galdov->flags, ENT_RAPIDFIRE);
559 if ((Math::prand() % 25) == 0)
561 switch (Math::prand() % 5)
564 engine.setInfoMessage("Galdov: Stupid creature!! Give up and join us!", 0, INFO_HINT);
567 engine.setInfoMessage("Galdov: Why do you persist in fighting us?!", 0, INFO_HINT);
570 engine.setInfoMessage("Galdov: And this is the best the Blob Army can offer?", 0, INFO_HINT);
573 engine.setInfoMessage("Galdov: We WILL have the crystals! NOTHING will stop us!!", 0, INFO_HINT);
576 engine.setInfoMessage("Galdov: You're mine now!!!", 0, INFO_HINT);