2 Copyright (C) 2004 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)
119 void destroyBullet(Entity *bullet)
121 if (bullet->deathSound == -1)
128 if (bullet->flags & ENT_SPARKS)
130 audio.playSound(bullet->deathSound, CH_TOUCH);
133 if (bullet->flags & ENT_EXPLODES)
135 addExplosion(bullet->x + (bullet->width / 2), bullet->y + (bullet->height / 2), bullet->damage, bullet->owner);
138 if (bullet->id == WP_STALAGTITE)
140 throwStalagParticles(bullet->x, bullet->y);
145 for (int i = 0 ; i < 3 ; i++)
147 dx = Math::rrand(-30, 30); dx /= 12;
148 dy = Math::rrand(-30, 30); dy /= 12;
150 if (bullet->flags & ENT_SPARKS)
152 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.white, NULL, 0);
156 map.addParticle(bullet->x, bullet->y, dx, dy, Math::rrand(5, 30), graphics.red, NULL, 0);
161 // Just a little convinence function!
162 void removeBullet(Entity *bullet)
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);
171 void bounceBullet(Entity *bullet, float dx, float dy)
175 bullet->dx = -bullet->dx;
176 bullet->x += bullet->dx;
177 if (bullet->id != WP_LASER)
180 audio.playSound(SND_GRBOUNCE, CH_TOUCH);
182 bullet->face = !bullet->face;
187 bullet->dy = -bullet->dy;
188 bullet->y += bullet->dy;
190 Math::limitFloat(&bullet->dy, -4, 4);
192 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
193 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
195 if (bullet->id != WP_LASER)
198 audio.playSound(SND_GRBOUNCE, CH_TOUCH);
201 if ((bullet->dy > -2) && (bullet->dy <= 0)) bullet->dy = -2;
202 if ((bullet->dy > 0) && (bullet->dy < 2)) bullet->dy = 2;
204 bullet->face = !bullet->face;
208 bool bulletHasCollided(Entity *bullet, float dx, float dy)
213 int x = (int)bullet->x >> BRICKSHIFT;
214 int y = (int)bullet->y >> BRICKSHIFT;
216 if ((x < 0) || (y < 0))
218 removeBullet(bullet);
222 if (map.isSolid(x, y))
224 if (map.isBreakable(x, y))
226 if (bullet->flags & ENT_EXPLODES)
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);
235 if ((Math::prand() % 2) == 0)
237 map.data[x][y] = MAP_AIR;
238 audio.playSound(SND_STONEBREAK, CH_EXPLODE);
239 throwBrickParticles(x << BRICKSHIFT, y << BRICKSHIFT);
244 if (bullet->flags & ENT_BOUNCES)
246 bounceBullet(bullet, dx, dy);
253 enemyBulletCollisions(bullet);
255 checkPlayerBulletCollisions(bullet);
257 checkBossBulletCollisions(bullet);
259 checkSwitchContact(bullet);
261 if ((checkTrainContact(bullet, 0)) || (checkObstacleContact(bullet, 0)))
263 if (bullet->flags & ENT_BOUNCES)
264 bounceBullet(bullet, dx, dy);
273 Entity *bullet = (Entity*)map.bulletList.getHead();
274 Entity *previous = bullet;
278 while (bullet->next != NULL)
280 bullet = (Entity*)bullet->next;
282 bullet->owner->referenced = true;
284 x = (int)(bullet->x - engine.playerPosX);
285 y = (int)(bullet->y - engine.playerPosY);
287 graphics.blit(bullet->getFaceImage(), x, y, graphics.screen, true);
290 if (bullet->flags & ENT_ONFIRE)
292 addFireParticles(bullet->x + Math::rrand(-8, 8), bullet->y + Math::rrand(-8, 8), 1);
295 if (bullet->flags & ENT_FIRETRAIL)
297 addFireTrailParticle(bullet->x, bullet->y);
300 if (bullet->flags & ENT_PARTICLETRAIL)
302 addColorParticles(x, y, -1, 3);
305 if (bullet->owner == &player)
307 if ((x < -160) || (y < -120) || (x > 800) || (y > 600))
309 removeBullet(bullet);
313 if (bulletHasCollided(bullet, bullet->dx, 0))
315 if (!(bullet->flags & ENT_BOUNCES))
321 if (bulletHasCollided(bullet, 0, bullet->dy))
323 if (!(bullet->flags & ENT_BOUNCES))
331 if (bullet->health == 0)
333 Math::removeBit(&bullet->flags, ENT_SPARKS);
334 Math::removeBit(&bullet->flags, ENT_PUFFS);
337 if (!(bullet->flags & ENT_WEIGHTLESS))
342 if (bullet->health > 0)
348 destroyBullet(bullet);
349 map.bulletList.remove(previous, bullet);