diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 024fd620d6..f88090ad2f 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -78,6 +78,44 @@ const byte _track_sloped_sprites[14] = { * 11uuuudd => rail depot */ +/** Struct used in EnsureNoTrainOnTrack() */ +struct TrainOnTrackData { + TileIndex tile; ///< tile to check + uint z; ///< tile max Z + TrackBits rail_bits; ///< trackbits of interest +}; + +static void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) +{ + const TrainOnTrackData *info = (const TrainOnTrackData *)data; + + if (v->tile != info->tile || v->type != VEH_TRAIN) return NULL; + if (v->z_pos > info->z) return NULL; + + if ((v->u.rail.track != info->rail_bits) && !TracksOverlap(v->u.rail.track | info->rail_bits)) return NULL; + + _error_message = VehicleInTheWayErrMsg(v); + return v; +} + +/** + * Tests if a vehicle interacts with the specified track. + * All track bits interact except parallel TRACK_BIT_HORZ or TRACK_BIT_VERT. + * + * @param tile The tile. + * @param track The track. + */ +static bool EnsureNoTrainOnTrack(TileIndex tile, Track track) +{ + TrainOnTrackData info; + + info.tile = tile; + info.z = GetTileMaxZ(tile); + info.rail_bits = TrackToTrackBits(track); + + return VehicleFromPos(tile, &info, EnsureNoTrainOnTrackProc) == NULL; +} + static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) { TrackBits current; // The current track layout @@ -239,7 +277,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p switch (GetTileType(tile)) { case MP_RAILWAY: if (!CheckTrackCombination(tile, trackbit, flags) || - !EnsureNoVehicleOnGround(tile)) { + !EnsureNoTrainOnTrack(tile, track)) { return CMD_ERROR; } if (!IsTileOwner(tile, _current_player) || @@ -374,7 +412,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 if (!IsPlainRailTile(tile) || (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) || - !EnsureNoVehicleOnGround(tile)) { + !EnsureNoTrainOnTrack(tile, track)) { return CMD_ERROR; } @@ -647,7 +685,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 SignalVariant sigvar = (pre_signal ^ HASBIT(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; CommandCost cost; - if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicleOnGround(tile)) + if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoTrainOnTrack(tile, track)) return CMD_ERROR; /* Protect against invalid signal copying */ @@ -935,7 +973,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint3 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || - !EnsureNoVehicleOnGround(tile) || + !EnsureNoTrainOnTrack(tile, track) || !HasSignalOnTrack(tile, track)) { return CMD_ERROR; }