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