]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/tankBoss.cpp
Capitalize Makefiles.
[quix0rs-blobwars.git] / src / tankBoss.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
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.
9
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.
13
14 See the GNU General Public License for more details.
15
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.
19
20 */
21
22 #include "tankBoss.h"
23
24 // **************** Machine Gun Boss ***********************
25
26 void tankBossMGFight();
27 void tankBossGLFight();
28 void activateGLBoss();
29
30 /**
31 * Adds a load of particles within an area of the specified location
32 * @param x The x location
33 * @param y The y location
34 */
35 void plasmaBurstTraceParticles(int x, int y)
36 {
37         int color[7];
38         
39         for (int i = 0 ; i < 7 ; i++)
40         {
41                 color[i] = SDL_MapRGB(graphics.screen->format, 0, 100 + (i * 20), 0);
42         }
43         
44         int dx = 0;
45
46         for (int i = 0 ; i < 25 ; i++)
47         {
48                 dx = Math::rrand(0, 5);
49                 
50                 if (self->face == 1)
51                 {
52                         dx = -dx;
53                 }
54
55                 map.addParticle(x + Math::rrand(-6, 6), y + Math::rrand(-2, 2), dx, 0, Math::rrand(1, 90), color[Math::rrand(0, 6)], NULL, PAR_WEIGHTLESS);
56         }
57 }
58
59 /**
60 * Adds particles to the front of the MG Tank Boss's gun
61 */
62 void plasmaChargeParticles()
63 {
64         int x = (int)self->x;
65         int y = (int)self->y + 10;
66         
67         if (self->face == 0)
68         {
69                 x += self->getFaceImage()->w;
70         }
71         
72         float dx, dy;
73         
74         for (int i = 0 ; i < 2 ; i++)
75         {
76                 dx = Math::rrand(-30, 30); dx /= 90;
77                 dy = Math::rrand(-30, 30); dy /= 90;
78                 map.addParticle(x, y, dx, dy, Math::rrand(30, 60), graphics.green, NULL, PAR_WEIGHTLESS);
79         }
80 }
81
82 /**
83 * Traces a line from the MG Tank Boss to 800 pixel in the
84 * direction it is facing. Anything in the path is killed immediately.
85 */
86 void traceTankBossMGFireLine()
87 {
88         int dx = 1;
89         
90         if (self->face == 1)
91         {
92                 dx = -1;
93         }
94         
95         int x = (int)self->x;
96         int y = (int)self->y + 10;
97         
98         Entity *enemy = NULL;
99         
100         for (int i = 0 ; i < 800 ; i++)
101         {
102                 x = (int)self->x;
103                 
104                 if (self->face == 0)
105                 {
106                         x += self->getFaceImage()->w;
107                 }
108                 
109                 x += (i * dx);
110                 
111                 plasmaBurstTraceParticles(x, y);
112                 
113                 if (Collision::collision(player.x, player.y, 20, 20, x - 1, y - 1, 2, 2))
114                 {
115                         throwAndDamageEntity(&player, 100, dx * 10, dx * 10, 0);
116                         
117                         for (int i = 0 ; i < 10 ; i++)
118                         {
119                                 addExplosion(player.x + Math::rrand(-25, 25), player.y + Math::rrand(-25, 25), 10, self);
120                         }
121                 }
122                 
123                 enemy = (Entity*)map.enemyList.getHead();
124
125                 while (enemy->next != NULL)
126                 {
127                         enemy = (Entity*)enemy->next;
128                         
129                         if (Collision::collision(enemy->x, enemy->y, enemy->getFaceImage()->w, enemy->getFaceImage()->h, x - 1, y - 1, 2, 2))
130                         {
131                                 throwAndDamageEntity(enemy, 100, dx * 10, dx * 10, 0);
132                                 
133                                 enemy->health = -1;
134                                 
135                                 for (int i = 0 ; i < 10 ; i++)
136                                 {
137                                         addExplosion(enemy->x + Math::rrand(-25, 25), enemy->y + Math::rrand(-25, 25), 10, self);
138                                 }
139                         }
140                 }       
141         }
142         
143         self->setThinkTime(2);
144         self->setActionFinished(90);
145         Math::removeBit(&self->flags, ENT_IMMUNE);
146         self->think = &tankBossMGFight;
147 }
148
149 /**
150 * Tells the Machine Gun Tank to fire it's beam laser
151 */
152 void tankBossMGCannonFire()
153 {
154         self->setThinkTime(2);
155         self->setActionFinished(2);
156         self->think = &tankBossMGCannonFire;
157         
158         traceTankBossMGFireLine();
159 }
160
161 /**
162 * Tells the Machine Gun boss to begin charging it's
163 * cannon and play the appropriate sound
164 */
165 void tankBossMGCannonChargeFire()
166 {
167         plasmaChargeParticles();
168         
169         self->setActionFinished(2);
170         
171         self->custom--;
172         
173         if (self->custom == 0)
174         {
175                 self->think = tankBossMGCannonFire;
176                 audio.playSound(SND_BOSSCUSTOM2, CH_AMBIANCE);
177         }
178 }
179
180 void tankBossMGRapidFire()
181 {
182         (self->x < player.x) ? self->face = 0 : self->face = 1;
183         
184         addBullet((Entity*)self, 0, 0);
185         
186         self->think = &tankBossMGRapidFire;
187         self->setActionFinished(4);
188         self->custom--;
189         
190         if (self->custom <= 0)
191         {
192                 self->think = &tankBossMGFight;
193                 self->setThinkTime(2);
194                 self->setActionFinished(90);
195         }
196 }
197
198 void tankBossMGFire()
199 {
200         (self->x < player.x) ? self->face = 0 : self->face = 1;
201         
202         addBullet((Entity*)self, 0, 0);
203         
204         self->think = &tankBossMGFire;
205         self->setActionFinished(15);
206         self->custom--;
207         
208         if (self->custom <= 0)
209         {
210                 self->think = &tankBossMGFight;
211                 self->setThinkTime(2);
212                 self->setActionFinished(60);
213         }
214 }
215
216 void tankBossMGJump()
217 {
218         self->dy = -12;
219         
220         (player.x < self->x) ? self->dx = -6 : self->dx = 6;
221         
222         self->think = &tankBossMGFight;
223         self->setActionFinished(45);
224 }
225
226 void tankBossMGDie()
227 {
228         self->setThinkTime(60);
229         self->setActionFinished(60);
230         self->health -= Math::rrand(1, 2);
231         
232         // don't hurt the player(!)
233         addExplosion(self->x, self->y, 50, &player);
234         addSmokeAndFire(self, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
235         addBlood(self, Math::rrand(-5, 5), Math::rrand(-5, 5), 3);
236         
237         if ((Math::prand() % 5) == 0)
238         {
239                 self->dx = Math::rrand(-15, 15);
240                 self->dy = Math::rrand(-8, 0);
241         }
242         
243         if (self->health <= -100)
244         {
245                 checkObjectives(self->name, false);
246                 
247                 activateGLBoss();
248         }
249 }
250
251 void tankBossMGAttack()
252 {
253         (player.x > self->x) ? self->face = 0 : self->face = 1;
254         
255         int r = Math::prand() % 12;
256         
257         if (r < 6)
258         {
259                 self->custom = Math::rrand(1, 6);
260                 self->think = &tankBossMGFire;
261                 self->setThinkTime(0);
262                 self->setActionFinished(2);
263         }
264         else if (r < 10)
265         {
266                 self->custom = Math::rrand(35, 80);
267                 self->think = &tankBossMGCannonChargeFire;
268                 self->setThinkTime(0);
269                 self->setActionFinished(2);
270                 audio.playSound(SND_BOSSCUSTOM1, CH_AMBIANCE);
271                 Math::addBit(&self->flags, ENT_IMMUNE);
272         }
273         else
274         {
275                 self->custom = 15;
276                 self->think = &tankBossMGRapidFire;
277                 self->setThinkTime(0);
278                 self->setActionFinished(2);
279         }
280 }
281
282 void tankBossMGFight()
283 {
284         if (player.health < 1)
285         {
286                 self->dx = 0;
287                 return;
288         }
289         
290         int r = Math::prand() % 10;
291         
292         if (r < 5)
293         {
294                 if (player.x - 320 < self->x)
295                         self->dx = -2;
296                 else if (player.x + 320 > self->x)
297                         self->dx = 2;
298                 else
299                         self->dx = Math::rrand(-2, 2);
300                 
301                 (self->x < player.x) ? self->face = 0 : self->face = 1;
302                 self->setActionFinished(60);
303                 self->setThinkTime(1);
304         }
305         else if (r < 6)
306         {
307                 self->think = &tankBossMGJump;
308                 self->setActionFinished(2);
309                 self->setThinkTime(2);
310         }
311         else
312         {
313                 self->dx = 0;
314                 self->setThinkTime(2);
315                 self->think = &tankBossMGAttack;
316         }
317 }
318
319 void activateGLBoss()
320 {
321         if (map.boss[1] == NULL)
322         {
323                 map.mainBossPart = NULL;
324                 return;
325         }
326         
327         map.boss[1]->active = true;
328         map.boss[1]->dx = Math::rrand(416, 928);
329         map.boss[1]->dy = 8576;
330         map.boss[1]->setThinkTime(2);
331         map.boss[1]->setActionFinished(2);
332         map.boss[1]->think = &tankBossGLFight;
333         Math::addBit(&map.boss[1]->flags, ENT_TELEPORTING);
334         
335         map.setMainBossPart(map.boss[1]);
336 }
337
338 void tankBossMGSwap()
339 {
340         // Machine Gun Boss wait state
341         self->active = false;
342         self->face = 0;
343         
344         // Grenade launcher boss active state
345         activateGLBoss();
346 }
347
348 void tankBossMGReact()
349 {
350         if (map.boss[1] == NULL)
351         {
352                 return;
353         }
354         
355         if (self->flags & ENT_IMMUNE)
356         {
357                 return;
358         }
359         
360         if ((Math::prand() % 25) > 0)
361         {
362                 return;
363         }
364         
365         self->dx = 915;
366         self->dy = 8256;
367         self->think = &tankBossMGSwap;
368         self->setThinkTime(2);
369         self->setActionFinished(2);
370         Math::addBit(&self->flags, ENT_TELEPORTING);
371 }
372
373 void tankBossMGStart()
374 {
375         self->dx = Math::rrand(416, 928);
376         self->dy = 8576;
377         Math::addBit(&self->flags, ENT_TELEPORTING);
378         self->think = &tankBossMGFight;
379 }
380
381 void tankBossMGInit()
382 {
383         debug(("tankBossMGInit\n"));
384         
385         map.boss[0] = new Boss();
386         strlcpy(map.boss[0]->name, "BioMech Tank V1.1", sizeof map.boss[0]->name);
387         map.boss[0]->health = 65 * game.skill;
388         map.boss[0]->maxHealth = 65 * game.skill;
389         map.boss[0]->setSprites(graphics.getSprite("BlobTankCannonRight", true), graphics.getSprite("BlobTankCannonLeft", true), graphics.getSprite("BlobTankCannonLeft", true));
390         map.boss[0]->currentWeapon = &weapon[WP_PLASMARIFLE];
391         map.boss[0]->face = 0;
392         map.boss[0]->active = false;
393         map.boss[0]->x = 900;
394         map.boss[0]->y = 8256;
395         map.boss[0]->immune = 0;
396         map.boss[0]->setThinkTime(1);
397         map.boss[0]->setActionFinished(1);
398         map.boss[0]->think = &tankBossMGStart;
399         map.boss[0]->react = &tankBossMGReact;
400         map.boss[0]->die = &tankBossMGDie;
401         Math::addBit(&map.boss[0]->flags, ENT_AIMS);
402         
403         audio.loadSound(SND_BOSSCUSTOM1, "sound/tankBeam");
404         audio.loadSound(SND_BOSSCUSTOM2, "sound/tankBeamFire");
405         
406         map.setMainBossPart(map.boss[0]);
407         
408         debug(("tankBossMGInit: Done\n"));
409 }
410
411 // **************** Grenade Launcher Boss ***********************
412
413 void tankBossGLJump()
414 {
415         self->dy = -12;
416         
417         (player.x < self->x) ? self->dx = -6 : self->dx = 6;
418         
419         self->think = &tankBossGLFight;
420         self->setActionFinished(45);
421 }
422
423 void tankBossGLRapidFire()
424 {
425         (self->x < player.x) ? self->face = 0 : self->face = 1;
426         
427         addBullet((Entity*)self, 0, 0);
428         
429         self->think = &tankBossGLRapidFire;
430         self->setActionFinished(4);
431         self->custom--;
432         
433         if (self->custom <= 0)
434         {
435                 self->think = &tankBossGLFight;
436                 self->setThinkTime(2);
437                 self->setActionFinished(90);
438         }
439 }
440
441 void tankBossGLMortor()
442 {
443         (self->x < player.x) ? self->face = 0 : self->face = 1;
444         
445         int speed = Math::rrand(3, 5);
446         if (self->face == 1)
447                 speed = -speed;
448         
449         addBullet((Entity*)self, speed, 0);
450         
451         self->think = &tankBossGLMortor;
452         self->setActionFinished(20);
453         self->custom--;
454         
455         if (self->custom <= 0)
456         {
457                 self->think = &tankBossGLFight;
458                 self->setThinkTime(2);
459                 self->setActionFinished(60);
460         }
461 }
462
463 void tankBossGLAttack()
464 {
465         (player.x > self->x) ? self->face = 0 : self->face = 1;
466         
467         int r = Math::prand() % 10;
468         
469         if (r < 5)
470         {
471                 Math::removeBit(&self->flags, ENT_AIMS);
472                 self->currentWeapon = getWeaponByName("Mortor Shells");
473                 self->think = &tankBossGLMortor;
474                 self->setThinkTime(0);
475                 self->setActionFinished(2);
476                 self->custom = Math::rrand(2, 5);
477         }
478         else if (r < 8)
479         {
480                 Math::addBit(&self->flags, ENT_AIMS);
481                 self->currentWeapon = getWeaponByName("Aimed Pistol");
482                 self->custom = 15;
483                 self->think = &tankBossGLRapidFire;
484                 self->setThinkTime(0);
485                 self->setActionFinished(2);
486         }
487         else
488         {
489                 self->custom = Math::rrand(45, 60);
490                 //self->think = &tankBossGLCannonChargeFire;
491                 self->setThinkTime(0);
492                 self->setActionFinished(2);
493         }
494 }
495
496 void tankBossGLFight()
497 {
498         if (player.health < 1)
499         {
500                 self->dx = 0;
501                 return;
502         }
503         
504         int r = Math::prand() % 10;
505         
506         if (r < 5)
507         {
508                 if (player.x - 320 < self->x)
509                         self->dx = -2;
510                 else if (player.x + 320 > self->x)
511                         self->dx = 2;
512                 else
513                         self->dx = Math::rrand(-2, 2);
514                 
515                 (self->x < player.x) ? self->face = 0 : self->face = 1;
516                 self->setActionFinished(60);
517                 self->setThinkTime(1);
518         }
519         else if (r < 6)
520         {
521                 self->think = &tankBossGLJump;
522                 self->setActionFinished(2);
523                 self->setThinkTime(2);
524         }
525         else
526         {
527                 self->dx = 0;
528                 self->setThinkTime(2);
529                 self->think = &tankBossGLAttack;
530         }
531 }
532
533 void activateMGBoss()
534 {
535         if (map.boss[0] == NULL)
536         {
537                 map.mainBossPart = NULL;
538                 return;
539         }
540         
541         map.boss[0]->active = true;
542         map.boss[0]->dx = Math::rrand(416, 928);
543         map.boss[0]->dy = 8576;
544         map.boss[0]->setThinkTime(2);
545         map.boss[0]->setActionFinished(2);
546         map.boss[0]->think = &tankBossMGFight;
547         Math::addBit(&map.boss[0]->flags, ENT_TELEPORTING);
548         
549         map.setMainBossPart(map.boss[0]);
550 }
551
552 void tankBossGLSwap()
553 {
554         // Grenade launcher Boss wait state
555         self->active = false;
556         self->face = 1;
557         
558         // Machine Gun boss active state
559         activateMGBoss();
560 }
561
562 void tankBossGLReact()
563 {
564         if (map.boss[0] == NULL)
565                 return;
566         
567         if ((Math::prand() % 25) > 0)
568                 return;
569         
570         self->dx = 420;
571         self->dy = 8256;
572         self->think = &tankBossGLSwap;
573         self->setThinkTime(2);
574         self->setActionFinished(2);
575         Math::addBit(&self->flags, ENT_TELEPORTING);
576 }
577
578 void tankBossGLDie()
579 {
580         self->setThinkTime(60);
581         self->setActionFinished(60);
582         self->health -= Math::rrand(1, 2);
583         
584         // don't hurt the player(!)
585         addExplosion(self->x, self->y, 50, &player);
586         addSmokeAndFire(self, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
587         addBlood(self, Math::rrand(-5, 5), Math::rrand(-5, 5), 3);
588         
589         if ((Math::prand() % 5) == 0)
590         {
591                 self->dx = Math::rrand(-15, 15);
592                 self->dy = Math::rrand(-8, 0);
593         }
594         
595         if (self->health <= -100)
596         {
597                 checkObjectives(self->name, false);
598                 
599                 activateMGBoss();
600         }
601 }
602
603 void tankBossGLInit()
604 {
605         debug(("tankBossGLInit\n"));
606         
607         map.boss[1] = new Boss();
608         strlcpy(map.boss[1]->name, "BioMech Tank V2.6", sizeof map.boss[1]->name);
609         map.boss[1]->health = 65 * game.skill;
610         map.boss[1]->maxHealth = 65 * game.skill;
611         map.boss[1]->setSprites(graphics.getSprite("BlobTankGrenadeRight", true), graphics.getSprite("BlobTankGrenadeLeft", true), graphics.getSprite("BlobTankGrenadeLeft", true));
612         map.boss[1]->currentWeapon = getWeaponByName("Mortor Shells");
613         map.boss[1]->face = 1;
614         map.boss[1]->active = false;
615         map.boss[1]->x = 420;
616         map.boss[1]->y = 8256;
617         map.boss[1]->immune = 0;
618         map.boss[1]->setThinkTime(1);
619         map.boss[1]->setActionFinished(1);
620         map.boss[1]->think = &tankBossGLFight;
621         map.boss[1]->react = &tankBossGLReact;
622         map.boss[1]->die = &tankBossGLDie;
623         
624         debug(("tankBossMGInit: Done\n"));
625 }