]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/galdov.cpp
Use UNIX line endings everywhere.
[quix0rs-blobwars.git] / src / galdov.cpp
1 /*
2 Copyright (C) 2004 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 "galdov.h"
22
23 void galdovAttack();
24 void galdovCheckSplit();
25
26 void splitParticles()
27 {
28         (self->x < player.x) ? self->face = 0 : self->face = 1;
29         
30         int color = 0;
31         float dx, dy;
32         
33         dx = 0;
34         
35         switch (Math::prand() % 5)
36         {
37                 case 0:
38                         color = graphics.red;
39                         break;
40                 case 1:
41                         color = graphics.yellow;
42                         break;
43                 case 2:
44                         color = graphics.green;
45                         break;
46                 case 3:
47                         color = graphics.cyan;
48                         break;
49                 case 4:
50                         color = graphics.white;
51                         break;
52         }
53         
54         for (int i = 0 ; i < 20 ; i++)
55         {
56                 dy = Math::rrand(-150, -50);
57                 dy /= 100;
58                 map.addParticle(self->x + (Math::prand() % self->width), self->y  + (Math::prand() % self->height), dx, dy, Math::rrand(1, 60), color, NULL, PAR_WEIGHTLESS);
59         }
60         
61         self->setThinkTime(1);
62         self->setActionFinished(1);
63         self->think = &splitParticles;
64         self->custom--;
65         
66         if (self->custom == 0)
67         {
68                 self->setThinkTime(2);
69                 self->setActionFinished(2);
70                 self->think = &galdovAttack;
71                 
72                 if (self == map.boss[0])
73                 {
74                         if ((Math::prand() % self->health) == 0)
75                         {
76                                 self->think = &galdovCheckSplit;
77                         }
78                 }
79                 
80         }
81 }
82
83 void galdovTeleport()
84 {
85         self->setThinkTime(2);
86         self->setActionFinished(2);
87         
88         int x = (int)player.x >> BRICKSHIFT;
89         int y = (int)player.y >> BRICKSHIFT;
90         x += Math::rrand(-10, 10);
91         y += Math::rrand(-10, 10);
92         
93         Math::limitInt(&x, 1, 28);
94         Math::limitInt(&y, 259, 283);
95         
96         if (map.data[x][y] == MAP_AIR)
97         {
98                 x = x << BRICKSHIFT;
99                 y = y << BRICKSHIFT;
100                 self->x = x;
101                 self->y = y;
102                 addTeleportParticles(self->x + 10, self->y + 10, 50, SND_TELEPORT2);
103                 self->think = &galdovAttack;
104         }
105 }
106
107 void galdovReact()
108 {
109         if (self->health < 0)
110                 return;
111         
112         int r = Math::prand() % 10;
113         
114         if (r == 0)
115         {
116                 self->setThinkTime(2);
117                 self->setActionFinished(2);
118                 self->think = &galdovTeleport;
119                 
120                 r = Math::prand() % 3;
121                 
122                 if (r == 0)
123                 {
124                         self->setThinkTime(2);
125                         self->setActionFinished(2);
126                         self->think = &galdovCheckSplit;
127                 }
128         }
129 }
130
131 void galdovSplit(int i)
132 {
133         audio.playSound(SND_BOSSCUSTOM1, CH_AMBIANCE);
134         
135         map.boss[i]->active = true;
136         map.boss[i]->health = 4 * game.skill;
137         map.boss[i]->maxHealth = 4 * game.skill;
138         map.boss[i]->x = map.boss[0]->x;
139         map.boss[i]->y = map.boss[0]->y;
140         map.boss[i]->flags = map.boss[0]->flags;
141         map.boss[i]->think = &galdovAttack;
142         
143         if ((Math::prand() % 2) == 0)
144         {
145                 map.boss[i]->currentWeapon = getRandomAimedWeapon();
146                 Math::addBit(&map.boss[i]->flags, ENT_AIMS);
147         }
148         else
149         {
150                 map.boss[i]->currentWeapon = getRandomStraightWeapon();
151                 Math::removeBit(&map.boss[i]->flags, ENT_AIMS);
152         }
153         
154         if ((Math::prand() % 2) == 0)
155         {
156                 map.boss[0]->dx = -.5;
157                 map.boss[0]->dy = 0;
158                 map.boss[i]->dx = .5;
159                 map.boss[i]->dy = 0;
160         }
161         else
162         {
163                 map.boss[0]->dx = .5;
164                 map.boss[0]->dy = 0;
165                 map.boss[i]->dx = -.5;
166                 map.boss[i]->dy = 0;
167         }
168         
169         map.boss[0]->think = &splitParticles;
170         map.boss[0]->setThinkTime(1);
171         map.boss[0]->setActionFinished(1);
172         map.boss[0]->custom = 60;
173         
174         map.boss[i]->think = &splitParticles;
175         map.boss[i]->setThinkTime(1);
176         map.boss[i]->setActionFinished(1);
177         map.boss[i]->custom = 60;
178 }
179
180 void galdovCheckSplit()
181 {
182         for (int i = 1 ; i < 10 ; i++)
183         {
184                 if (!map.boss[i]->active)
185                 {
186                         galdovSplit(i);
187                         return;
188                 }
189         }
190 }
191
192 void galdovFire()
193 {       
194         (self->x < player.x) ? self->face = 0 : self->face = 1;
195         
196         self->setActionFinished(9);
197         self->setThinkTime(2);
198         self->think = &galdovFire;
199         
200         if (hasClearShot(self))
201         {
202                 self->flags & ENT_AIMS ? addBullet((Entity*)self, 0, 0) : addBullet((Entity*)self, self->currentWeapon->getSpeed(self->face), 0);
203                         
204                 if (self->currentWeapon == &weapon[WP_ALIENSPREAD])
205                 {
206                         addBullet(self, self->currentWeapon->getSpeed(self->face), 2);
207                         addBullet(self, self->currentWeapon->getSpeed(self->face), -2);
208                 }
209         }
210         
211         self->custom--;
212         if (self->custom == 0)
213         {
214                 self->think = &galdovAttack;
215         }
216 }
217
218 void galdovRocketAttack()
219 {
220         (self->x < player.x) ? self->face = 0 : self->face = 1;
221         
222         if (!hasClearShot(self))
223                 return;
224         
225         self->setActionFinished(5);
226         self->setThinkTime(2);
227         self->think = &galdovRocketAttack;
228         
229         addBullet((Entity*)self, 0, 0);
230         
231         self->custom--;
232         
233         if (self->custom == 0)
234         {
235                 self->think = &galdovAttack;
236                 self->currentWeapon = getRandomGaldovWeapon();
237         }
238 }
239
240 void galdovChasePlayer()
241 {
242         (self->x < player.x) ? self->face = 0 : self->face = 1;
243         
244         float dx, dy;
245         
246         Math::calculateSlope(player.x, player.y, self->x, self->y, &dx, &dy);
247         
248         self->dx = (dx * 2);
249         self->dy = (dy * 2);
250         
251         self->setThinkTime(10);
252         self->setActionFinished(10);
253         self->think = &galdovAttack;
254 }
255
256 void galdovMoveRandom()
257 {
258         self->think = &galdovAttack;
259         
260         if (self->flags & ENT_FLIES)
261         {
262                 self->dx = Math::rrand(-200, 200);
263                 self->dy = Math::rrand(-200, 200);
264         
265                 self->dx *= 0.01;
266                 self->dy *= 0.01;
267         
268                 self->setThinkTime(2);
269                 self->setActionFinished(Math::rrand(60, 90));
270         }
271         else
272         {
273                 self->dy = Math::rrand(-12, 0);
274         
275                 (player.x < self->x) ? self->dx = -3 : self->dx = 3;
276                 
277                 self->think = &galdovAttack;
278                 self->setActionFinished(45);
279         }
280 }
281
282 void galdovDoInvisible()
283 {
284         if ((Math::prand() % 2) == 0)
285         {
286                 map.boss[0]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
287         }
288         else
289         {
290                 map.boss[0]->setSprites(graphics.getSprite("GaldovInvsRight", true), graphics.getSprite("GaldovInvsLeft", true), graphics.getSprite("GaldovInvsLeft", true));
291         }
292         
293         self->setThinkTime(2);
294         self->setActionFinished(2);
295         self->think = &galdovAttack;
296 }
297
298 void galdovAttack()
299 {       
300         if (player.health < 1)
301         {
302                 self->dx = self->dy = 0;
303                 return;
304         }
305         
306         (self->x < player.x) ? self->face = 0 : self->face = 1;
307         
308         self->think = &galdovAttack;
309         self->setThinkTime(2);
310         self->setActionFinished(2);
311         
312         int r = Math::prand() % 100;
313         
314         if (r < 10)
315         {
316                 self->think = &galdovFire;
317                 self->custom = Math::rrand(1, 8);
318         }
319         else if (r < 17)
320         {
321                 // Make sure only the real Galdov does this!
322                 if (self == map.boss[0])
323                 {
324                         addTeleportParticles(self->x + 10, self->y + 10, 50, SND_TELEPORT2);
325                         self->x = -9999;
326                         self->y = -9999;
327                         self->setActionFinished(120);
328                         self->setThinkTime(2);
329                         self->think = &galdovTeleport;
330                 }
331         }
332         else if (r < 40)
333         {
334                 self->think = &galdovChasePlayer;
335         }
336         else if (r < 60)
337         {
338                 self->think = &galdovMoveRandom;
339         }
340         else if (r < 80)
341         {
342                 if ((self->flags & ENT_FLIES) && (Math::prand() % 5) == 0)
343                 {
344                         Math::removeBit(&self->flags, ENT_FLIES);
345                         Math::removeBit(&self->flags, ENT_FIRETRAIL);
346                 }
347                 else
348                 {
349                         Math::addBit(&self->flags, ENT_FLIES);
350                         Math::addBit(&self->flags, ENT_FIRETRAIL);
351                 }
352         }
353         else if (r < 85)
354         {
355                 if (self == map.boss[0])
356                 {
357                         self->think = &galdovDoInvisible;
358                 }
359         }
360         else if (r < 90)
361         {
362                 map.boss[0]->currentWeapon = getRandomGaldovWeapon();
363         }
364         else if (r == 91)
365         {
366                 // Make sure only the real Galdov does this!
367                 if (self == map.boss[0])
368                 {
369                         self->custom = Math::rrand(4, 8);
370                         self->currentWeapon = &weapon[WP_ROCKETS];
371                         self->think = &galdovRocketAttack;
372                 }
373         }
374         else
375         {
376                 // Make sure only the real Galdov does this!
377                 if (self == map.boss[0])
378                 {
379                         self->think = &galdovCheckSplit;
380                 }
381         }
382 }
383
384 void galdovDie()
385 {       
386         self->health--;
387         
388         if (map.mainBossPart != NULL)
389         {
390                 map.mainBossPart = NULL;
391                 audio.playSound(SND_BOSSCUSTOM2, CH_AMBIANCE);
392         }
393         
394         if ((self->health % 5) == 0)
395         {
396                 self->setActionFinished(5);
397                 self->setThinkTime(2);
398                 
399                 self->dx = Math::rrand(-5, 5);
400                 self->dy = Math::rrand(-5, 5);
401                 
402                 addExplosion(self->x, self->y, 5, &player);
403                 addSmokeAndFire(self, Math::rrand(-4, 4), Math::rrand(-4, 4), 2);
404         }
405         
406         for (int i = 1 ; i < 10 ; i++)
407         {
408                 if (map.boss[i]->health > -1)
409                 {
410                         map.boss[i]->health = -1;
411                 }
412         }
413         
414         if (self->health <= -100)
415         {
416                 checkObjectives(self->name, false);     
417                 map.mainBossPart = NULL;
418                 addTeleportParticles(self->x, self->y, 75, SND_TELEPORT3);
419         }
420 }
421
422 void dropItems(int x, int y)
423 {
424         int r;
425         
426         for (int i = 0 ; i < 2 ; i++)
427         {
428                 r = Math::rrand(ITEM_PISTOL, ITEM_DOUBLECHERRY);
429                 
430                 // Grenades make this battle far too easy(!)
431                 if (r == ITEM_GRENADES)
432                         r = ITEM_LASER;
433                 
434                 if ((Math::prand() % 10) == 0)
435                         r = ITEM_TRIPLECHERRY;
436                 
437                 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
438         }
439 }
440
441 void fakeDie()
442 {
443         dropItems((int)self->x, (int)self->y);
444         
445         addExplosion(self->x, self->y, 50, self);
446         self->setThinkTime(2);
447         self->setActionFinished(2);
448         self->active = false;
449         self->face = 1;
450         self->x = 9999;
451         self->y = 9999;
452 }
453
454 void galdovInit()
455 {
456         debug(("galdovInit\n"));
457         
458         map.boss[0] = new Boss();
459         strcpy(map.boss[0]->name, "Galdov");
460         map.boss[0]->health = 45 * game.skill;
461         map.boss[0]->maxHealth = 45 * game.skill;
462         map.boss[0]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
463         map.boss[0]->currentWeapon = &weapon[WP_AIMEDPISTOL];
464         map.boss[0]->face = 0;
465         map.boss[0]->active = true;
466         map.boss[0]->x = 448;
467         map.boss[0]->y = 9024;
468         map.boss[0]->immune = 0;
469         map.boss[0]->setThinkTime(2);
470         map.boss[0]->setActionFinished(2);
471         map.boss[0]->think = &galdovCheckSplit;
472         map.boss[0]->react = &galdovReact;
473         map.boss[0]->die = &galdovDie;
474         
475         Math::addBit(&map.boss[0]->flags, ENT_AIMS);
476         
477         SDL_SetAlpha(graphics.getSprite("GaldovInvsLeft", true)->image[0], SDL_SRCALPHA|SDL_RLEACCEL, 100);
478         SDL_SetAlpha(graphics.getSprite("GaldovInvsRight", true)->image[0], SDL_SRCALPHA|SDL_RLEACCEL, 100);
479         
480         for (int i = 1 ; i < 10 ; i++)
481         {
482                 map.boss[i] = new Boss();
483                 strcpy(map.boss[i]->name, "Fake");
484                 map.boss[i]->setSprites(graphics.getSprite("GaldovRight", true), graphics.getSprite("GaldovLeft", true), graphics.getSprite("GaldovLeft", true));
485                 map.boss[i]->x = 9999;
486                 map.boss[i]->y = 9999;
487                 map.boss[i]->active = false;
488                 map.boss[i]->think = &galdovAttack;
489                 map.boss[i]->react = NULL;
490                 map.boss[i]->die = &fakeDie;
491         }
492         
493         map.setMainBossPart(map.boss[0]);
494         
495         audio.loadSound(SND_BOSSCUSTOM1, "sound/galdovSplit.wav");
496         audio.loadSound(SND_BOSSCUSTOM2, "sound/galdovPain.wav");
497         
498         debug(("galdovInit: Done\n"));
499 }