summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/train_cmd.cpp118
1 files changed, 69 insertions, 49 deletions
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index ca5accc28..8bcb99791 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -3250,14 +3250,59 @@ static const byte _breakdown_speeds[16] = {
225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
};
+
+/**
+ * Train is approaching line end, slow down and possibly reverse
+ *
+ * @param v front train engine
+ * @param signal not line end, just a red signal
+ * @return true iff we did NOT have to reverse
+ */
+static bool TrainApproachingLineEnd(Vehicle *v, bool signal)
+{
+ /* Calc position within the current tile */
+ uint x = v->x_pos & 0xF;
+ uint y = v->y_pos & 0xF;
+
+ switch (v->direction) {
+ case DIR_N : x = ~x + ~y + 24; break;
+ case DIR_NW: x = y; /* FALLTHROUGH */
+ case DIR_NE: x = ~x + 16; break;
+ case DIR_E : x = ~x + y + 8; break;
+ case DIR_SE: x = y; break;
+ case DIR_S : x = x + y - 8; break;
+ case DIR_W : x = ~y + x + 8; break;
+ default: break;
+ }
+
+ /* do not reverse when approaching red signal */
+ if (!signal && x + 4 >= TILE_SIZE) {
+ /* we are too near the tile end, reverse now */
+ v->cur_speed = 0;
+ ReverseTrainDirection(v);
+ return false;
+ }
+
+ /* slow down */
+ v->vehstatus |= VS_TRAIN_SLOWING;
+ uint16 break_speed = _breakdown_speeds[x & 0xF];
+ if (!(v->direction & 1)) break_speed >>= 1;
+ if (break_speed < v->cur_speed) v->cur_speed = break_speed;
+
+ return true;
+}
+
+
/**
* Checks for line end. Also, bars crossing at next tile if needed
*
* @param v vehicle we are checking
- * @return true iff we do NOT have to reverse
+ * @return true iff we did NOT have to reverse
*/
static bool TrainCheckIfLineEnds(Vehicle *v)
{
+ /* First, handle broken down train */
+
int t = v->breakdown_ctr;
if (t > 1) {
v->vehstatus |= VS_TRAIN_SLOWING;
@@ -3268,17 +3313,19 @@ static bool TrainCheckIfLineEnds(Vehicle *v)
v->vehstatus &= ~VS_TRAIN_SLOWING;
}
- if (v->u.rail.track == TRACK_BIT_WORMHOLE) return true; // exit if inside a tunnel
- if (v->u.rail.track == TRACK_BIT_DEPOT) return true; // exit if inside a depot
+ /* Exit if inside a tunnel/bridge or a depot */
+ if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return true;
TileIndex tile = v->tile;
+ /* entering a tunnel/bridge? */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
DiagDirection dir = GetTunnelBridgeDirection(tile);
if (DiagDirToDir(dir) == v->direction) return true;
}
- if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT) {
+ /* entering a depot? */
+ if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile));
if (DiagDirToDir(dir) == v->direction) return true;
}
@@ -3287,61 +3334,34 @@ static bool TrainCheckIfLineEnds(Vehicle *v)
DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
/* Calculate next tile */
tile += TileOffsByDiagDir(dir);
- // determine the track status on the next tile.
+
+ /* Determine the track status on the next tile */
uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir];
- /* Calc position within the current tile ?? */
- uint x = v->x_pos & 0xF;
- uint y = v->y_pos & 0xF;
+ /* We are sure the train is not entering a depot, it is detected above */
- switch (v->direction) {
- case DIR_N : x = ~x + ~y + 24; break;
- case DIR_NW: x = y; /* FALLTHROUGH */
- case DIR_NE: x = ~x + 16; break;
- case DIR_E : x = ~x + y + 8; break;
- case DIR_SE: x = y; break;
- case DIR_S : x = x + y - 8; break;
- case DIR_W : x = ~y + x + 8; break;
- default: break;
+ /* no suitable trackbits at all || wrong railtype || not our track ||
+ * tunnel/bridge from opposite side || depot from opposite side */
+ if (GB(ts, 0, 16) == 0 || !CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner ||
+ (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) ||
+ (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) == dir) ) {
+ return TrainApproachingLineEnd(v, false);
}
- if (GB(ts, 0, 16) != 0) {
- /* If we approach a rail-piece which we can't enter, or the back of a depot, don't enter it! */
- if (x + 4 >= TILE_SIZE &&
- (!CheckCompatibleRail(v, tile) ||
- (IsTileDepotType(tile, TRANSPORT_RAIL) &&
- GetRailDepotDirection(tile) == dir))) {
- v->cur_speed = 0;
- ReverseTrainDirection(v);
- return false;
- }
- if ((ts &= (ts >> 16)) == 0) {
- /* make a rail/road crossing red
- * do not make crossing red behind depot the train is entering */
- if (IsLevelCrossingTile(tile) && (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || GetRailDepotDirection(v->tile) == dir)) {
- if (!IsCrossingBarred(tile)) {
- BarCrossing(tile);
- SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
- MarkTileDirtyByTile(tile);
- }
- }
- return true;
- }
- } else if (x + 4 >= TILE_SIZE) {
- v->cur_speed = 0;
- ReverseTrainDirection(v);
- return false;
- }
+ /* approaching red signal */
+ if ((ts & (ts >> 16)) != 0) return TrainApproachingLineEnd(v, true);
- /* slow down */
- v->vehstatus |= VS_TRAIN_SLOWING;
- uint16 break_speed = _breakdown_speeds[x & 0xF];
- if (!(v->direction & 1)) break_speed >>= 1;
- if (break_speed < v->cur_speed) v->cur_speed = break_speed;
+ /* approaching a rail/road crossing? then make it red */
+ if (IsLevelCrossingTile(tile) && !IsCrossingBarred(tile)) {
+ BarCrossing(tile);
+ SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
+ MarkTileDirtyByTile(tile);
+ }
return true;
}
+
static void TrainLocoHandler(Vehicle *v, bool mode)
{
/* train has crashed? */