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