2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
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.
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.
14 See the GNU General Public License for more details.
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.
24 void addBullet(Entity *owner, float dx, float dy)
26 if (!(owner->flags & ENT_BOSS))
28 if (owner->environment == ENV_WATER)
30 if ((owner->currentWeapon != &weapon[WP_PISTOL]) && (owner->currentWeapon != &weapon[WP_AIMEDPISTOL]))
37 Entity *bullet = new Entity();
40 bullet->y = owner->y;// + owner->dy;
42 if (owner != &engine.world)
44 bullet->x += (owner->width / 2);
45 bullet->y += (owner->height / 2);
48 bullet->setName(owner->currentWeapon->name);
49 bullet->id = owner->currentWeapon->id;
51 bullet->dy = owner->currentWeapon->dy + dy;
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);
60 if (bullet->flags & ENT_EXPLODES)
62 bullet->deathSound = SND_GRENADE;
64 else if (owner->currentWeapon->fireSound > -1)
66 if ((Math::prand() % 2) == 0)
68 bullet->deathSound = SND_RICO1;
72 bullet->deathSound = SND_RICO2;
77 if (owner->currentWeapon->id == WP_STALAGTITE)
79 bullet->deathSound = SND_STONEBREAK;
82 if (owner->currentWeapon->fireSound > -1)
84 audio.playSound(owner->currentWeapon->fireSound, CH_WEAPON, owner->x);
87 if (owner->flags & ENT_AIMS)
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;
94 map.addBullet(bullet);
96 // Adjust the reload time of enemies according to difficulty level
97 owner->reload = owner->currentWeapon->reload;
99 if ((owner != &player) && (game.skill < 3))
101 owner->reload *= (3 - game.skill);
104 if (owner->flags & ENT_ALWAYSFIRES)
109 if (owner == &player)
111 game.incBulletsFired();
113 if (engine.cheatReload)
118 if (game.bulletsFired[game.currentWeapon] == 10000)
120 presentPlayerMedal("10000_Bullets");
125 void destroyBullet(Entity *bullet)
127 if (bullet->deathSound == -1)
134 if (bullet->flags & ENT_SPARKS)
136 audio.playSound(bullet->deathSound, CH_TOUCH, bullet->x);
139 if (bullet->flags & ENT_EXPLODES)
141 addExplosion(bullet->x + (bullet->width / 2), bullet->y + (bullet->height / 2), bullet->damage, bullet->owner);
144 if (bullet->id == WP_STALAGTITE)
146 throwStalagParticles(bullet->x, bullet->y);
151 for (int i = 0 ; i < 3 ; i++)
153 dx = Math::rrand(-30, 30); dx /= 12;
154 dy = Math::rrand(-30, 30); dy /= 12;
156 if (bullet->flags & ENT_SPARKS)
158 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.white, NULL, 0);
162 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.red, NULL, 0);
167 // Just a little convinence function!
168 void removeBullet(Entity *bullet)
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);
177 void bounceBullet(Entity *bullet, float dx, float dy)
181 bullet->dx = -bullet->dx;
182 bullet->x += bullet->dx;
183 if (bullet->id != WP_LASER)
186 audio.playSound(SND_GRBOUNCE, CH_TOUCH, bullet->x);
188 bullet->face = !bullet->face;
193 bullet->dy = -bullet->dy;
194 bullet->y += bullet->dy;
196 Math::limitFloat(&bullet->dy, -4, 4);
198 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
199 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
201 if (bullet->id != WP_LASER)
204 audio.playSound(SND_GRBOUNCE, CH_TOUCH, bullet->x);
207 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
208 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
210 bullet->face = !bullet->face;
214 bool bulletHasCollided(Entity *bullet, float dx, float dy)
219 int x = (int)bullet->x >> BRICKSHIFT;
220 int y = (int)bullet->y >> BRICKSHIFT;
222 if ((x < 0) || (y < 0))
224 removeBullet(bullet);
228 if (map.isSolid(x, y))
230 if (map.isBreakable(x, y))
232 if (bullet->flags & ENT_EXPLODES)
234 Math::removeBit(&bullet->flags, ENT_BOUNCES);
235 map.data[x][y] = MAP_AIR;
236 audio.playSound(SND_STONEBREAK, CH_EXPLODE, bullet->x);
237 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
241 if ((Math::prand() % 2) == 0)
243 map.data[x][y] = MAP_AIR;
244 audio.playSound(SND_STONEBREAK, CH_EXPLODE, bullet->x);
245 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
250 if (bullet->flags & ENT_BOUNCES)
252 bounceBullet(bullet, dx, dy);
259 enemyBulletCollisions(bullet);
261 checkPlayerBulletCollisions(bullet);
263 checkBossBulletCollisions(bullet);
265 checkSwitchContact(bullet);
267 if ((checkTrainContact(bullet, 0)) || (checkObstacleContact(bullet, 0)))
269 if (bullet->flags & ENT_BOUNCES)
270 bounceBullet(bullet, dx, dy);
279 Entity *bullet = (Entity*)map.bulletList.getHead();
280 Entity *previous = bullet;
284 while (bullet->next != NULL)
286 bullet = (Entity*)bullet->next;
288 bullet->owner->referenced = true;
290 x = (int)(bullet->x - engine.playerPosX);
291 y = (int)(bullet->y - engine.playerPosY);
293 graphics.blit(bullet->getFaceImage(), x, y, graphics.screen, true);
296 if (bullet->flags & ENT_ONFIRE)
298 addFireParticles(bullet->x + Math::rrand(-8, 8), bullet->y + Math::rrand(-8, 8), 1);
301 if (bullet->flags & ENT_FIRETRAIL)
303 addFireTrailParticle(bullet->x, bullet->y);
306 if (bullet->flags & ENT_PARTICLETRAIL)
308 addColorParticles(x, y, -1, 3);
311 if (bullet->owner == &player)
313 if ((x < -160) || (y < -120) || (x > 800) || (y > 600))
315 removeBullet(bullet);
319 if (bulletHasCollided(bullet, bullet->dx, 0))
321 if (!(bullet->flags & ENT_BOUNCES))
327 if (bulletHasCollided(bullet, 0, bullet->dy))
329 if (!(bullet->flags & ENT_BOUNCES))
337 if (bullet->health == 0)
339 Math::removeBit(&bullet->flags, ENT_SPARKS);
340 Math::removeBit(&bullet->flags, ENT_PUFFS);
343 if (!(bullet->flags & ENT_WEIGHTLESS))
348 if (bullet->health > 0)
354 destroyBullet(bullet);
355 map.bulletList.remove(previous, bullet);