]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/bullets.cpp
Update copyrights to 2011.
[quix0rs-blobwars.git] / src / bullets.cpp
1 /*
2 Copyright (C) 2004-2011 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                 if (game.bulletsFired[game.currentWeapon] == 10000)
118                 {
119                         presentPlayerMedal("10000_Bullets");
120                 }
121         }
122 }
123
124 void destroyBullet(Entity *bullet)
125 {
126         if (bullet->deathSound == -1)
127         {
128                 return;
129         }
130
131         bullet->health = 0;
132
133         if (bullet->flags & ENT_SPARKS)
134         {
135                 audio.playSound(bullet->deathSound, CH_TOUCH);
136         }
137
138         if (bullet->flags & ENT_EXPLODES)
139         {
140                 addExplosion(bullet->x + (bullet->width / 2), bullet->y + (bullet->height / 2), bullet->damage, bullet->owner);
141         }
142         
143         if (bullet->id == WP_STALAGTITE)
144         {
145                 throwStalagParticles(bullet->x, bullet->y);
146         }
147
148         float dx, dy;
149
150         for (int i = 0 ; i < 3 ; i++)
151         {
152                 dx = Math::rrand(-30, 30); dx /= 12;
153                 dy = Math::rrand(-30, 30); dy /= 12;
154                 
155                 if (bullet->flags & ENT_SPARKS)
156                 {
157                         map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.white, NULL, 0);
158                 }
159                 else
160                 {
161                         map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.red, NULL, 0);
162                 }
163         }
164 }
165
166 // Just a little convinence function!
167 void removeBullet(Entity *bullet)
168 {
169         bullet->health = 0;
170         bullet->deathSound = -1;
171         Math::removeBit(&bullet->flags, ENT_SPARKS);
172         Math::removeBit(&bullet->flags, ENT_PUFFS);
173         Math::removeBit(&bullet->flags, ENT_EXPLODES);
174 }
175
176 void bounceBullet(Entity *bullet, float dx, float dy)
177 {
178         if (dx)
179         {
180                 bullet->dx = -bullet->dx;
181                 bullet->x += bullet->dx;
182                 if (bullet->id != WP_LASER)
183                 {
184                         bullet->dx *= 0.75;
185                         audio.playSound(SND_GRBOUNCE, CH_TOUCH);
186                 }
187                 bullet->face = !bullet->face;
188         }
189
190         if (dy)
191         {
192                 bullet->dy = -bullet->dy;
193                 bullet->y += bullet->dy;
194                 
195                 Math::limitFloat(&bullet->dy, -4, 4);
196
197                 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
198                 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
199
200                 if (bullet->id != WP_LASER)
201                 {
202                         bullet->dy *= 0.75;
203                         audio.playSound(SND_GRBOUNCE, CH_TOUCH);
204                 }
205
206                 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
207                 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
208
209                 bullet->face = !bullet->face;
210         }
211 }
212
213 bool bulletHasCollided(Entity *bullet, float dx, float dy)
214 {
215         bullet->x += dx;
216         bullet->y += dy;
217
218         int x = (int)bullet->x >> BRICKSHIFT;
219         int y = (int)bullet->y >> BRICKSHIFT;
220
221         if ((x < 0) || (y < 0))
222         {
223                 removeBullet(bullet);
224         }
225         else
226         {
227                 if (map.isSolid(x, y))
228                 {
229                         if (map.isBreakable(x, y))
230                         {
231                                 if (bullet->flags & ENT_EXPLODES)
232                                 {
233                                         Math::removeBit(&bullet->flags, ENT_BOUNCES);
234                                         map.data[x][y] = MAP_AIR;
235                                         audio.playSound(SND_STONEBREAK, CH_EXPLODE);
236                                         throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
237                                 }
238                                 else
239                                 {
240                                         if ((Math::prand() % 2) == 0)
241                                         {
242                                                 map.data[x][y] = MAP_AIR;
243                                                 audio.playSound(SND_STONEBREAK, CH_EXPLODE);
244                                                 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
245                                         }
246                                 }
247                         }
248
249                         if (bullet->flags & ENT_BOUNCES)
250                         {
251                                 bounceBullet(bullet, dx, dy);
252                         }
253
254                         return true;
255                 }
256         }
257
258         enemyBulletCollisions(bullet);
259
260         checkPlayerBulletCollisions(bullet);
261         
262         checkBossBulletCollisions(bullet);
263         
264         checkSwitchContact(bullet);
265
266         if ((checkTrainContact(bullet, 0)) || (checkObstacleContact(bullet, 0)))
267         {
268                 if (bullet->flags & ENT_BOUNCES)
269                         bounceBullet(bullet, dx, dy);
270                 return true;
271         }
272
273         return false;
274 }
275
276 void doBullets()
277 {
278         Entity *bullet = (Entity*)map.bulletList.getHead();
279         Entity *previous = bullet;
280
281         int x, y;
282
283         while (bullet->next != NULL)
284         {
285                 bullet = (Entity*)bullet->next;
286                 
287                 bullet->owner->referenced = true;
288
289                 x = (int)(bullet->x - engine.playerPosX);
290                 y = (int)(bullet->y - engine.playerPosY);
291
292                 graphics.blit(bullet->getFaceImage(), x, y, graphics.screen, true);
293                 bullet->animate();
294
295                 if (bullet->flags & ENT_ONFIRE)
296                 {
297                         addFireParticles(bullet->x + Math::rrand(-8, 8), bullet->y + Math::rrand(-8, 8), 1);
298                 }
299
300                 if (bullet->flags & ENT_FIRETRAIL)
301                 {
302                         addFireTrailParticle(bullet->x, bullet->y);
303                 }
304                 
305                 if (bullet->flags & ENT_PARTICLETRAIL)
306                 {
307                         addColorParticles(x, y, -1, 3);
308                 }
309
310                 if (bullet->owner == &player)
311                 {
312                         if ((x < -160) || (y < -120) || (x > 800) || (y > 600))
313                         {
314                                 removeBullet(bullet);
315                         }
316                 }
317
318                 if (bulletHasCollided(bullet, bullet->dx, 0))
319                 {
320                         if (!(bullet->flags & ENT_BOUNCES))
321                         {
322                                 bullet->health = 0;
323                         }
324                 }
325
326                 if (bulletHasCollided(bullet, 0, bullet->dy))
327                 {
328                         if (!(bullet->flags & ENT_BOUNCES))
329                         {
330                                 bullet->health = 0;
331                         }
332                 }
333
334                 bullet->health--;
335                 
336                 if (bullet->health == 0)
337                 {
338                         Math::removeBit(&bullet->flags, ENT_SPARKS);
339                         Math::removeBit(&bullet->flags, ENT_PUFFS);
340                 }
341
342                 if (!(bullet->flags & ENT_WEIGHTLESS))
343                 {
344                         bullet->dy += 0.1;
345                 }
346
347                 if (bullet->health > 0)
348                 {
349                         previous = bullet;
350                 }
351                 else
352                 {
353                         destroyBullet(bullet);
354                         map.bulletList.remove(previous, bullet);
355                         bullet = previous;
356                 }
357         }
358 }
359