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.
25 void galdovCheckSplit();
29 (self->x < player.x) ? self->face = 0 : self->face = 1;
36 switch (Math::prand() % 5)
42 color = graphics.yellow;
45 color = graphics.green;
48 color = graphics.cyan;
51 color = graphics.white;
55 for (int i = 0 ; i < 20 ; i++)
57 dy = Math::rrand(-150, -50);
59 map.addParticle(self->x + (Math::prand() % self->width), self->y + (Math::prand() % self->height), dx, dy, Math::rrand(1, 60), color, NULL, PAR_WEIGHTLESS);
62 self->setThinkTime(1);
63 self->setActionFinished(1);
64 self->think = &splitParticles;
67 if (self->custom == 0)
69 self->setThinkTime(2);
70 self->setActionFinished(2);
71 self->think = &galdovAttack;
73 if (self == map.boss[0])
75 if ((Math::prand() % self->health) == 0)
77 self->think = &galdovCheckSplit;
86 self->setThinkTime(2);
87 self->setActionFinished(2);
89 int x = (int)player.x >> BRICKSHIFT;
90 int y = (int)player.y >> BRICKSHIFT;
91 x += Math::rrand(-10, 10);
92 y += Math::rrand(-10, 10);
94 Math::limitInt(&x, 1, 28);
95 Math::limitInt(&y, 259, 283);
97 if (map.data[x][y] == MAP_AIR)
103 addTeleportParticles(self->x + 10, self->y + 10, 50, SND_TELEPORT2);
104 self->think = &galdovAttack;
110 if (self->health < 0)
113 int r = Math::prand() % 10;
117 self->setThinkTime(2);
118 self->setActionFinished(2);
119 self->think = &galdovTeleport;
121 r = Math::prand() % 3;
125 self->setThinkTime(2);
126 self->setActionFinished(2);
127 self->think = &galdovCheckSplit;
132 void galdovSplit(int i)
134 audio.playSound(SND_BOSSCUSTOM1, CH_AMBIANCE, map.boss[0]->x);
136 map.boss[i]->active = true;
137 map.boss[i]->health = 4 * game.skill;
138 map.boss[i]->maxHealth = 4 * game.skill;
139 map.boss[i]->x = map.boss[0]->x;
140 map.boss[i]->y = map.boss[0]->y;
141 map.boss[i]->flags = map.boss[0]->flags;
142 map.boss[i]->think = &galdovAttack;
144 if ((Math::prand() % 2) == 0)
146 map.boss[i]->currentWeapon = getRandomAimedWeapon();
147 Math::addBit(&map.boss[i]->flags, ENT_AIMS);
151 map.boss[i]->currentWeapon = getRandomStraightWeapon();
152 Math::removeBit(&map.boss[i]->flags, ENT_AIMS);
155 if ((Math::prand() % 2) == 0)
157 map.boss[0]->dx = -.5;
159 map.boss[i]->dx = .5;
164 map.boss[0]->dx = .5;
166 map.boss[i]->dx = -.5;
170 map.boss[0]->think = &splitParticles;
171 map.boss[0]->setThinkTime(1);
172 map.boss[0]->setActionFinished(1);
173 map.boss[0]->custom = 60;
175 map.boss[i]->think = &splitParticles;
176 map.boss[i]->setThinkTime(1);
177 map.boss[i]->setActionFinished(1);
178 map.boss[i]->custom = 60;
181 void galdovCheckSplit()
183 for (int i = 1 ; i < 10 ; i++)
185 if (!map.boss[i]->active)
195 (self->x < player.x) ? self->face = 0 : self->face = 1;
197 self->setActionFinished(9);
198 self->setThinkTime(2);
199 self->think = &galdovFire;
201 if (hasClearShot(self))
203 self->flags & ENT_AIMS ? addBullet((Entity*)self, 0, 0) : addBullet((Entity*)self, self->currentWeapon->getSpeed(self->face), 0);
205 if (self->currentWeapon == &weapon[WP_ALIENSPREAD])
207 addBullet(self, self->currentWeapon->getSpeed(self->face), 2);
208 addBullet(self, self->currentWeapon->getSpeed(self->face), -2);
213 if (self->custom == 0)
215 self->think = &galdovAttack;
219 void galdovRocketAttack()
221 (self->x < player.x) ? self->face = 0 : self->face = 1;
223 if (!hasClearShot(self))
226 self->setActionFinished(5);
227 self->setThinkTime(2);
228 self->think = &galdovRocketAttack;
230 addBullet((Entity*)self, 0, 0);
234 if (self->custom == 0)
236 self->think = &galdovAttack;
237 self->currentWeapon = getRandomGaldovWeapon();
241 void galdovChasePlayer()
243 (self->x < player.x) ? self->face = 0 : self->face = 1;
247 Math::calculateSlope(player.x, player.y, self->x, self->y, &dx, &dy);
252 self->setThinkTime(10);
253 self->setActionFinished(10);
254 self->think = &galdovAttack;
257 void galdovMoveRandom()
259 self->think = &galdovAttack;
261 if (self->flags & ENT_FLIES)
263 self->dx = Math::rrand(-200, 200);
264 self->dy = Math::rrand(-200, 200);
269 self->setThinkTime(2);
270 self->setActionFinished(Math::rrand(60, 90));
274 self->dy = Math::rrand(-12, 0);
276 (player.x < self->x) ? self->dx = -3 : self->dx = 3;
278 self->think = &galdovAttack;
279 self->setActionFinished(45);
283 void galdovDoInvisible()
285 if ((Math::prand() % 2) == 0)
287 map.boss[0]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
291 map.boss[0]->setSprites(graphics.getSprite("GaldovInvsRight", true), graphics.getSprite("GaldovInvsLeft", true), graphics.getSprite("GaldovInvsLeft", true));
294 self->setThinkTime(2);
295 self->setActionFinished(2);
296 self->think = &galdovAttack;
301 if (player.health < 1)
303 self->dx = self->dy = 0;
307 (self->x < player.x) ? self->face = 0 : self->face = 1;
309 self->think = &galdovAttack;
310 self->setThinkTime(2);
311 self->setActionFinished(2);
313 int r = Math::prand() % 100;
317 self->think = &galdovFire;
318 self->custom = Math::rrand(1, 8);
322 // Make sure only the real Galdov does this!
323 if (self == map.boss[0])
325 addTeleportParticles(self->x + 10, self->y + 10, 50, SND_TELEPORT2);
328 self->setActionFinished(120);
329 self->setThinkTime(2);
330 self->think = &galdovTeleport;
335 self->think = &galdovChasePlayer;
339 self->think = &galdovMoveRandom;
343 if ((self->flags & ENT_FLIES) && (Math::prand() % 5) == 0)
345 Math::removeBit(&self->flags, ENT_FLIES);
346 Math::removeBit(&self->flags, ENT_FIRETRAIL);
350 Math::addBit(&self->flags, ENT_FLIES);
351 Math::addBit(&self->flags, ENT_FIRETRAIL);
356 if (self == map.boss[0])
358 self->think = &galdovDoInvisible;
363 map.boss[0]->currentWeapon = getRandomGaldovWeapon();
367 // Make sure only the real Galdov does this!
368 if (self == map.boss[0])
370 self->custom = Math::rrand(4, 8);
371 self->currentWeapon = &weapon[WP_ROCKETS];
372 self->think = &galdovRocketAttack;
377 // Make sure only the real Galdov does this!
378 if (self == map.boss[0])
380 self->think = &galdovCheckSplit;
389 if (map.mainBossPart != NULL)
391 map.mainBossPart = NULL;
392 audio.playSound(SND_BOSSCUSTOM2, CH_AMBIANCE, self->x);
395 if ((self->health % 5) == 0)
397 self->setActionFinished(5);
398 self->setThinkTime(2);
400 self->dx = Math::rrand(-5, 5);
401 self->dy = Math::rrand(-5, 5);
403 addExplosion(self->x, self->y, 5, &player);
404 addSmokeAndFire(self, Math::rrand(-4, 4), Math::rrand(-4, 4), 2);
407 for (int i = 1 ; i < 10 ; i++)
409 if (map.boss[i]->health > -1)
411 map.boss[i]->health = -1;
415 if (self->health <= -100)
417 checkObjectives(self->name, false);
418 map.mainBossPart = NULL;
419 addTeleportParticles(self->x, self->y, 75, SND_TELEPORT3);
423 void dropItems(int x, int y)
427 for (int i = 0 ; i < 2 ; i++)
429 r = Math::rrand(ITEM_PISTOL, ITEM_DOUBLECHERRY);
431 // Grenades make this battle far too easy(!)
432 if (r == ITEM_GRENADES)
435 if ((Math::prand() % 10) == 0)
436 r = ITEM_TRIPLECHERRY;
438 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
444 dropItems((int)self->x, (int)self->y);
446 addExplosion(self->x, self->y, 50, self);
447 self->setThinkTime(2);
448 self->setActionFinished(2);
449 self->active = false;
457 debug(("galdovInit\n"));
459 map.boss[0] = new Boss();
460 strlcpy(map.boss[0]->name, "Galdov", sizeof map.boss[0]->name);
461 map.boss[0]->health = 45 * game.skill;
462 map.boss[0]->maxHealth = 45 * game.skill;
463 map.boss[0]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
464 map.boss[0]->currentWeapon = &weapon[WP_AIMEDPISTOL];
465 map.boss[0]->face = 0;
466 map.boss[0]->active = true;
467 map.boss[0]->x = 448;
468 map.boss[0]->y = 9024;
469 map.boss[0]->immune = 0;
470 map.boss[0]->setThinkTime(2);
471 map.boss[0]->setActionFinished(2);
472 map.boss[0]->think = &galdovCheckSplit;
473 map.boss[0]->react = &galdovReact;
474 map.boss[0]->die = &galdovDie;
476 Math::addBit(&map.boss[0]->flags, ENT_AIMS);
478 SDL_SetAlpha(graphics.getSprite("GaldovInvsLeft", true)->image[0], 100);
479 SDL_SetAlpha(graphics.getSprite("GaldovInvsRight", true)->image[0], 100);
481 for (int i = 1 ; i < 10 ; i++)
483 map.boss[i] = new Boss();
484 strlcpy(map.boss[i]->name, "Fake", sizeof map.boss[i]->name);
485 map.boss[i]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
486 map.boss[i]->x = 9999;
487 map.boss[i]->y = 9999;
488 map.boss[i]->active = false;
489 map.boss[i]->think = &galdovAttack;
490 map.boss[i]->react = NULL;
491 map.boss[i]->die = &fakeDie;
494 map.setMainBossPart(map.boss[0]);
496 audio.loadSound(SND_BOSSCUSTOM1, "sound/galdovSplit");
497 audio.loadSound(SND_BOSSCUSTOM2, "sound/galdovPain");
499 debug(("galdovInit: Done\n"));