diff options
-rw-r--r-- | src/train_cmd.cpp | 118 |
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? */ |