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;
107 void getTrainMotion(Entity *ent, int &dx, int &dy)
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));
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
130 bool checkTrainContact(Entity *ent, int dir)
132 Train *train = (Train*)map.trainList.getHead();
134 bool collision = false;
135 int x, y, mapAttribute;
137 while (train->next != NULL)
139 train = (Train*)train->next;
143 collision = (Collision::collision(ent->x + ent->dx, ent->y, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
145 else if (dir == DIR_Y)
147 collision = (Collision::collision(ent->x, ent->y + ent->dy, ent->width, ent->height - 1, train->x, train->y, train->width, train->height));
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));
159 if (ent->flags & ENT_BULLET)
164 if (ent->flags & ENT_FLIES)
169 if ((ent == &player) && (train->waitsForPlayer()))
171 train->active = true;
174 x = (int)(ent->x + ent->dx) >> BRICKSHIFT;
175 y = (int)(ent->y + ent->height - 1) >> BRICKSHIFT;
177 mapAttribute = map.data[x][y];
179 evaluateMapAttribute(ent, mapAttribute);
187 ent->x -= train->getDX();
194 ent->y -= ent->height;
196 ent->falling = false;
203 if (!(ent->flags & ENT_BULLET))
211 ent->falling = false;
217 case TR_LOCKED_SLIDEDOOR:
218 trainBlockEntity(ent, "Door is locked", train, dir);
223 case TR_GOLD_SLIDEDOOR:
224 if ((ent == &player) && (carryingItem("Gold Key")))
230 trainBlockEntity(ent, "Gold Key Required", train, dir);
236 case TR_SILVER_SLIDEDOOR:
237 if ((ent == &player) && (carryingItem("Silver Key")))
243 trainBlockEntity(ent, "Silver Key Required", train, dir);
249 case TR_BRONZE_SLIDEDOOR:
250 if ((ent == &player) && (carryingItem("Bronze Key")))
256 trainBlockEntity(ent, "Bronze Key Required", train, dir);
268 * Lazy way of setting the sprite for the train
269 * @param train The train to set the Sprite for
271 void setTrainSprite(Train *train)
276 train->sprite = graphics.getSprite("Platform", true);
280 train->sprite = graphics.getSprite("NormalDoor", true);
283 train->sprite = graphics.getSprite("GoldDoor", true);
286 train->sprite = graphics.getSprite("SilverDoor", true);
289 train->sprite = graphics.getSprite("BronzeDoor", true);
292 case TR_LOCKED_SLIDEDOOR:
293 train->sprite = graphics.getSprite("SlideDoor", true);
295 case TR_GOLD_SLIDEDOOR:
296 train->sprite = graphics.getSprite("GoldSlideDoor", true);
298 case TR_SILVER_SLIDEDOOR:
299 train->sprite = graphics.getSprite("SilverSlideDoor", true);
301 case TR_BRONZE_SLIDEDOOR:
302 train->sprite = graphics.getSprite("BronzeSlideDoor", true);
308 * Checks to see if a door has attempted to open or close on the Player
310 * @param train The door to perform the check on
311 * @return Whether an entity was in the path of the door
313 bool doorClosedOnEntity(Train *train)
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;
318 if (Collision::collision(player.x, player.y, player.width, player.height, train->x, y, train->width, train->height))
323 Entity *enemy = (Entity*)map.enemyList.getHead();
325 while (enemy->next != NULL)
327 enemy = (Entity*)enemy->next;
329 if (Collision::collision(enemy->x, enemy->y, enemy->width, enemy->height, train->x, y, train->width, train->height))
339 * Peforms actions for all the trains on the level. Moves them, etc.
343 Train *train = (Train*)map.trainList.getHead();
345 int x, y, oldX, oldY;
346 int playSound = false;
348 while (train->next != NULL)
350 train = (Train*)train->next;
352 x = (int)(train->x - engine.playerPosX);
353 y = (int)(train->y - engine.playerPosY);
355 if ((train->type == TR_TRAIN) && (train->active))
360 if (train->type != TR_TRAIN)
362 oldX = (int)train->x;
363 oldY = (int)train->y;
365 playSound = train->openClose();
367 // only check if the door actually moved(!)
368 if ((oldX != (int)train->x) || (oldY != (int)train->y))
370 if (doorClosedOnEntity(train))
377 audio.playSound(SND_DOOROPENED, CH_TOUCH, train->x);
382 if (train->sprite == NULL)
384 setTrainSprite(train);
387 if (train->sprite && (abs(x) <= 800) && (abs(y) <= 600))
389 graphics.blit(train->sprite->getCurrentFrame(), x, y, graphics.screen, false);