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 throwAndDamageEntity(Entity *ent, int damage, int minDX, int maxDX, int DY)
26 if ((ent == &player) && (game.missionOver > 0))
31 if (!(ent->flags & ENT_EXPLODES))
33 audio.playSound(SND_HIT, CH_ANY, ent->x);
34 for (int i = 0 ; i < 4 ; i++)
36 addBlood(ent, Math::rrand(-5, 5), Math::rrand(-6, -3), i);
41 audio.playSound(SND_CLANG, CH_ANY, ent->x);
42 addColorParticles(ent->x, ent->y, Math::rrand(25, 75), -1);
45 if ((ent == &player) && (engine.cheatInvulnerable))
49 ent->health -= damage;
58 ent->health -= damage;
63 if (player.health <= 0)
65 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH, player.x);
69 Math::removeBit(&player.flags, ENT_FLIES);
71 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
75 ent->health -= damage;
78 ((Math::prand() % 2) == 0) ? ent->dx = -minDX : ent->dx = maxDX;
90 bool checkBrickContactX(Entity *ent)
92 int new_ent_x = (int)round((ent->x + ent->dx) * 100) / 100;
93 int ent_y = (int)round(ent->y * 100) / 100;
94 int x1 = new_ent_x >> BRICKSHIFT;
95 int x2 = (new_ent_x + ent->width - 1) >> BRICKSHIFT;
96 int y1 = ent_y >> BRICKSHIFT;
97 int y2 = (ent_y + ent->height - 1) >> BRICKSHIFT;
99 if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
104 int mapAttribute = map.data[x1][y2];
106 evaluateMapAttribute(ent, mapAttribute);
108 if ((ent->flags & ENT_SWIMS) && (mapAttribute == MAP_AIR))
113 if ((map.isSolid(x1, y1)) || (map.isSolid(x1, y2)))
115 ent->x = (x1 + 1) * BRICKSIZE;
117 // if (map.isSolid(x1, y2))
119 // ent->falling = false;
125 else if (ent->dx > 0)
127 if ((map.isSolid(x2, y1)) || (map.isSolid(x2, y2)))
129 ent->x = (x2 * BRICKSIZE) - ent->width;
131 // if (map.isSolid(x1, y2))
133 // ent->falling = false;
143 bool checkBrickContactY(Entity *ent)
145 int ent_x = (int)round(ent->x * 100) / 100;
146 int new_ent_y = (int)round((ent->y + ent->dy) * 100) / 100;
147 int x1 = ent_x >> BRICKSHIFT;
148 int x2 = (ent_x + ent->width - 1) >> BRICKSHIFT;
149 int y1 = new_ent_y >> BRICKSHIFT;
150 int y2 = (new_ent_y + ent->height - 1) >> BRICKSHIFT;
152 if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
157 int mapAttribute = map.data[x1][y2];
161 mapAttribute = map.data[x1][y1];
164 evaluateMapAttribute(ent, mapAttribute);
166 if (ent->flags & ENT_SWIMS)
168 switch (mapAttribute)
174 case MAP_AIR_CEILING_1:
177 if (map.isCavesTileset)
182 case MAP_AIR_CEILING_2:
183 if (map.isGrasslandsTileset)
193 if ((map.isSolid(x1, y1)) || (map.isSolid(x2, y1)))
195 ent->y = (y1 + 1) * BRICKSIZE;
196 ent->falling = false;
201 else if (ent->dy > 0)
205 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
207 ent->falling = false;
209 ent->y = (y2 * BRICKSIZE) - ent->height;
211 if ((map.isSolid(x1, y2)) && (!map.isBreakable(x1, y2)) && (!map.isNoReset(x1, y2)))
213 if ((ent == &player) && (player.environment == ENV_AIR))
215 game.setCheckPoint(x1 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
219 game.setObjectiveCheckPoint();
224 if ((map.isSolid(x2, y2)) && (!map.isBreakable(x2, y2)) && (!map.isNoReset(x2, y2)))
226 if ((ent == &player) && (player.environment == ENV_AIR))
228 game.setCheckPoint(x2 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
231 game.setObjectiveCheckPoint();
243 void moveEntity(Entity *ent)
245 if (ent->owner->flags & ENT_TELEPORTING)
247 int diffX = (abs((int)ent->x - (int)ent->dx) / 20);
248 int diffY = (abs((int)ent->y - (int)ent->dy) / 20);
250 // add teleport particles so we can see where thing are going (no sound)
251 addTeleportParticles(ent->x + Math::prand() % ent->width, ent->y + Math::prand() % ent->height, 3, -1);
253 Math::limitInt(&diffX, 3, 30);
254 Math::limitInt(&diffY, 3, 30);
256 if (ent->x > ent->dx) ent->x -= diffX;
257 if (ent->x < ent->dx) ent->x += diffX;
258 if (ent->y > ent->dy) ent->y -= diffY;
259 if (ent->y < ent->dy) ent->y += diffY;
261 if (Collision::collision(ent->x, ent->y, ent->width, ent->height, ent->dx, ent->dy, ent->width, ent->height))
263 Math::removeBit(&ent->flags, ENT_TELEPORTING);
264 addTeleportParticles(ent->x + (ent->width / 2), ent->y + (ent->height / 2), 25, SND_TELEPORT3);
265 ent->dx = ent->dy = 0;
266 ent->environment = ENV_AIR;
270 if (player.flags & ENT_FLIES)
272 player.setSprites(graphics.getSprite("JPBobRight", true), graphics.getSprite("JPBobLeft", true), graphics.getSprite("BobSpin", true));
276 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
280 // raise to the floor
281 int x1 = (int)ent->x >> BRICKSHIFT;
282 int x2 = ((int)ent->x + ent->width - 1) >> BRICKSHIFT;
283 int y2 = ((int)ent->y + ent->height - 1) >> BRICKSHIFT;
284 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
286 ent->y = (y2 * BRICKSIZE) - ent->height;
289 debug(("%s reappeared at %f:%f\n", ent->name, ent->x, ent->y));
295 if (ent->owner != ent)
304 if ((!(ent->flags & ENT_WEIGHTLESS)) && (!(ent->flags & ENT_FLIES)) && (!(ent->flags & ENT_SWIMS)))
309 else if (!(ent->flags & ENT_FLIES))
311 if (ent->environment == ENV_AIR)
315 // This is what makes swimming work:
316 else if ((!config.isControl(CONTROL::UP)) && (!config.isControl(CONTROL::JUMP)) && (!config.isControl(CONTROL::DOWN)))
324 if ((checkBrickContactX(ent)) || (checkObstacleContact(ent, 0)) || (checkTrainContact(ent, 0)))
331 if (ent->flags & ENT_SLIDES)
339 if ((checkBrickContactY(ent)) || (checkObstacleContact(ent, 1)) || (checkTrainContact(ent, 1)))
341 if ((ent->flags & ENT_BOUNCES) && (ent->dy >= 3))
343 ent->dy = (0 - ent->dy / 2);
354 checkSwitchContact(ent);
355 checkTeleportContact(ent);
357 // Math::limitFloat(&ent->x, 10, (MAPWIDTH * BRICKSIZE) - 20);
366 else if (ent->x > (MAPWIDTH * BRICKSIZE) - 20)
368 ent->x = (MAPWIDTH * BRICKSIZE) - 20;