]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/trains.cpp
Use time_t to store time data.
[quix0rs-blobwars.git] / src / trains.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 "trains.h"
23
24 /**
25 * Opens a door and converts it into a normal door (TR_DOOR)
26 * at the same time. Uses up keys if needed
27 * @param train The door to open.
28 */
29 void openDoor(Train *train)
30 {
31         if (train->active)
32         {
33                 return;
34         }
35
36         switch (train->type)
37         {
38                 case TR_GOLD_DOOR:
39                 case TR_GOLD_SLIDEDOOR:
40                         engine.setInfoMessage("Used Gold Key", 1, INFO_NORMAL);
41                         break;
42                 case TR_SILVER_DOOR:
43                 case TR_SILVER_SLIDEDOOR:
44                         engine.setInfoMessage("Used Silver Key", 1, INFO_NORMAL);
45                         break;
46                 case TR_BRONZE_DOOR:
47                 case TR_BRONZE_SLIDEDOOR:
48                         engine.setInfoMessage("Used Bronze Key", 1, INFO_NORMAL);
49                         break;
50         }
51
52         if ((train->type != TR_LOCKED_DOOR) && (train->type != TR_LOCKED_SLIDEDOOR))
53         {
54                 if (train->type < TR_SLIDEDOOR)
55                 {
56                         train->type = TR_DOOR;
57                 }
58                 else
59                 {
60                         train->type = TR_SLIDEDOOR;
61                 }
62         }
63
64         train->active = true;
65
66         audio.playSound(SND_OPENDOOR, CH_TOUCH, train->x);
67 }
68
69 /**
70 * Blocks an entity from moving any further and shows
71 * a message for the reason the door would not open
72 * @param ent The entity to block
73 * @param message The message to show when blocking the Player
74 * @param train The door that performs the blocking
75 * @param dir The direction the entity was moving in (required for clipping)
76 */
77 void trainBlockEntity(Entity *ent, const char *message, Train *train, int dir)
78 {
79         if (ent == &player)
80         {
81                 if ((train->isReady()) && (!train->active))
82                 {
83                         engine.setInfoMessage(message, 1, INFO_NORMAL);
84                         audio.playSound(SND_LOCKEDDOOR, CH_TOUCH, train->x);
85                 }
86         }
87         
88         if ((ent->flags & ENT_BULLET) && (!(ent->flags & ENT_BOUNCES)))
89         {
90                 if (dir & DIR_X)
91                 {
92                         if (ent->dx < 0) ent->x = train->x + train->sprite->image[0]->w;
93                         if (ent->dx > 0) ent->x = train->x - ent->width;
94                 }
95         }
96
97         if (dir & DIR_Y)
98         {
99                 if ((ent->dy >= 0) && (train->type >= TR_SLIDEDOOR))
100                 {
101                         ent->dy = 0;
102                         ent->falling = false;
103                 }
104         }
105 }
106
107 void getTrainMotion(Entity *ent, int &dx, int &dy)
108 {
109         dx = 0;
110         dy = 0;
111         Train *train = (Train*)map.trainList.getHead();
112         while (train->next != NULL) {
113                 train = (Train*)train->next;
114                 bool collision = (Collision::collision(ent->x, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
115                 if(collision) {
116                         dx = train->getDX();
117                         dy = train->getDY();
118                         break;
119                 }
120         }
121 }
122
123 /**
124 * Checks to see if an entity has touched this train. Depending on
125 * the trains status certain other functions will be invoked
126 * @param ent The entity to test
127 * @param dir The direction the entity was moving in
128 * @return Whether a collision took place
129 */
130 bool checkTrainContact(Entity *ent, int dir)
131 {
132         Train *train = (Train*)map.trainList.getHead();
133
134         bool collision = false;
135         int x, y, mapAttribute;
136
137         while (train->next != NULL)
138         {
139                 train = (Train*)train->next;
140
141                 if (dir == DIR_X)
142                 {
143                         collision = (Collision::collision(ent->x + ent->dx, ent->y, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
144                 }
145                 else if (dir == DIR_Y)
146                 {
147                         collision = (Collision::collision(ent->x, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
148                 }
149                 else
150                 {
151                         collision = (Collision::collision(ent->x + ent->dx, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
152                 }
153
154                 if (collision)
155                 {
156                         switch (train->type)
157                         {
158                                 case TR_TRAIN:
159                                         if (ent->flags & ENT_BULLET)
160                                         {
161                                                 return true;
162                                         }
163                                         
164                                         if (ent->flags & ENT_FLIES)
165                                         {
166                                                 return false;
167                                         }
168
169                                         if ((ent == &player) && (train->waitsForPlayer()))
170                                         {
171                                                 train->active = true;
172                                         }
173
174                                         x = (int)(ent->x + ent->dx) >> BRICKSHIFT;
175                                         y = (int)(ent->y + ent->height - 1) >> BRICKSHIFT;
176
177                                         mapAttribute = map.data[x][y];
178
179                                         evaluateMapAttribute(ent, mapAttribute);
180
181                                         if (ent->dy >= 0)
182                                         {
183                                                 if (train->active)
184                                                 {
185                                                         if (!map.isIceLevel)
186                                                         {
187                                                                 ent->x -= train->getDX();
188                                                         }
189                                                 }
190
191                                                 ent->dy = 1;
192
193                                                 ent->y = train->y;
194                                                 ent->y -= ent->height;
195
196                                                 ent->falling = false;
197                                         }
198
199                                         break;
200
201                                 case TR_DOOR:
202                                 case TR_SLIDEDOOR:
203                                         if (!(ent->flags & ENT_BULLET))
204                                         {
205                                                 openDoor(train);
206                                         }
207                                         
208                                         if (dir & DIR_Y)
209                                         {
210                                                 ent->dy = 0;
211                                                 ent->falling = false;
212                                         }
213                                         return true;
214                                         break;
215
216                                 case TR_LOCKED_DOOR:
217                                 case TR_LOCKED_SLIDEDOOR:
218                                         trainBlockEntity(ent, "Door is locked", train, dir);
219                                         return true;
220                                         break;
221
222                                 case TR_GOLD_DOOR:
223                                 case TR_GOLD_SLIDEDOOR:
224                                         if ((ent == &player) && (carryingItem("Gold Key")))
225                                         {
226                                                 openDoor(train);
227                                         }
228                                         else
229                                         {
230                                                 trainBlockEntity(ent, "Gold Key Required", train, dir);
231                                         }
232                                         return true;
233                                         break;
234
235                                 case TR_SILVER_DOOR:
236                                 case TR_SILVER_SLIDEDOOR:
237                                         if ((ent == &player) && (carryingItem("Silver Key")))
238                                         {
239                                                 openDoor(train);
240                                         }
241                                         else
242                                         {
243                                                 trainBlockEntity(ent, "Silver Key Required", train, dir);
244                                         }
245                                         return true;
246                                         break;
247
248                                 case TR_BRONZE_DOOR:
249                                 case TR_BRONZE_SLIDEDOOR:
250                                         if ((ent == &player) && (carryingItem("Bronze Key")))
251                                         {
252                                                 openDoor(train);
253                                         }
254                                         else
255                                         {
256                                                 trainBlockEntity(ent, "Bronze Key Required", train, dir);
257                                         }
258                                         return true;
259                                         break;
260                         }
261                 }
262         }
263
264         return false;
265 }
266
267 /**
268 * Lazy way of setting the sprite for the train
269 * @param train The train to set the Sprite for
270 */
271 void setTrainSprite(Train *train)
272 {
273         switch (train->type)
274         {
275                 case TR_TRAIN:
276                         train->sprite = graphics.getSprite("Platform", true);
277                         break;
278                 case TR_DOOR:
279                 case TR_LOCKED_DOOR:
280                         train->sprite = graphics.getSprite("NormalDoor", true);
281                         break;
282                 case TR_GOLD_DOOR:
283                         train->sprite = graphics.getSprite("GoldDoor", true);
284                         break;
285                 case TR_SILVER_DOOR:
286                         train->sprite = graphics.getSprite("SilverDoor", true);
287                         break;
288                 case TR_BRONZE_DOOR:
289                         train->sprite = graphics.getSprite("BronzeDoor", true);
290                         break;
291                 case TR_SLIDEDOOR:
292                 case TR_LOCKED_SLIDEDOOR:
293                         train->sprite = graphics.getSprite("SlideDoor", true);
294                         break;
295                 case TR_GOLD_SLIDEDOOR:
296                         train->sprite = graphics.getSprite("GoldSlideDoor", true);
297                         break;
298                 case TR_SILVER_SLIDEDOOR:
299                         train->sprite = graphics.getSprite("SilverSlideDoor", true);
300                         break;
301                 case TR_BRONZE_SLIDEDOOR:
302                         train->sprite = graphics.getSprite("BronzeSlideDoor", true);
303                         break;
304         }
305 }
306
307 /**
308 * Checks to see if a door has attempted to open or close on the Player
309 * or an enemy
310 * @param train The door to perform the check on
311 * @return Whether an entity was in the path of the door
312 */
313 bool doorClosedOnEntity(Train *train)
314 {
315         // allow entities to stand on an horizontal moving door without blocking its movement.
316         int y = (train->type < TR_SLIDEDOOR) ? (int)train->y : (int)train->y + 1;
317         
318         if (Collision::collision(player.x, player.y, player.width, player.height, train->x, y, train->width, train->height))
319         {
320                 return true;
321         }
322         
323         Entity *enemy = (Entity*)map.enemyList.getHead();
324
325         while (enemy->next != NULL)
326         {
327                 enemy = (Entity*)enemy->next;
328                 
329                 if (Collision::collision(enemy->x, enemy->y, enemy->width, enemy->height, train->x, y, train->width, train->height))
330                 {
331                         return true;
332                 }
333         }
334         
335         return false;
336 }
337
338 /**
339 * Peforms actions for all the trains on the level. Moves them, etc.
340 */
341 void doTrains()
342 {
343         Train *train = (Train*)map.trainList.getHead();
344
345         int x, y, oldX, oldY;
346         int playSound = false;
347
348         while (train->next != NULL)
349         {
350                 train = (Train*)train->next;
351
352                 x = (int)(train->x - engine.playerPosX);
353                 y = (int)(train->y - engine.playerPosY);
354
355                 if ((train->type == TR_TRAIN) && (train->active))
356                 {
357                         train->move();
358                 }
359
360                 if (train->type != TR_TRAIN)
361                 {
362                         oldX = (int)train->x;
363                         oldY = (int)train->y;
364                         
365                         playSound = train->openClose();
366                         
367                         // only check if the door actually moved(!)
368                         if ((oldX != (int)train->x) || (oldY != (int)train->y))
369                         {
370                                 if (doorClosedOnEntity(train))
371                                 {
372                                         train->x = oldX;
373                                         train->y = oldY;
374                                 }
375                                 else if (playSound)
376                                 {
377                                         audio.playSound(SND_DOOROPENED, CH_TOUCH, train->x);
378                                 }
379                         }
380                 }
381
382                 if (train->sprite == NULL)
383                 {
384                         setTrainSprite(train);
385                 }
386
387                 if (train->sprite && (abs(x) <= 800) && (abs(y) <= 600))
388                 {
389                         graphics.blit(train->sprite->getCurrentFrame(), x, y, graphics.screen, false);
390                 }
391         }
392 }