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