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);
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);
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));
131 collision = (Collision::collision(ent->x, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
139 if (ent->flags & ENT_BULLET)
144 if (ent->flags & ENT_FLIES)
149 if ((ent == &player) && (train->waitsForPlayer()))
151 train->active = true;
154 x = (int)(ent->x + ent->dx) >> BRICKSHIFT;
155 y = (int)(ent->y + ent->height - 1) >> BRICKSHIFT;
157 mapAttribute = map.data[x][y];
159 evaluateMapAttribute(ent, mapAttribute);
167 ent->x -= train->getDX();
174 ent->y -= ent->height;
176 ent->falling = false;
183 if (!(ent->flags & ENT_BULLET))
191 ent->falling = false;
197 case TR_LOCKED_SLIDEDOOR:
198 trainBlockEntity(ent, "Door is locked", train, dir);
203 case TR_GOLD_SLIDEDOOR:
204 if ((ent == &player) && (carryingItem("Gold Key")))
210 trainBlockEntity(ent, "Gold Key Required", train, dir);
216 case TR_SILVER_SLIDEDOOR:
217 if ((ent == &player) && (carryingItem("Silver Key")))
223 trainBlockEntity(ent, "Silver Key Required", train, dir);
229 case TR_BRONZE_SLIDEDOOR:
230 if ((ent == &player) && (carryingItem("Bronze Key")))
236 trainBlockEntity(ent, "Bronze Key Required", train, dir);
248 * Lazy way of setting the sprite for the train
249 * @param train The train to set the Sprite for
251 void setTrainSprite(Train *train)
256 train->sprite = graphics.getSprite("Platform", true);
260 train->sprite = graphics.getSprite("NormalDoor", true);
263 train->sprite = graphics.getSprite("GoldDoor", true);
266 train->sprite = graphics.getSprite("SilverDoor", true);
269 train->sprite = graphics.getSprite("BronzeDoor", true);
272 case TR_LOCKED_SLIDEDOOR:
273 train->sprite = graphics.getSprite("SlideDoor", true);
275 case TR_GOLD_SLIDEDOOR:
276 train->sprite = graphics.getSprite("GoldSlideDoor", true);
278 case TR_SILVER_SLIDEDOOR:
279 train->sprite = graphics.getSprite("SilverSlideDoor", true);
281 case TR_BRONZE_SLIDEDOOR:
282 train->sprite = graphics.getSprite("BronzeSlideDoor", true);
288 * Checks to see if a door has attempted to open or close on the Player
290 * @param train The door to perform the check on
291 * @return Whether an entity was in the path of the door
293 bool doorClosedOnEntity(Train *train)
295 // allow entities to stand on an horizontal moving door without blocking its movement.
296 int y = (train->type < TR_SLIDEDOOR) ? (int)train->y : (int)train->y + 1;
298 if (Collision::collision(player.x, player.y, player.width, player.height, train->x, y, train->width, train->height))
303 Entity *enemy = (Entity*)map.enemyList.getHead();
305 while (enemy->next != NULL)
307 enemy = (Entity*)enemy->next;
309 if (Collision::collision(enemy->x, enemy->y, enemy->width, enemy->height, train->x, y, train->width, train->height))
319 * Peforms actions for all the trains on the level. Moves them, etc.
323 Train *train = (Train*)map.trainList.getHead();
325 int x, y, oldX, oldY;
326 int playSound = false;
328 while (train->next != NULL)
330 train = (Train*)train->next;
332 x = (int)(train->x - engine.playerPosX);
333 y = (int)(train->y - engine.playerPosY);
335 if ((train->type == TR_TRAIN) && (train->active))
340 if (train->type != TR_TRAIN)
342 oldX = (int)train->x;
343 oldY = (int)train->y;
346 playSound = train->openClose();
348 // only check if the door actually moved(!)
349 if ((oldX != (int)train->x) || (oldY != (int)train->y))
351 if (doorClosedOnEntity(train))
358 audio.playSound(SND_DOOROPENED, CH_TOUCH);
363 if (train->sprite == NULL)
365 setTrainSprite(train);
368 if ((abs(x) <= 800) && (abs(y) <= 600))
370 graphics.blit(train->sprite->getCurrentFrame(), x, y, graphics.screen, false);