makefile: support a MinGW cross-compilation environment
[blobwars-mingw.git] / src / entities.cpp
blob5d48ac518a36621aae16f963ddedb60bfd3ce0ef
1 /*
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.
21 #include "entities.h"
23 void throwAndDamageEntity(Entity *ent, int damage, int minDX, int maxDX, int DY)
25 if ((ent == &player) && (game.missionOver > 0))
27 return;
30 if (!(ent->flags & ENT_EXPLODES))
32 audio.playSound(SND_HIT, CH_ANY);
33 for (int i = 0 ; i < 4 ; i++)
35 addBlood(ent, Math::rrand(-5, 5), Math::rrand(-6, -3), i);
38 else
40 audio.playSound(SND_CLANG, CH_ANY);
41 addColorParticles(ent->x, ent->y, Math::rrand(25, 75), -1);
44 if ((ent == &player) && (engine.cheatInvulnerable))
46 if (!ent->immune)
48 ent->health -= damage;
50 return;
53 if (ent == &player)
55 if (!ent->immune)
57 ent->health -= damage;
60 ent->immune = 180;
62 if (player.health <= 0)
64 audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
65 player.health = 0;
68 Math::removeBit(&player.flags, ENT_FLIES);
70 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
72 else
74 ent->health -= damage;
77 ((Math::prand() % 2) == 0) ? ent->dx = -minDX : ent->dx = maxDX;
79 if (ent->dy >= 0)
81 ent->dy = DY;
83 else
85 ent->dy = -DY;
89 bool checkBrickContactX(Entity *ent)
91 int new_ent_x = (int)round((ent->x + ent->dx) * 100) / 100;
92 int ent_y = (int)round(ent->y * 100) / 100;
93 int x1 = new_ent_x >> BRICKSHIFT;
94 int x2 = (new_ent_x + ent->width - 1) >> BRICKSHIFT;
95 int y1 = ent_y >> BRICKSHIFT;
96 int y2 = (ent_y + ent->height - 1) >> BRICKSHIFT;
98 if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
100 return true;
103 int mapAttribute = map.data[x1][y2];
105 evaluateMapAttribute(ent, mapAttribute);
107 if ((ent->flags & ENT_SWIMS) && (mapAttribute == MAP_AIR))
108 return true;
110 if (ent->dx < 0)
112 if ((map.isSolid(x1, y1)) || (map.isSolid(x1, y2)))
114 ent->x = (x1 + 1) * BRICKSIZE;
116 // if (map.isSolid(x1, y2))
117 // {
118 // ent->falling = false;
119 // }
121 return true;
124 else if (ent->dx > 0)
126 if ((map.isSolid(x2, y1)) || (map.isSolid(x2, y2)))
128 ent->x = (x2 * BRICKSIZE) - ent->width;
130 // if (map.isSolid(x1, y2))
131 // {
132 // ent->falling = false;
133 // }
135 return true;
139 return false;
142 bool checkBrickContactY(Entity *ent)
144 int ent_x = (int)round(ent->x * 100) / 100;
145 int new_ent_y = (int)round((ent->y + ent->dy) * 100) / 100;
146 int x1 = ent_x >> BRICKSHIFT;
147 int x2 = (ent_x + ent->width - 1) >> BRICKSHIFT;
148 int y1 = new_ent_y >> BRICKSHIFT;
149 int y2 = (new_ent_y + ent->height - 1) >> BRICKSHIFT;
151 if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
153 return true;
156 int mapAttribute = map.data[x1][y2];
158 if (ent->dy < 0)
160 mapAttribute = map.data[x1][y1];
163 evaluateMapAttribute(ent, mapAttribute);
165 if (ent->flags & ENT_SWIMS)
167 switch (mapAttribute)
169 case MAP_AIR:
170 case MAP_AIR_WALL_1:
171 case MAP_AIR_WALL_2:
172 case MAP_AIR_WALL_3:
173 case MAP_AIR_CEILING_1:
174 return true;
175 case MAP_AIR_WALL_4:
176 if (map.isCavesTileset)
178 return true;
180 break;
181 case MAP_AIR_CEILING_2:
182 if (map.isGrasslandsTileset)
184 return true;
186 break;
190 if (ent->dy < 0)
192 if ((map.isSolid(x1, y1)) || (map.isSolid(x2, y1)))
194 ent->y = (y1 + 1) * BRICKSIZE;
195 ent->falling = false;
197 return true;
200 else if (ent->dy > 0)
202 ent->falling = true;
204 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
206 ent->falling = false;
208 ent->y = (y2 * BRICKSIZE) - ent->height;
210 if ((map.isSolid(x1, y2)) && (!map.isBreakable(x1, y2)) && (!map.isNoReset(x1, y2)))
212 if ((ent == &player) && (player.environment == ENV_AIR))
214 game.setCheckPoint(x1 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
216 if (engine.practice)
218 game.setObjectiveCheckPoint();
223 if ((map.isSolid(x2, y2)) && (!map.isBreakable(x2, y2)) && (!map.isNoReset(x2, y2)))
225 if ((ent == &player) && (player.environment == ENV_AIR))
227 game.setCheckPoint(x2 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
228 if (engine.practice)
230 game.setObjectiveCheckPoint();
235 return true;
239 return false;
242 void moveEntity(Entity *ent)
244 if (ent->owner->flags & ENT_TELEPORTING)
246 int diffX = (abs((int)ent->x - (int)ent->dx) / 20);
247 int diffY = (abs((int)ent->y - (int)ent->dy) / 20);
249 // add teleport particles so we can see where thing are going (no sound)
250 addTeleportParticles(ent->x + Math::prand() % ent->width, ent->y + Math::prand() % ent->height, 3, -1);
252 Math::limitInt(&diffX, 3, 30);
253 Math::limitInt(&diffY, 3, 30);
255 if (ent->x > ent->dx) ent->x -= diffX;
256 if (ent->x < ent->dx) ent->x += diffX;
257 if (ent->y > ent->dy) ent->y -= diffY;
258 if (ent->y < ent->dy) ent->y += diffY;
260 if (Collision::collision(ent->x, ent->y, ent->width, ent->height, ent->dx, ent->dy, ent->width, ent->height))
262 Math::removeBit(&ent->flags, ENT_TELEPORTING);
263 addTeleportParticles(ent->x + (ent->width / 2), ent->y + (ent->height / 2), 25, SND_TELEPORT3);
264 ent->dx = ent->dy = 0;
265 ent->environment = ENV_AIR;
267 if (ent == &player)
269 if (player.flags & ENT_FLIES)
271 player.setSprites(graphics.getSprite("JPBobRight", true), graphics.getSprite("JPBobLeft", true), graphics.getSprite("BobSpin", true));
273 else
275 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
279 // raise to the floor
280 int x1 = (int)ent->x >> BRICKSHIFT;
281 int x2 = ((int)ent->x + ent->width - 1) >> BRICKSHIFT;
282 int y2 = ((int)ent->y + ent->height - 1) >> BRICKSHIFT;
283 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
285 ent->y = (y2 * BRICKSIZE) - ent->height;
288 debug(("%s reappeared at %f:%f\n", ent->name, ent->x, ent->y));
291 return;
294 if (ent->owner != ent)
296 return;
299 ent->falling = true;
301 if (ent != &player)
303 if ((!(ent->flags & ENT_WEIGHTLESS)) && (!(ent->flags & ENT_FLIES)) && (!(ent->flags & ENT_SWIMS)))
305 ent->applyGravity();
308 else if (!(ent->flags & ENT_FLIES))
310 if (ent->environment == ENV_AIR)
312 ent->applyGravity();
314 // This is what makes swimming work:
315 else if ((!config.isControl(CONTROL::UP)) && (!config.isControl(CONTROL::DOWN)))
317 ent->applyGravity();
321 if (ent->dx != 0)
323 if ((checkBrickContactX(ent)) || (checkObstacleContact(ent, 0)) || (checkTrainContact(ent, 0)))
325 ent->dx = 0;
328 ent->x += ent->dx;
330 if (ent->flags & ENT_SLIDES)
332 ent->dx *= 0.98;
336 if (ent->dy != 0)
338 if ((checkBrickContactY(ent)) || (checkObstacleContact(ent, 1)) || (checkTrainContact(ent, 1)))
340 if ((ent->flags & ENT_BOUNCES) && (ent->dy >= 3))
342 ent->dy = (0 - ent->dy / 2);
344 else
346 ent->dy = 0;
350 ent->y += ent->dy;
353 checkSwitchContact(ent);
354 checkTeleportContact(ent);
356 // Math::limitFloat(&ent->x, 10, (MAPWIDTH * BRICKSIZE) - 20);
357 if (ent->x < 10)
359 ent->x = 10;
360 if (ent->dx < 0)
362 ent->dx = 0;
365 else if (ent->x > (MAPWIDTH * BRICKSIZE) - 20)
367 ent->x = (MAPWIDTH * BRICKSIZE) - 20;
368 if (ent->dx > 0)
370 ent->dx = 0;