]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/droidBoss.cpp
Use time_t to store time data.
[quix0rs-blobwars.git] / src / droidBoss.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 "droidBoss.h"
23
24 void droidBossAttack();
25
26 void droidBossChangeParticles()
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 (self->shieldFrequency)
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(2);
62         self->setActionFinished(10);
63         self->think = &droidBossChangeParticles;
64         self->custom--;
65         
66         if (self->custom == 0)
67         {
68                 self->setThinkTime(2);
69                 self->setActionFinished(10);
70                 self->think = &droidBossAttack;
71         }
72 }
73
74 void droidBossChasePlayer()
75 {
76         (self->x < player.x) ? self->face = 0 : self->face = 1;
77         
78         float dx, dy;
79         
80         Math::calculateSlope(player.x, player.y, self->x, self->y, &dx, &dy);
81         
82         self->dx = (dx * 2);
83         self->dy = (dy * 2);
84         
85         self->setThinkTime(10);
86         self->setActionFinished(10);
87         self->think = &droidBossAttack;
88 }
89
90 void droidBossChangeFrequency()
91 {
92         (self->x < player.x) ? self->face = 0 : self->face = 1;
93         
94         self->shieldFrequency = Math::rrand(WP_PISTOL, WP_SPREAD);
95         
96         self->think = &droidBossChangeParticles;
97         self->setThinkTime(2);
98         self->setActionFinished(2);
99         self->custom = 5;
100         
101         Math::removeBit(&self->flags, ENT_AIMS);
102         Math::removeBit(&self->flags, ENT_RAPIDFIRE);
103         
104         switch (self->shieldFrequency)
105         {
106                 case WP_PISTOL:
107                         self->currentWeapon = getWeaponByName("Aimed Pistol");
108                         Math::addBit(&self->flags, ENT_AIMS);
109                         self->setSprites(graphics.getSprite("JetpackBlobRight1", true), graphics.getSprite("JetpackBlobLeft1", true), graphics.getSprite("JetpackBlobLeft1", true));
110                         break;
111                 case WP_MACHINEGUN:
112                         self->currentWeapon = getWeaponByName("Machine Gun");
113                         Math::addBit(&self->flags, ENT_RAPIDFIRE);
114                         self->setSprites(graphics.getSprite("JetpackBlobRight2", true), graphics.getSprite("JetpackBlobLeft2", true), graphics.getSprite("JetpackBlobLeft2", true));
115                         break;
116                 case WP_LASER:
117                         self->currentWeapon = getWeaponByName("Alien Laser Cannon");
118                         self->setSprites(graphics.getSprite("JetpackBlobRight3", true), graphics.getSprite("JetpackBlobLeft3", true), graphics.getSprite("JetpackBlobLeft3", true));
119                         break;
120                 case WP_GRENADES:
121                         self->currentWeapon = getWeaponByName("Aimed Pistol");
122                         self->shieldFrequency = WP_PISTOL;
123                         Math::addBit(&self->flags, ENT_AIMS);
124                         self->setSprites(graphics.getSprite("JetpackBlobRight1", true), graphics.getSprite("JetpackBlobLeft1", true), graphics.getSprite("JetpackBlobLeft1", true));
125                         break;
126                 case WP_SPREAD:
127                         self->currentWeapon = &weapon[WP_ALIENSPREAD];
128                         Math::addBit(&self->flags, ENT_AIMS);
129                         self->setSprites(graphics.getSprite("JetpackBlobRight4", true), graphics.getSprite("JetpackBlobLeft4", true), graphics.getSprite("JetpackBlobLeft4", true));
130                         break;
131         }
132         
133         audio.playSound(SND_BOSSCUSTOM1, CH_AMBIANCE, self->x);
134 }
135
136 void droidBossDie()
137 {
138         self->health -= Math::rrand(1, 2);
139         self->setActionFinished(30);
140         self->setThinkTime(2);
141         
142         self->dx = Math::rrand(-3, 3);
143         self->dy = Math::rrand(-3, 3);
144         
145         addExplosion(self->x + Math::prand() % self->width, self->y + Math::prand() % self->height, 50, &player);
146         addSmokeAndFire(self, Math::rrand(-5, 5), Math::rrand(-5, 5), 2);
147         
148         if (self->health <= -100)
149         {
150                 checkObjectives(self->name, false);
151                 
152                 map.mainBossPart = NULL;
153         }
154 }
155
156 void droidGoCrazy()
157 {
158         self->dx = Math::rrand(-8, 8);
159         self->dy = Math::rrand(-8, 8);
160         
161         (self->dx > 0) ? self->face = 0 : self->face = 1;
162         
163         if (self->y >= 4800)
164                 self->dy = -2;
165         
166         self->setThinkTime(2);
167         self->setActionFinished(5);
168         self->think = &droidGoCrazy;
169         
170         self->custom--;
171         
172         if (self->custom == 0)
173         {
174                 Math::removeBit(&self->flags, ENT_IMMUNE);
175                 self->think = &droidBossChangeFrequency;
176                 self->setActionFinished(2);
177                 self->setThinkTime(2);
178         }
179 }
180
181 void droidBossReact()
182 {
183         if ((Math::prand() % 10) == 0)
184         {
185                 Math::addBit(&self->flags, ENT_IMMUNE);
186                 audio.playSound(SND_BOSSCUSTOM2, CH_SPAWN, self->x);
187                 self->custom = 5;
188                 self->think = &droidGoCrazy;
189                 self->setActionFinished(2);
190                 self->setThinkTime(2);
191         }
192 }
193
194 void droidBossFire()
195 {       
196         (self->x < player.x) ? self->face = 0 : self->face = 1;
197         
198         if (hasClearShot((Entity*)self))
199         {
200                 self->flags & ENT_AIMS ? addBullet((Entity*)self, 0, 0) : addBullet((Entity*)self, self->currentWeapon->getSpeed(self->face), 0);
201                 
202                 if (self->currentWeapon == &weapon[WP_ALIENSPREAD])
203                 {
204                         addBullet(self, self->currentWeapon->getSpeed(self->face), 2);
205                         addBullet(self, self->currentWeapon->getSpeed(self->face), -2);
206                 }
207         }
208                                         
209         self->setThinkTime(2);
210         self->setActionFinished(self->currentWeapon->reload);
211         
212         self->custom--;
213         if (self->custom == 0)
214                 self->think = &droidBossAttack;
215 }
216
217 void orbWait()
218 {
219         self->setThinkTime(60);
220         self->setActionFinished(60);
221 }
222
223 void orbExplode()
224 {
225         addExplosion(self->x, self->y, 50, self);
226         self->setThinkTime(2);
227         self->setActionFinished(2);
228         self->active = false;
229         self->face = 1;
230         self->think = &orbWait;
231         self->x = 9999;
232         self->y = 9999;
233 }
234
235 void doOrb()
236 {
237         (self->x < player.x) ? self->face = 0 : self->face = 1;
238         
239         float dx, dy;
240         
241         Math::calculateSlope(player.x, player.y, self->x, self->y, &dx, &dy);
242         
243         self->dx = (dx * (1 + game.skill));
244         self->dy = (dy * (1 + game.skill));
245         
246         self->setThinkTime(2);
247         self->setActionFinished(Math::rrand(10, 90));
248         self->think = &doOrb;
249         
250         if (game.skill >= 2)
251         {
252                 int distX = (int)fabs(player.x - self->x);
253                 int distY = (int)fabs(player.y - self->y);
254         
255                 distX *= distX;
256                 distY *= distY;
257         
258                 int distance = (int)sqrt(distX + distY);
259                 
260                 if (distance <= 25)
261                         self->health = -1;
262         }
263         
264         if ((Math::prand() % 10) == 0)
265                 self->health = -1;
266 }
267
268 void fireOrb(int i)
269 {
270         debug(("fireOrb()\n"));
271         
272         map.boss[i]->active = true;
273         map.boss[i]->maxHealth = map.boss[i]->health = 1 * game.skill;
274         map.boss[i]->x = self->x;
275         map.boss[i]->y = self->y + 20;
276         
277         map.boss[i]->think = &doOrb;
278         map.boss[i]->die = &orbExplode;
279         map.boss[i]->setActionFinished(2);
280         map.boss[i]->setThinkTime(2);
281 }
282
283 void droidBossOrbAttack()
284 {
285         debug(("droidBossClawAttack\n"));
286         
287         for (int i = 1 ; i < 6 ; i++)
288         {
289                 if (!map.boss[i]->active)
290                 {
291                         fireOrb(i);
292                         self->setThinkTime(2);
293                         self->setActionFinished(90);
294                         self->think = &droidBossAttack;
295                         return;
296                 }
297         }
298         
299         // nothing to do(!)
300         self->think = &droidBossAttack;
301 }
302
303 void droidBossMoveRandomly()
304 {
305         self->dx = Math::rrand(-200, 200);
306         self->dy = Math::rrand(-200, 200);
307         
308         self->dx *= 0.01;
309         self->dy *= 0.01;
310         
311         self->setThinkTime(2);
312         self->setActionFinished(90);
313         self->think = &droidBossAttack;
314 }
315
316 void droidBossAttack()
317 {
318         if (player.health < 1)
319         {
320                 self->dx = self->dy = 0;
321                 return;
322         }
323         
324         (self->x < player.x) ? self->face = 0 : self->face = 1;
325         
326         int r = Math::prand() % 110;
327         
328         if (r < 30)
329         {
330                 self->think = &droidBossChasePlayer;
331                 self->setThinkTime(2);
332                 self->setActionFinished(2);
333                 self->custom = 10;
334         }
335         else if (r < 70)
336         {
337                 self->think = &droidBossFire;
338                 self->setThinkTime(2);
339                 self->setActionFinished(2);
340                 self->custom = Math::rrand(1, 3);
341         }
342         else if (r < 95)
343         {
344                 self->think = &droidBossMoveRandomly;
345                 self->setThinkTime(2);
346                 self->setActionFinished(2);
347                 self->custom = 10;
348         }
349         else if (r < 108)
350         {
351                 self->think = &droidBossOrbAttack;
352                 self->setThinkTime(2);
353                 self->setActionFinished(2);
354                 self->custom = Math::rrand(1, 3);
355         }
356         else
357         {
358                 self->think = &droidBossChangeFrequency;
359                 self->setThinkTime(2);
360                 self->setActionFinished(2);
361         }
362 }
363
364 void droidBossInit()
365 {
366         debug(("droidBossInit\n"));
367         
368         map.boss[0] = new Boss();
369         strlcpy(map.boss[0]->name, "BioMech Jetpack Blob", sizeof map.boss[0]->name);
370         map.boss[0]->health = 30 * game.skill;
371         map.boss[0]->maxHealth = 30 * game.skill;
372         map.boss[0]->setSprites(graphics.getSprite("JetpackBlobRight1", true), graphics.getSprite("JetpackBlobLeft1", true), graphics.getSprite("JetpackBlobLeft1", true));
373         map.boss[0]->currentWeapon = getWeaponByName("Aimed Pistol");
374         map.boss[0]->face = 1;
375         map.boss[0]->active = true;
376         map.boss[0]->x = 3172;
377         map.boss[0]->y = 4646;
378         map.boss[0]->immune = 0;
379         map.boss[0]->setThinkTime(2);
380         map.boss[0]->setActionFinished(2);
381         map.boss[0]->think = &droidBossChangeFrequency;
382         map.boss[0]->react = &droidBossReact;
383         map.boss[0]->die = &droidBossDie;
384         Math::addBit(&map.boss[0]->flags, ENT_FLIES);
385         
386         map.setMainBossPart(map.boss[0]);
387         
388         for (int i = 1 ; i < 6 ; i++)
389         {
390                 map.boss[i] = new Boss();
391                 strlcpy(map.boss[i]->name, "Orb Bomb", sizeof map.boss[i]->name);
392                 map.boss[i]->setSprites(graphics.getSprite("DroidOrb", true), graphics.getSprite("DroidOrb", true), graphics.getSprite("DroidOrb", true));
393                 map.boss[i]->active = false;
394                 map.boss[i]->face = 1;
395                 map.boss[i]->think = &orbWait;
396                 map.boss[i]->x = 9999;
397                 map.boss[i]->y = 9999;
398                 Math::addBit(&map.boss[i]->flags, ENT_FLIES);
399         }
400         
401         audio.loadSound(SND_BOSSCUSTOM1, "sound/droidChangeFreq");
402         audio.loadSound(SND_BOSSCUSTOM2, "sound/droidFreakOut");
403         
404         debug(("droidBossInit: Done\n"));
405 }