]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/entities.cpp
cf29c2b02a6924f3863ce434f9dfc9aea320324e
[quix0rs-blobwars.git] / src / entities.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include "entities.h"
22
23 void throwAndDamageEntity(Entity *ent, int damage, int minDX, int maxDX, int DY)
24 {
25         if ((ent == &player) && (game.missionOver > 0))
26         {
27                 return;
28         }
29
30         if (!(ent->flags & ENT_EXPLODES))
31         {
32                 audio.playSound(SND_HIT, CH_ANY);
33                 for (int i = 0 ; i < 4 ; i++)
34                 {
35                         addBlood(ent, Math::rrand(-5, 5), Math::rrand(-6, -3), i);
36                 }
37         }
38         else
39         {
40                 audio.playSound(SND_CLANG, CH_ANY);
41                 addColorParticles(ent->x, ent->y, Math::rrand(25, 75), -1);
42         }
43
44         if ((ent == &player) && (engine.cheatInvulnerable))
45         {
46                 if (!ent->immune)
47                 {
48                         ent->health -= damage;
49                 }
50                 return;
51         }
52
53         if (ent == &player)
54         {
55                 if (!ent->immune)
56                 {
57                         ent->health -= damage;
58                 }
59
60                 ent->immune = 180;
61
62                 if (player.health <= 0)
63                 {
64                         audio.playSound(SND_DEATH1 + Math::prand() % 3, CH_DEATH);
65                         player.health = 0;
66                 }
67
68                 Math::removeBit(&player.flags, ENT_FLIES);
69                 
70                 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
71         }
72         else
73         {
74                 ent->health -= damage;
75         }
76
77         ((Math::prand() % 2) == 0) ? ent->dx = -minDX : ent->dx = maxDX;
78         
79         if (ent->dy >= 0)
80         {
81                 ent->dy = DY;
82         }
83         else
84         {
85                 ent->dy = -DY;
86         }
87 }
88
89 bool checkBrickContactX(Entity *ent)
90 {
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;
97         
98         if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
99         {
100                 return true;
101         }
102
103         int mapAttribute = map.data[x1][y2];
104
105         evaluateMapAttribute(ent, mapAttribute);
106
107         if ((ent->flags & ENT_SWIMS) && (mapAttribute == MAP_AIR))
108                 return true;
109
110         if (ent->dx < 0)
111         {
112                 if ((map.isSolid(x1, y1)) || (map.isSolid(x1, y2)))
113                 {
114                         ent->x = (x1 + 1) * BRICKSIZE;
115
116 //                      if (map.isSolid(x1, y2))
117 //                      {
118 //                              ent->falling = false;
119 //                      }
120
121                         return true;
122                 }
123         }
124         else if (ent->dx > 0)
125         {
126                 if ((map.isSolid(x2, y1)) || (map.isSolid(x2, y2)))
127                 {
128                         ent->x = (x2 * BRICKSIZE) - ent->width;
129
130 //                      if (map.isSolid(x1, y2))
131 //                      {
132 //                              ent->falling = false;
133 //                      }
134
135                         return true;
136                 }
137         }
138
139         return false;
140 }
141
142 bool checkBrickContactY(Entity *ent)
143 {
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;
150         
151         if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0))
152         {
153                 return true;
154         }
155
156         int mapAttribute = map.data[x1][y2];
157         
158         if (ent->dy < 0)
159         {
160                 mapAttribute = map.data[x1][y1];
161         }
162
163         evaluateMapAttribute(ent, mapAttribute);
164         
165         if (ent->flags & ENT_SWIMS)
166         {
167                 switch (mapAttribute)
168                 {
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)
177                                 {
178                                         return true;
179                                 }
180                                 break;
181                         case MAP_AIR_CEILING_2:
182                                 if (map.isGrasslandsTileset)
183                                 {
184                                         return true;
185                                 }
186                                 break;
187                 }
188         }
189
190         if (ent->dy < 0)
191         {
192                 if ((map.isSolid(x1, y1)) || (map.isSolid(x2, y1)))
193                 {
194                         ent->y = (y1 + 1) * BRICKSIZE;
195                         ent->falling = false;
196
197                         return true;
198                 }
199         }
200         else if (ent->dy > 0)
201         {
202                 ent->falling = true;
203                 
204                 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
205                 {               
206                         ent->falling = false;
207                         
208                         ent->y = (y2 * BRICKSIZE) - ent->height;
209                         
210                         if ((map.isSolid(x1, y2)) && (!map.isBreakable(x1, y2)) && (!map.isNoReset(x1, y2)))
211                         {
212                                 if ((ent == &player) && (player.environment == ENV_AIR))
213                                 {
214                                         game.setCheckPoint(x1 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
215                                         
216                                         if (engine.practice)
217                                         {
218                                                 game.setObjectiveCheckPoint();
219                                         }
220                                 }
221                         }
222
223                         if ((map.isSolid(x2, y2)) && (!map.isBreakable(x2, y2)) && (!map.isNoReset(x2, y2)))
224                         {         
225                                 if ((ent == &player) && (player.environment == ENV_AIR))
226                                 {
227                                         game.setCheckPoint(x2 * BRICKSIZE, (y2 * BRICKSIZE) - BRICKSIZE);
228                                         if (engine.practice)
229                                         {
230                                                 game.setObjectiveCheckPoint();  
231                                         }
232                                 }
233                         }
234
235                         return true;
236                 }
237         }
238
239         return false;
240 }
241
242 void moveEntity(Entity *ent)
243 {
244         if (ent->owner->flags & ENT_TELEPORTING)
245         {
246                 int diffX = (abs((int)ent->x - (int)ent->dx) / 20);
247                 int diffY = (abs((int)ent->y - (int)ent->dy) / 20);
248
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);
251
252                 Math::limitInt(&diffX, 3, 30);
253                 Math::limitInt(&diffY, 3, 30);
254
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;
259
260                 if (Collision::collision(ent->x, ent->y, ent->width, ent->height, ent->dx, ent->dy, ent->width, ent->height))
261                 {
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;
266                         
267                         if (ent == &player)
268                         {
269                                 if (player.flags & ENT_FLIES)
270                                 {
271                                         player.setSprites(graphics.getSprite("JPBobRight", true), graphics.getSprite("JPBobLeft", true), graphics.getSprite("BobSpin", true));
272                                 }
273                                 else
274                                 {
275                                         player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
276                                 }
277                         }
278                         
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)))
284                         {
285                                 ent->y = (y2 * BRICKSIZE) - ent->height;
286                         }
287
288                         debug(("%s reappeared at %f:%f\n", ent->name, ent->x, ent->y));
289                 }
290
291                 return;
292         }
293
294         if (ent->owner != ent)
295         {
296                 return;
297         }
298                 
299         ent->falling = true;
300         
301         if (ent != &player)
302         {
303                 if ((!(ent->flags & ENT_WEIGHTLESS)) && (!(ent->flags & ENT_FLIES)) && (!(ent->flags & ENT_SWIMS)))
304                 {
305                         ent->applyGravity();
306                 }
307         }
308         else if (!(ent->flags & ENT_FLIES))
309         {
310                 if (ent->environment == ENV_AIR)
311                 {
312                         ent->applyGravity();
313                 }
314                 // This is what makes swimming work:
315                 else if ((!config.isControl(CONTROL::UP)) && (!config.isControl(CONTROL::JUMP))  && (!config.isControl(CONTROL::DOWN)))
316                 {
317                         ent->applyGravity();
318                 }
319         }
320
321         if (ent->dx != 0)
322         {               
323                 if ((checkBrickContactX(ent)) || (checkObstacleContact(ent, 0)) || (checkTrainContact(ent, 0)))
324                 {
325                         ent->dx = 0;
326                 }
327
328                 ent->x += ent->dx;
329
330                 if (ent->flags & ENT_SLIDES)
331                 {
332                         ent->dx *= 0.98;
333                 }
334         }
335
336         if (ent->dy != 0)
337         {
338                 if ((checkBrickContactY(ent)) || (checkObstacleContact(ent, 1)) || (checkTrainContact(ent, 1)))
339                 {
340                         if ((ent->flags & ENT_BOUNCES) && (ent->dy >= 3))
341                         {
342                                 ent->dy = (0 - ent->dy / 2);
343                         }
344                         else
345                         {
346                                 ent->dy = 0;
347                         }
348                 }
349                 
350                 ent->y += ent->dy;
351         }
352         
353         checkSwitchContact(ent);
354         checkTeleportContact(ent);
355
356 //      Math::limitFloat(&ent->x, 10, (MAPWIDTH * BRICKSIZE) - 20);
357         if (ent->x < 10)
358         {
359                 ent->x = 10;
360                 if (ent->dx < 0)
361                 {
362                         ent->dx = 0;
363                 }
364         }
365         else if (ent->x > (MAPWIDTH * BRICKSIZE) - 20)
366         {
367                 ent->x = (MAPWIDTH * BRICKSIZE) - 20;
368                 if (ent->dx > 0)
369                 {
370                         ent->dx = 0;
371                 }
372         }
373 }