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