2 Copyright © 2004 Parallel Realities
3 Copyright © 2007-2008 Kővágó Zoltán <DirtY.iCE.hu@gmail.com>
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.
27 #include "CGraphics.h"
30 #include "CObjective.h"
31 #include "console/console.hpp"
32 #include "finalBattle.h"
34 void galdovMiniAttack();
35 void galdovFinalFlee1();
36 void blackDroidAttack();
38 // ************************ Black Droids for Part 2 *************************************
42 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
44 if (!hasClearShot(self
))
47 self
->setActionFinished(9);
48 self
->setThinkTime(2);
49 self
->think
= &blackDroidFire
;
51 addBullet((Entity
*)self
, 0, 0);
54 if (self
->custom
== 0)
56 self
->think
= &blackDroidAttack
;
63 Math::removeBit(&self
->flags
, ENT_FLIES
);
65 if (self
->health
< -10)
67 if ((self
->health
% 3) == 0)
69 addExplosion(self
->x
, self
->y
, 35, self
);
70 addSmokeAndFire(self
, Math::rrand(-15, 15), Math::rrand(-15, 15), 2);
74 if (self
->health
<= -60)
76 if ((rand() % 2) == 0)
78 dropItems((int)self
->x
, (int)self
->y
);
79 dropItems((int)self
->x
, (int)self
->y
);
83 addItem(100, "Red Keycard", (int)self
->x
, (int)self
->y
, "RedKeyCard", 240, 1, ENT_DYING
, true);
86 self
->place(9999, 9999);
90 void blackDroidChasePlayer()
92 self
->think
= &blackDroidAttack
;
94 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
98 Math::calculateSlope(player
.x
, player
.y
, self
->x
, self
->y
, &dx
, &dy
);
103 self
->setThinkTime(10);
104 self
->setActionFinished(10);
107 void blackDroidMoveRandom()
109 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
111 self
->think
= &blackDroidAttack
;
113 self
->dx
= Math::rrand(-200, 200);
114 self
->dy
= Math::rrand(-200, 200);
119 self
->setThinkTime(2);
120 self
->setActionFinished(Math::rrand(60, 90));
123 void blackDroidAttack()
125 self
->think
= blackDroidAttack
;
126 self
->setThinkTime(2);
127 self
->setActionFinished(2);
133 self
->think
= &blackDroidFire
;
134 self
->setThinkTime(2);
135 self
->setActionFinished(2);
136 self
->custom
= Math::rrand(2, 4) * game
.skill
;
140 self
->think
= &blackDroidChasePlayer
;
141 self
->setThinkTime(2);
142 self
->setActionFinished(2);
146 self
->think
= &blackDroidMoveRandom
;
147 self
->setThinkTime(2);
148 self
->setActionFinished(2);
152 void galdovInitBlackDroids()
154 for (int i
= 6 ; i
< 10 ; i
++)
156 if (map
.boss
[i
] == NULL
)
158 map
.boss
[i
] = new Boss();
160 debug("boss", 2) << "BlackDroid " << i
<< " init" << std::endl
;
161 strcpy(map
.boss
[i
]->name
, "BlackDrod");
162 map
.boss
[i
]->health
= -90;
163 map
.boss
[i
]->maxHealth
= -90;
164 map
.boss
[i
]->setSprites(graphics
.getSprite("BlackDroidRight", true), graphics
.getSprite("BlackDroidLeft", true), graphics
.getSprite("BlackDroidDie", true));
165 map
.boss
[i
]->currentWeapon
= &weapon
[WP_PLASMARIFLE
];
166 map
.boss
[i
]->face
= 0;
167 map
.boss
[i
]->active
= false;
168 map
.boss
[i
]->place(9999, 9999);
169 map
.boss
[i
]->immune
= 0;
170 map
.boss
[i
]->setThinkTime(2);
171 map
.boss
[i
]->think
= &blackDroidAttack
;
172 map
.boss
[i
]->react
= NULL
;
173 map
.boss
[i
]->die
= &blackDroidDie
;
174 map
.boss
[i
]->setActionFinished(120);
175 Math::addBit(&map
.boss
[i
]->flags
, ENT_FLIES
);
176 Math::addBit(&map
.boss
[i
]->flags
, ENT_AIMS
);
177 Math::removeBit(&map
.boss
[i
]->flags
, ENT_FIRETRAIL
);
181 // ************************ First part of final battle **********************************
183 void galdovFinalKeepAlive1()
185 map
.boss
[0]->health
= 30 * game
.skill
;
188 void galdovFinalPainThrow()
193 self
->think
= &galdovFinalFlee1
;
194 self
->setThinkTime(2);
195 self
->setActionFinished(140);
198 void galdovFinalDropCrystal()
200 self
->setThinkTime(2);
201 self
->setActionFinished(2);
203 int x
= (int)player
.x
>> BRICKSHIFT
;
204 int y
= (int)player
.y
>> BRICKSHIFT
;
205 x
+= Math::rrand(-2, 2);
206 y
+= Math::rrand(-2, 2);
208 Math::limitInt(&x
, 2, 62);
209 Math::limitInt(&y
, 2, 26);
211 if (map
.data
[x
][y
] == MAP_AIR
)
217 addTeleportParticles(self
->x
+ 10, self
->y
+ 10, 50, SND_TELEPORT2
);
218 addItem(101, "Reality Crystal", (int)self
->x
, (int)self
->y
, "RealityCrystal", 100, 1, 0, true);
219 self
->think
= &galdovFinalPainThrow
;
220 self
->react
= &galdovFinalKeepAlive1
;
221 Math::removeBit(&self
->flags
, ENT_FLIES
);
222 Math::removeBit(&self
->flags
, ENT_FIRETRAIL
);
223 map
.setMainBossPart(NULL
);
224 map
.boss
[0]->health
= 30 * game
.skill
;
225 map
.boss
[0]->setSprites(graphics
.getSprite("GaldovPain", true), graphics
.getSprite("GaldovPain", true), graphics
.getSprite("GaldovPain", true));
226 engine
.setInfoMessage("Galdov has dropped the crystal! Quick! Get it!!", 99, INFO_HINT
);
227 audio
.playSound(SND_BOSSCUSTOM2
, CH_AMBIANCE
);
231 void galdovFinalDie()
233 if (game
.missionOverReason
== MIS_INPROGRESS
)
235 game
.missionOverReason
= MIS_GAMECOMPLETE
;
237 audio
.playSound(SND_BOSSCUSTOM3
, CH_AMBIANCE
);
242 Math::removeBit(&self
->flags
, ENT_FLIES
);
243 Math::removeBit(&self
->flags
, ENT_FIRETRAIL
);
246 self
->setActionFinished(1);
247 self
->setThinkTime(1);
251 if (self
->health
> -35)
254 if (self
->health
== -99)
256 checkObjectives(self
->name
, false);
259 Math::wrapInt(&self
->health
, -99, -41);
261 if ((self
->health
% 3) == 0)
263 self
->setActionFinished(5);
264 self
->setThinkTime(2);
266 self
->dx
= Math::rrand(-5, 5);
267 self
->dy
= Math::rrand(-5, 5);
269 addExplosion(self
->x
, self
->y
, 50, &player
);
270 addSmokeAndFire(self
, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
274 void galdovMiniFire()
276 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
278 if (!hasClearShot(self
))
281 self
->setActionFinished(9);
282 self
->setThinkTime(2);
283 self
->think
= &galdovMiniFire
;
285 addBullet((Entity
*)self
, 0, 0);
288 if (self
->custom
== 0)
290 self
->think
= &galdovMiniAttack
;
294 void galdovFinalTeleport()
296 self
->setThinkTime(2);
297 self
->setActionFinished(2);
299 int x
= (int)player
.x
>> BRICKSHIFT
;
300 int y
= (int)player
.y
>> BRICKSHIFT
;
301 x
+= Math::rrand(-10, 10);
302 y
+= Math::rrand(-10, 10);
304 Math::limitInt(&x
, 2, 62);
305 Math::limitInt(&y
, 2, 26);
307 if (self
== map
.boss
[0])
309 if (self
->health
< 45 * game
.skill
)
311 Math::limitInt(&x
, 23, 62);
312 Math::limitInt(&y
, 42, 61);
313 self
->currentWeapon
= getRandomGaldovWeapon();
317 if (map
.data
[x
][y
] == MAP_AIR
)
323 addTeleportParticles(self
->x
+ 10, self
->y
+ 10, 50, SND_TELEPORT2
);
324 self
->think
= &galdovMiniAttack
;
328 void galdovMiniChasePlayer()
330 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
334 Math::calculateSlope(player
.x
, player
.y
, self
->x
, self
->y
, &dx
, &dy
);
339 self
->setThinkTime(10);
340 self
->setActionFinished(10);
341 self
->think
= &galdovMiniAttack
;
344 void galdovMiniMoveRandom()
346 self
->think
= &galdovMiniAttack
;
348 if (self
->flags
& ENT_FLIES
)
350 self
->dx
= Math::rrand(-200, 200);
351 self
->dy
= Math::rrand(-200, 200);
356 self
->setThinkTime(2);
357 self
->setActionFinished(Math::rrand(60, 90));
361 self
->dy
= Math::rrand(-12, 0);
363 (player
.x
< self
->x
) ? self
->dx
= -3 : self
->dx
= 3;
365 self
->think
= &galdovMiniAttack
;
366 self
->setActionFinished(45);
370 void galdovMiniAttack()
372 if (player
.health
< 1)
374 self
->dx
= self
->dy
= 0;
378 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
380 self
->think
= &galdovMiniAttack
;
381 self
->setThinkTime(2);
382 self
->setActionFinished(2);
384 int r
= rand() % 100;
388 self
->think
= &galdovMiniFire
;
389 self
->custom
= Math::rrand(1, 8);
393 addTeleportParticles(self
->x
+ 10, self
->y
+ 10, 50, SND_TELEPORT2
);
396 self
->setActionFinished(120);
397 self
->setThinkTime(2);
398 self
->think
= &galdovFinalTeleport
;
402 self
->think
= &galdovMiniChasePlayer
;
406 self
->think
= &galdovMiniMoveRandom
;
410 if ((self
->flags
& ENT_FLIES
) && (rand() % 5) == 0)
412 Math::removeBit(&self
->flags
, ENT_FLIES
);
413 Math::removeBit(&self
->flags
, ENT_FIRETRAIL
);
417 Math::addBit(&self
->flags
, ENT_FLIES
);
418 Math::addBit(&self
->flags
, ENT_FIRETRAIL
);
425 addExplosion(self
->x
, self
->y
, 5, self
);
426 dropItems((int)self
->x
, (int)self
->y
);
427 self
->setThinkTime(2);
428 self
->setActionFinished(2);
429 self
->active
= false;
430 self
->place(9999, 9999);
432 // Don't kill it properly(!!)
437 for (int i
= 1 ; i
< 10 ; i
++)
439 if (map
.boss
[i
]->health
> 0)
447 map
.boss
[0]->think
= &galdovFinalDropCrystal
;
448 map
.boss
[0]->setThinkTime(2);
449 map
.boss
[0]->setActionFinished(2);
455 debug("boss", 2) << "galdovRejoin" << std::endl
;
457 for (int i
= 1 ; i
< 10 ; i
++)
459 if (map
.boss
[i
] != NULL
)
461 addTeleportParticles(map
.boss
[i
]->x
+ 4, map
.boss
[i
]->y
+ 4, 75, -1);
463 if ((rand() % (2 + (game
.skill
))) == 0)
465 dropItems((int)map
.boss
[i
]->x
, (int)map
.boss
[i
]->y
);
468 map
.boss
[i
]->place(9999, 9999);
469 map
.boss
[i
]->active
= false;
473 self
->setThinkTime(2);
474 self
->setActionFinished(120);
475 self
->think
= &galdovFinalTeleport
;
476 self
->currentWeapon
= getRandomGaldovWeapon();
478 audio
.playSound(SND_BOSSCUSTOM1
, CH_AMBIANCE
);
480 map
.setMainBossPart(map
.boss
[0]);
482 debug("boss", 2) << "galdovRejoin: Done" << std::endl
;
485 void galdovFinalMiniReact()
487 if (self
->health
> 0)
489 map
.setMainBossPart(self
);
493 map
.setMainBossPart(NULL
);
497 void galdovFinalSplit()
499 debug("boss", 2) << "galdovFinalSplit" << std::endl
;
501 for (int i
= 1 ; i
< 10 ; i
++)
503 if (map
.boss
[i
] == NULL
)
505 map
.boss
[i
] = new Boss();
506 strcpy(map
.boss
[i
]->name
, "MiniGaldov");
507 map
.boss
[i
]->health
= 10 * game
.skill
;
508 map
.boss
[i
]->maxHealth
= 10 * game
.skill
;
510 map
.boss
[i
]->setSprites(graphics
.getSprite("GaldovMiniRight", true), graphics
.getSprite("GaldovMiniLeft", true), graphics
.getSprite("GaldovMiniLeft", true));
511 map
.boss
[i
]->currentWeapon
= getRandomAimedWeapon();
512 map
.boss
[i
]->face
= 0;
513 map
.boss
[i
]->active
= true;
515 if (map
.boss
[i
]->health
> 0)
517 map
.boss
[i
]->dx
= Math::rrand(-2, 2);
518 map
.boss
[i
]->dy
= Math::rrand(-2, 2);
519 map
.boss
[i
]->x
= map
.boss
[0]->x
;
520 map
.boss
[i
]->y
= map
.boss
[0]->y
;
524 map
.boss
[i
]->active
= false;
527 map
.boss
[i
]->immune
= 0;
528 map
.boss
[i
]->setThinkTime(2);
529 map
.boss
[i
]->setActionFinished(120);
530 map
.boss
[i
]->think
= &galdovMiniAttack
;
531 map
.boss
[i
]->react
= &galdovFinalMiniReact
;
532 map
.boss
[i
]->die
= &galdovMiniDie
;
533 Math::addBit(&map
.boss
[i
]->flags
, ENT_AIMS
);
534 Math::addBit(&map
.boss
[i
]->flags
, ENT_FLIES
);
535 Math::addBit(&map
.boss
[i
]->flags
, ENT_FIRETRAIL
);
537 addTeleportParticles(map
.boss
[i
]->x
+ 10 + map
.boss
[i
]->dx
, map
.boss
[i
]->y
+ 10 + map
.boss
[i
]->dy
, 75, -1);
540 map
.boss
[0]->place(9999, 9999);
541 map
.boss
[0]->setThinkTime(2);
542 map
.boss
[0]->setActionFinished(Math::rrand(10, 15) * 60);
543 map
.boss
[0]->think
= &galdovRejoin
;
544 map
.boss
[0]->active
= true;
546 audio
.playSound(SND_BOSSCUSTOM1
, CH_AMBIANCE
);
547 map
.setMainBossPart(NULL
);
549 debug("boss", 2) << "galdovFinalSplit: Done" << std::endl
;
552 void galdovFinalReact()
554 map
.boss
[0]->health
= 45 * game
.skill
;
556 if ((rand() % 5) == 0)
558 map
.boss
[0]->setThinkTime(2);
559 map
.boss
[0]->setActionFinished(2);
560 map
.boss
[0]->think
= &galdovFinalSplit
;
564 void galdovFinalInit()
566 debug("boss", 2) << "galdovFinalInit" << std::endl
;
568 map
.boss
[0] = new Boss();
569 strcpy(map
.boss
[0]->name
, "Galdov");
570 map
.boss
[0]->health
= 45 * game
.skill
;
571 map
.boss
[0]->maxHealth
= 45 * game
.skill
;
572 map
.boss
[0]->setSprites(graphics
.getSprite("GaldovRight", true), graphics
.getSprite("GaldovLeft", true), graphics
.getSprite("GaldovDie", true));
573 map
.boss
[0]->currentWeapon
= &weapon
[WP_AIMEDPISTOL
];
574 map
.boss
[0]->face
= 0;
575 map
.boss
[0]->active
= true;
576 map
.boss
[0]->x
= 480;
577 map
.boss
[0]->y
= 576;
578 map
.boss
[0]->immune
= 0;
579 map
.boss
[0]->setThinkTime(2);
580 map
.boss
[0]->setActionFinished(2);
581 map
.boss
[0]->think
= &galdovMiniAttack
;
582 //map.boss[0]->think = &galdovFinalDropCrystal;
583 map
.boss
[0]->react
= &galdovFinalReact
;
584 map
.boss
[0]->die
= &galdovFinalDie
;
585 Math::addBit(&map
.boss
[0]->flags
, ENT_AIMS
);
587 audio
.loadSound(SND_BOSSCUSTOM1
, "sound/galdovSplit.wav");
588 audio
.loadSound(SND_BOSSCUSTOM2
, "sound/galdovPain.wav");
589 audio
.loadSound(SND_BOSSCUSTOM3
, "sound/galdovDie.wav");
591 map
.setMainBossPart(map
.boss
[0]);
593 debug("boss", 2) << "galdovFinalInit: Done" << std::endl
;
596 // ******************** Second part of Final Battle *********************************
598 void galdovFinalReact2()
600 if (self
->health
< 1)
603 if ((rand() % 12) == 0)
605 addTeleportParticles(self
->x
+ (self
->width
/ 2), self
->y
+ (self
->height
/ 2), 50, SND_TELEPORT3
);
606 map
.boss
[0]->setThinkTime(2);
607 map
.boss
[0]->setActionFinished(2);
608 map
.boss
[0]->think
= &galdovFinalTeleport
;
612 void galdovFinalStandUp()
614 map
.boss
[0]->setSprites(graphics
.getSprite("GaldovShieldRight", true), graphics
.getSprite("GaldovShieldLeft", true), graphics
.getSprite("GaldovShieldLeft", true));
615 self
->setThinkTime(2);
616 self
->setActionFinished(2);
617 addTeleportParticles(self
->x
+ (self
->width
/ 2), self
->y
+ (self
->height
/ 2), 50, SND_TELEPORT3
);
618 self
->think
= &galdovFinalTeleport
;
620 if (map
.boss
[0]->health
<= 15 * game
.skill
)
622 self
->setSprites(graphics
.getSprite("GaldovRight", true), graphics
.getSprite("GaldovLeft", true), graphics
.getSprite("GaldovDie", true));
623 Math::removeBit(&map
.boss
[0]->flags
, ENT_IMMUNE
);
624 map
.boss
[0]->react
= &galdovFinalReact2
;
628 void galdovFinalPainThrow2()
633 self
->think
= &galdovFinalStandUp
;
634 self
->setThinkTime(2);
635 self
->setActionFinished(90);
640 (self
->x
< player
.x
) ? self
->face
= 0 : self
->face
= 1;
644 Math::calculateSlope(map
.boss
[0]->x
, map
.boss
[0]->y
, self
->x
, self
->y
, &dx
, &dy
);
646 self
->dx
= (dx
* (1 + game
.skill
));
647 self
->dy
= (dy
* (1 + game
.skill
));
649 self
->setThinkTime(2);
650 self
->setActionFinished(5);
651 self
->think
= &orbSeekGaldov
;
653 int distX
= (int)fabs(map
.boss
[0]->x
- self
->x
);
654 int distY
= (int)fabs(map
.boss
[0]->y
- self
->y
);
659 int distance
= (int)sqrt(distX
+ distY
);
663 self
->active
= false;
664 self
->setActionFinished(60);
665 self
->setThinkTime(60);
666 addExplosion(self
->x
, self
->y
, 75, &player
);
667 self
->place(9999, 9999);
668 map
.boss
[0]->setSprites(graphics
.getSprite("GaldovPain", true), graphics
.getSprite("GaldovPain", true), graphics
.getSprite("GaldovPain", true));
669 map
.boss
[0]->think
= &galdovFinalPainThrow2
;
670 map
.boss
[0]->health
-= (3 * game
.skill
);
671 Math::removeBit(&map
.boss
[0]->flags
, ENT_FLIES
);
672 Math::removeBit(&map
.boss
[0]->flags
, ENT_FIRETRAIL
);
673 audio
.playSound(SND_BOSSCUSTOM2
, CH_AMBIANCE
);
677 void galdovFinalShieldInit()
679 self
->setActionFinished(60);
680 self
->setThinkTime(60);
681 self
->think
= &galdovMiniAttack
;
684 Math::addBit(&map
.boss
[0]->flags
, ENT_IMMUNE
);
686 for (int i
= 1 ; i
< 6 ; i
++)
688 if (map
.boss
[i
] != NULL
)
692 map
.boss
[i
] = new Boss();
693 strcpy(map
.boss
[i
]->name
, "OrbBomb");
694 map
.boss
[i
]->setSprites(graphics
.getSprite("DroidOrb", true), graphics
.getSprite("DroidOrb", true), graphics
.getSprite("DroidOrb", true));
695 map
.boss
[i
]->health
= 999999;
696 map
.boss
[i
]->maxHealth
= 99999;
697 map
.boss
[i
]->immune
= 0;
698 Math::addBit(&map
.boss
[0]->flags
, ENT_IMMUNE
);
699 map
.boss
[i
]->active
= false;
700 map
.boss
[i
]->setActionFinished(2);
701 map
.boss
[i
]->setThinkTime(2);
702 map
.boss
[i
]->think
= &orbSeekGaldov
;
703 map
.boss
[i
]->react
= NULL
;
704 Math::addBit(&map
.boss
[i
]->flags
, ENT_FLIES
);
707 map
.boss
[1]->place(864, 1536);
708 map
.boss
[2]->place(864, 1792);
709 map
.boss
[3]->place(1856, 1792);
710 map
.boss
[4]->place(1888, 1440);
711 map
.boss
[5]->place(1408, 1472);
713 galdovInitBlackDroids();
716 void galdovFinalWaitForObjective()
718 self
->setActionFinished(120);
719 self
->setThinkTime(2);
721 Objective
*objective
= (Objective
*)map
.objectiveList
.getHead();
723 while (objective
->next
!= NULL
)
725 objective
= (Objective
*)objective
->next
;
727 if (strstr(objective
->target
, "Reality"))
729 if (objective
->completed
)
733 Math::addBit(&player
.flags
, ENT_TELEPORTING
);
734 self
->think
= &galdovFinalShieldInit
;
735 map
.boss
[0]->setSprites(graphics
.getSprite("GaldovShieldRight", true), graphics
.getSprite("GaldovShieldLeft", true), graphics
.getSprite("GaldovShieldLeft", true));
736 self
->setActionFinished(2);
737 self
->setThinkTime(2);
738 map
.setMainBossPart(map
.boss
[0]);
744 void galdovFinalFlee1()
748 addTeleportParticles(self
->x
+ (self
->width
/ 2), self
->y
+ (self
->height
/ 2), 50, SND_TELEPORT3
);
749 Math::addBit(&self
->flags
, ENT_TELEPORTING
);
750 Math::addBit(&self
->flags
, ENT_FLIES
);
751 Math::addBit(&self
->flags
, ENT_FIRETRAIL
);
752 self
->think
= &galdovFinalWaitForObjective
;
753 self
->setActionFinished(2);
754 self
->setThinkTime(2);