]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/bullets.cpp
Get rid of false positive warnings from cppcheck.
[quix0rs-blobwars.git] / src / bullets.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 "bullets.h"
23
24 void addBullet(Entity *owner, float dx, float dy)
25 {
26         if (!(owner->flags & ENT_BOSS))
27         {
28                 if (owner->environment == ENV_WATER)
29                 {
30                         if ((owner->currentWeapon != &weapon[WP_PISTOL]) && (owner->currentWeapon != &weapon[WP_AIMEDPISTOL]))
31                         {
32                                 return;
33                         }
34                 }
35         }
36
37         Entity *bullet = new Entity();
38
39         bullet->x = owner->x;
40         bullet->y = owner->y;// + owner->dy;
41
42         if (owner != &engine.world)
43         {
44                 bullet->x += (owner->width / 2);
45                 bullet->y += (owner->height / 2);
46         }
47
48         bullet->setName(owner->currentWeapon->name);
49         bullet->id = owner->currentWeapon->id;
50         bullet->dx = dx;
51         bullet->dy = owner->currentWeapon->dy + dy;
52
53         // Add motion of the player and any platform he/she is on to grenades
54         if (owner->currentWeapon->dy)
55         {
56                 int tdx, tdy;
57                 getTrainMotion(owner, tdx, tdy);
58                 bullet->dx += owner->dx - tdx;
59                 bullet->dy += -tdy;
60         }
61
62         bullet->next = NULL;
63         bullet->health = owner->currentWeapon->health;
64         bullet->damage = owner->currentWeapon->damage;
65         bullet->setSprites(owner->currentWeapon->sprite[0], owner->currentWeapon->sprite[1], owner->currentWeapon->sprite[1]);
66         bullet->face = owner->face;
67         bullet->owner = owner;
68         bullet->flags = owner->currentWeapon->flags + ENT_SPARKS + ENT_BULLET + ((owner->flags & ENT_BOSS) ? ENT_BOSS : 0);
69
70         if (bullet->flags & ENT_EXPLODES)
71         {
72                 bullet->deathSound = SND_GRENADE;
73         }
74         else if (owner->currentWeapon->fireSound > -1)
75         {
76                 if ((Math::prand() % 2) == 0)
77                 {
78                         bullet->deathSound = SND_RICO1;
79                 }
80                 else
81                 {
82                         bullet->deathSound = SND_RICO2;
83                 }
84         }
85         
86         // cheating here!
87         if (owner->currentWeapon->id == WP_STALAGTITE)
88         {
89                 bullet->deathSound = SND_STONEBREAK;
90         }
91
92         if (owner->currentWeapon->fireSound > -1)
93         {
94                 audio.playSound(owner->currentWeapon->fireSound, CH_WEAPON, owner->x);
95         }
96
97         if (owner->flags & ENT_AIMS)
98         {
99                 Math::calculateSlope(player.x + Math::rrand(-20, 20), player.y + Math::rrand(-20, 20), bullet->x, bullet->y, &bullet->dx, &bullet->dy);
100                 bullet->dx *= owner->currentWeapon->dx;
101                 bullet->dy *= owner->currentWeapon->dy;
102         }
103
104         map.addBullet(bullet);
105
106         // Adjust the reload time of enemies according to difficulty level
107         owner->reload = owner->currentWeapon->reload;
108         
109         if ((owner != &player) && (game.skill < 3))
110         {
111                 owner->reload *= (3 - game.skill);
112         }
113
114         if (owner->flags & ENT_ALWAYSFIRES)
115         {
116                 owner->reload = 10;
117         }
118
119         if (owner == &player)
120         {
121                 game.incBulletsFired();
122                 
123                 if (engine.cheatReload)
124                 {
125                         owner->reload = 4;
126                 }
127                 
128                 if (game.bulletsFired[game.currentWeapon] == 10000)
129                 {
130                         presentPlayerMedal("10000_Bullets");
131                 }
132         }
133 }
134
135 void destroyBullet(Entity *bullet)
136 {
137         if (bullet->deathSound == -1)
138         {
139                 return;
140         }
141
142         bullet->health = 0;
143
144         if (bullet->flags & ENT_SPARKS)
145         {
146                 audio.playSound(bullet->deathSound, CH_TOUCH, bullet->x);
147         }
148
149         if (bullet->flags & ENT_EXPLODES)
150         {
151                 addExplosion(bullet->x + (bullet->width / 2), bullet->y + (bullet->height / 2), bullet->damage, bullet->owner);
152         }
153         
154         if (bullet->id == WP_STALAGTITE)
155         {
156                 throwStalagParticles(bullet->x, bullet->y);
157         }
158
159         float dx, dy;
160
161         for (int i = 0 ; i < 3 ; i++)
162         {
163                 dx = Math::rrand(-30, 30); dx /= 12;
164                 dy = Math::rrand(-30, 30); dy /= 12;
165                 
166                 if (bullet->flags & ENT_SPARKS)
167                 {
168                         map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.white, NULL, 0);
169                 }
170                 else
171                 {
172                         map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.red, NULL, 0);
173                 }
174         }
175 }
176
177 // Just a little convinence function!
178 void removeBullet(Entity *bullet)
179 {
180         bullet->health = 0;
181         bullet->deathSound = -1;
182         Math::removeBit(&bullet->flags, ENT_SPARKS);
183         Math::removeBit(&bullet->flags, ENT_PUFFS);
184         Math::removeBit(&bullet->flags, ENT_EXPLODES);
185 }
186
187 void bounceBullet(Entity *bullet, float dx, float dy)
188 {
189         if (dx)
190         {
191                 bullet->dx = -bullet->dx;
192                 bullet->x += bullet->dx;
193                 if (bullet->id != WP_LASER)
194                 {
195                         bullet->dx *= 0.75;
196                         audio.playSound(SND_GRBOUNCE, CH_TOUCH, bullet->x);
197                 }
198                 bullet->face = !bullet->face;
199         }
200
201         if (dy)
202         {
203                 bullet->dy = -bullet->dy;
204                 bullet->y += bullet->dy;
205                 
206                 Math::limitFloat(&bullet->dy, -4, 4);
207
208                 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
209                 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
210
211                 if (bullet->id != WP_LASER)
212                 {
213                         bullet->dy *= 0.75;
214                         audio.playSound(SND_GRBOUNCE, CH_TOUCH, bullet->x);
215                 }
216
217                 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
218                 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
219
220                 bullet->face = !bullet->face;
221         }
222 }
223
224 bool bulletHasCollided(Entity *bullet, float dx, float dy)
225 {
226         bullet->x += dx;
227         bullet->y += dy;
228
229         int x = (int)bullet->x >> BRICKSHIFT;
230         int y = (int)bullet->y >> BRICKSHIFT;
231
232         if ((x < 0) || (y < 0))
233         {
234                 removeBullet(bullet);
235         }
236         else
237         {
238                 if (map.isSolid(x, y))
239                 {
240                         if (map.isBreakable(x, y))
241                         {
242                                 if (bullet->flags & ENT_EXPLODES)
243                                 {
244                                         Math::removeBit(&bullet->flags, ENT_BOUNCES);
245                                         map.data[x][y] = MAP_AIR;
246                                         audio.playSound(SND_STONEBREAK, CH_EXPLODE, bullet->x);
247                                         throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
248                                 }
249                                 else
250                                 {
251                                         if ((Math::prand() % 2) == 0)
252                                         {
253                                                 map.data[x][y] = MAP_AIR;
254                                                 audio.playSound(SND_STONEBREAK, CH_EXPLODE, bullet->x);
255                                                 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
256                                         }
257                                 }
258                         }
259
260                         if (bullet->flags & ENT_BOUNCES)
261                         {
262                                 bounceBullet(bullet, dx, dy);
263                         }
264
265                         return true;
266                 }
267         }
268
269         enemyBulletCollisions(bullet);
270
271         checkPlayerBulletCollisions(bullet);
272         
273         checkBossBulletCollisions(bullet);
274         
275         checkSwitchContact(bullet);
276
277         if ((checkTrainContact(bullet, DIR_XY)) || (checkObstacleContact(bullet, DIR_XY)))
278         {
279                 if (bullet->flags & ENT_BOUNCES)
280                         bounceBullet(bullet, dx, dy);
281                 return true;
282         }
283
284         return false;
285 }
286
287 void doBullets()
288 {
289         Entity *bullet = (Entity*)map.bulletList.getHead();
290         Entity *previous = bullet;
291
292         int x, y;
293
294         while (bullet->next != NULL)
295         {
296                 bullet = (Entity*)bullet->next;
297                 
298                 bullet->owner->referenced = true;
299
300                 x = (int)(bullet->x - engine.playerPosX);
301                 y = (int)(bullet->y - engine.playerPosY);
302
303                 graphics.blit(bullet->getFaceImage(), x, y, graphics.screen, true);
304                 bullet->animate();
305
306                 if (bullet->flags & ENT_ONFIRE)
307                 {
308                         addFireParticles(bullet->x + Math::rrand(-8, 8), bullet->y + Math::rrand(-8, 8), 1);
309                 }
310
311                 if (bullet->flags & ENT_FIRETRAIL)
312                 {
313                         addFireTrailParticle(bullet->x, bullet->y);
314                 }
315                 
316                 if (bullet->flags & ENT_PARTICLETRAIL)
317                 {
318                         addColorParticles(x, y, -1, 3);
319                 }
320
321                 if (bullet->owner == &player)
322                 {
323                         if ((x < -160) || (y < -120) || (x > 800) || (y > 600))
324                         {
325                                 removeBullet(bullet);
326                         }
327                 }
328
329                 if (bulletHasCollided(bullet, bullet->dx, 0))
330                 {
331                         if (!(bullet->flags & ENT_BOUNCES))
332                         {
333                                 bullet->health = 0;
334                         }
335                 }
336
337                 if (bulletHasCollided(bullet, 0, bullet->dy))
338                 {
339                         if (!(bullet->flags & ENT_BOUNCES))
340                         {
341                                 bullet->health = 0;
342                         }
343                 }
344
345                 bullet->health--;
346                 
347                 if (bullet->health == 0)
348                 {
349                         Math::removeBit(&bullet->flags, ENT_SPARKS);
350                         Math::removeBit(&bullet->flags, ENT_PUFFS);
351                 }
352
353                 if (!(bullet->flags & ENT_WEIGHTLESS))
354                 {
355                         bullet->dy += 0.1;
356                 }
357
358                 if (bullet->health > 0)
359                 {
360                         previous = bullet;
361                 }
362                 else
363                 {
364                         destroyBullet(bullet);
365                         map.bulletList.remove(previous, bullet);
366                         bullet = previous;
367                 }
368         }
369 }
370