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