2 Copyright (C) 2004-2011 Parallel Realities
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.
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.
13 See the GNU General Public License for more details.
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.
23 void addBullet(Entity *owner, float dx, float dy)
25 if (!(owner->flags & ENT_BOSS))
27 if (owner->environment == ENV_WATER)
29 if ((owner->currentWeapon != &weapon[WP_PISTOL]) && (owner->currentWeapon != &weapon[WP_AIMEDPISTOL]))
36 Entity *bullet = new Entity();
39 bullet->y = owner->y;// + owner->dy;
41 if (owner != &engine.world)
43 bullet->x += (owner->width / 2);
44 bullet->y += (owner->height / 2);
47 bullet->setName(owner->currentWeapon->name);
48 bullet->id = owner->currentWeapon->id;
50 bullet->dy = owner->currentWeapon->dy + dy;
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);
59 if (bullet->flags & ENT_EXPLODES)
61 bullet->deathSound = SND_GRENADE;
63 else if (owner->currentWeapon->fireSound > -1)
65 if ((Math::prand() % 2) == 0)
67 bullet->deathSound = SND_RICO1;
71 bullet->deathSound = SND_RICO2;
76 if (owner->currentWeapon->id == WP_STALAGTITE)
78 bullet->deathSound = SND_STONEBREAK;
81 if (owner->currentWeapon->fireSound > -1)
83 audio.playSound(owner->currentWeapon->fireSound, CH_WEAPON);
86 if (owner->flags & ENT_AIMS)
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;
93 map.addBullet(bullet);
95 // Adjust the reload time of enemies according to difficulty level
96 owner->reload = owner->currentWeapon->reload;
98 if ((owner != &player) && (game.skill < 3))
100 owner->reload *= (3 - game.skill);
103 if (owner->flags & ENT_ALWAYSFIRES)
108 if (owner == &player)
110 game.incBulletsFired();
112 if (engine.cheatReload)
117 if (game.bulletsFired[game.currentWeapon] == 10000)
119 presentPlayerMedal("10000_Bullets");
124 void destroyBullet(Entity *bullet)
126 if (bullet->deathSound == -1)
133 if (bullet->flags & ENT_SPARKS)
135 audio.playSound(bullet->deathSound, CH_TOUCH);
138 if (bullet->flags & ENT_EXPLODES)
140 addExplosion(bullet->x + (bullet->width / 2), bullet->y + (bullet->height / 2), bullet->damage, bullet->owner);
143 if (bullet->id == WP_STALAGTITE)
145 throwStalagParticles(bullet->x, bullet->y);
150 for (int i = 0 ; i < 3 ; i++)
152 dx = Math::rrand(-30, 30); dx /= 12;
153 dy = Math::rrand(-30, 30); dy /= 12;
155 if (bullet->flags & ENT_SPARKS)
157 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.white, NULL, 0);
161 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.red, NULL, 0);
166 // Just a little convinence function!
167 void removeBullet(Entity *bullet)
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);
176 void bounceBullet(Entity *bullet, float dx, float dy)
180 bullet->dx = -bullet->dx;
181 bullet->x += bullet->dx;
182 if (bullet->id != WP_LASER)
185 audio.playSound(SND_GRBOUNCE, CH_TOUCH);
187 bullet->face = !bullet->face;
192 bullet->dy = -bullet->dy;
193 bullet->y += bullet->dy;
195 Math::limitFloat(&bullet->dy, -4, 4);
197 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
198 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
200 if (bullet->id != WP_LASER)
203 audio.playSound(SND_GRBOUNCE, CH_TOUCH);
206 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
207 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
209 bullet->face = !bullet->face;
213 bool bulletHasCollided(Entity *bullet, float dx, float dy)
218 int x = (int)bullet->x >> BRICKSHIFT;
219 int y = (int)bullet->y >> BRICKSHIFT;
221 if ((x < 0) || (y < 0))
223 removeBullet(bullet);
227 if (map.isSolid(x, y))
229 if (map.isBreakable(x, y))
231 if (bullet->flags & ENT_EXPLODES)
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);
240 if ((Math::prand() % 2) == 0)
242 map.data[x][y] = MAP_AIR;
243 audio.playSound(SND_STONEBREAK, CH_EXPLODE);
244 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
249 if (bullet->flags & ENT_BOUNCES)
251 bounceBullet(bullet, dx, dy);
258 enemyBulletCollisions(bullet);
260 checkPlayerBulletCollisions(bullet);
262 checkBossBulletCollisions(bullet);
264 checkSwitchContact(bullet);
266 if ((checkTrainContact(bullet, 0)) || (checkObstacleContact(bullet, 0)))
268 if (bullet->flags & ENT_BOUNCES)
269 bounceBullet(bullet, dx, dy);
278 Entity *bullet = (Entity*)map.bulletList.getHead();
279 Entity *previous = bullet;
283 while (bullet->next != NULL)
285 bullet = (Entity*)bullet->next;
287 bullet->owner->referenced = true;
289 x = (int)(bullet->x - engine.playerPosX);
290 y = (int)(bullet->y - engine.playerPosY);
292 graphics.blit(bullet->getFaceImage(), x, y, graphics.screen, true);
295 if (bullet->flags & ENT_ONFIRE)
297 addFireParticles(bullet->x + Math::rrand(-8, 8), bullet->y + Math::rrand(-8, 8), 1);
300 if (bullet->flags & ENT_FIRETRAIL)
302 addFireTrailParticle(bullet->x, bullet->y);
305 if (bullet->flags & ENT_PARTICLETRAIL)
307 addColorParticles(x, y, -1, 3);
310 if (bullet->owner == &player)
312 if ((x < -160) || (y < -120) || (x > 800) || (y > 600))
314 removeBullet(bullet);
318 if (bulletHasCollided(bullet, bullet->dx, 0))
320 if (!(bullet->flags & ENT_BOUNCES))
326 if (bulletHasCollided(bullet, 0, bullet->dy))
328 if (!(bullet->flags & ENT_BOUNCES))
336 if (bullet->health == 0)
338 Math::removeBit(&bullet->flags, ENT_SPARKS);
339 Math::removeBit(&bullet->flags, ENT_PUFFS);
342 if (!(bullet->flags & ENT_WEIGHTLESS))
347 if (bullet->health > 0)
353 destroyBullet(bullet);
354 map.bulletList.remove(previous, bullet);