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