2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
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.
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.
14 See the GNU General Public License for more details.
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.
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.
29 void openDoor(Train *train)
39 case TR_GOLD_SLIDEDOOR:
40 engine.setInfoMessage("Used Gold Key", 1, INFO_NORMAL);
43 case TR_SILVER_SLIDEDOOR:
44 engine.setInfoMessage("Used Silver Key", 1, INFO_NORMAL);
47 case TR_BRONZE_SLIDEDOOR:
48 engine.setInfoMessage("Used Bronze Key", 1, INFO_NORMAL);
52 if ((train->type != TR_LOCKED_DOOR) && (train->type != TR_LOCKED_SLIDEDOOR))
54 if (train->type < TR_SLIDEDOOR)
56 train->type = TR_DOOR;
60 train->type = TR_SLIDEDOOR;
66 audio.playSound(SND_OPENDOOR, CH_TOUCH, train->x);
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)
77 void trainBlockEntity(Entity *ent, const char *message, Train *train, int dir)
81 if ((train->isReady()) && (!train->active))
83 engine.setInfoMessage(message, 1, INFO_NORMAL);
84 audio.playSound(SND_LOCKEDDOOR, CH_TOUCH, train->x);
88 if ((ent->flags & ENT_BULLET) && (!(ent->flags & ENT_BOUNCES)))
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;
99 if ((ent->dy >= 0) && (train->type >= TR_SLIDEDOOR))
102 ent->falling = false;
108 * Checks to see if an entity has touched this train. Depending on
109 * the trains status certain other functions will be invoked
110 * @param ent The entity to test
111 * @param dir The direction the entity was moving in
112 * @return Whether a collision took place
114 bool checkTrainContact(Entity *ent, int dir)
116 Train *train = (Train*)map.trainList.getHead();
118 bool collision = false;
119 int x, y, mapAttribute;
121 while (train->next != NULL)
123 train = (Train*)train->next;
127 collision = (Collision::collision(ent->x + ent->dx, ent->y, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
129 else if (dir == DIR_Y)
131 collision = (Collision::collision(ent->x, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
135 collision = (Collision::collision(ent->x + ent->dx, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
143 if (ent->flags & ENT_BULLET)
148 if (ent->flags & ENT_FLIES)
153 if ((ent == &player) && (train->waitsForPlayer()))
155 train->active = true;
158 x = (int)(ent->x + ent->dx) >> BRICKSHIFT;
159 y = (int)(ent->y + ent->height - 1) >> BRICKSHIFT;
161 mapAttribute = map.data[x][y];
163 evaluateMapAttribute(ent, mapAttribute);
171 ent->x -= train->getDX();
178 ent->y -= ent->height;
180 ent->falling = false;
187 if (!(ent->flags & ENT_BULLET))
195 ent->falling = false;
201 case TR_LOCKED_SLIDEDOOR:
202 trainBlockEntity(ent, "Door is locked", train, dir);
207 case TR_GOLD_SLIDEDOOR:
208 if ((ent == &player) && (carryingItem("Gold Key")))
214 trainBlockEntity(ent, "Gold Key Required", train, dir);
220 case TR_SILVER_SLIDEDOOR:
221 if ((ent == &player) && (carryingItem("Silver Key")))
227 trainBlockEntity(ent, "Silver Key Required", train, dir);
233 case TR_BRONZE_SLIDEDOOR:
234 if ((ent == &player) && (carryingItem("Bronze Key")))
240 trainBlockEntity(ent, "Bronze Key Required", train, dir);
252 * Lazy way of setting the sprite for the train
253 * @param train The train to set the Sprite for
255 void setTrainSprite(Train *train)
260 train->sprite = graphics.getSprite("Platform", true);
264 train->sprite = graphics.getSprite("NormalDoor", true);
267 train->sprite = graphics.getSprite("GoldDoor", true);
270 train->sprite = graphics.getSprite("SilverDoor", true);
273 train->sprite = graphics.getSprite("BronzeDoor", true);
276 case TR_LOCKED_SLIDEDOOR:
277 train->sprite = graphics.getSprite("SlideDoor", true);
279 case TR_GOLD_SLIDEDOOR:
280 train->sprite = graphics.getSprite("GoldSlideDoor", true);
282 case TR_SILVER_SLIDEDOOR:
283 train->sprite = graphics.getSprite("SilverSlideDoor", true);
285 case TR_BRONZE_SLIDEDOOR:
286 train->sprite = graphics.getSprite("BronzeSlideDoor", true);
292 * Checks to see if a door has attempted to open or close on the Player
294 * @param train The door to perform the check on
295 * @return Whether an entity was in the path of the door
297 bool doorClosedOnEntity(Train *train)
299 // allow entities to stand on an horizontal moving door without blocking its movement.
300 int y = (train->type < TR_SLIDEDOOR) ? (int)train->y : (int)train->y + 1;
302 if (Collision::collision(player.x, player.y, player.width, player.height, train->x, y, train->width, train->height))
307 Entity *enemy = (Entity*)map.enemyList.getHead();
309 while (enemy->next != NULL)
311 enemy = (Entity*)enemy->next;
313 if (Collision::collision(enemy->x, enemy->y, enemy->width, enemy->height, train->x, y, train->width, train->height))
323 * Peforms actions for all the trains on the level. Moves them, etc.
327 Train *train = (Train*)map.trainList.getHead();
329 int x, y, oldX, oldY;
330 int playSound = false;
332 while (train->next != NULL)
334 train = (Train*)train->next;
336 x = (int)(train->x - engine.playerPosX);
337 y = (int)(train->y - engine.playerPosY);
339 if ((train->type == TR_TRAIN) && (train->active))
344 if (train->type != TR_TRAIN)
346 oldX = (int)train->x;
347 oldY = (int)train->y;
350 playSound = train->openClose();
352 // only check if the door actually moved(!)
353 if ((oldX != (int)train->x) || (oldY != (int)train->y))
355 if (doorClosedOnEntity(train))
362 audio.playSound(SND_DOOROPENED, CH_TOUCH, train->x);
367 if (train->sprite == NULL)
369 setTrainSprite(train);
372 if ((abs(x) <= 800) && (abs(y) <= 600))
374 graphics.blit(train->sprite->getCurrentFrame(), x, y, graphics.screen, false);