diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp index 71a171c665..3657e7f6eb 100644 --- a/src/terraform_cmd.cpp +++ b/src/terraform_cmd.cpp @@ -270,7 +270,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin } } /* Check if tunnel would take damage */ - if (direction == -1 && IsTunnelInWay(tile, z_min, true)) { + if (direction == -1 && IsTunnelInWay(tile, z_min, ITIWF_IGNORE_CHUNNEL)) { _terraform_err_tile = tile; // highlight the tile above the tunnel return_cmd_error(STR_ERROR_EXCAVATION_WOULD_DAMAGE); } diff --git a/src/tunnel_map.cpp b/src/tunnel_map.cpp index 7b546848a4..b679bc0e00 100644 --- a/src/tunnel_map.cpp +++ b/src/tunnel_map.cpp @@ -103,14 +103,17 @@ TileIndex GetOtherTunnelEnd(TileIndex tile) return t->tile_n == tile ? t->tile_s : t->tile_n; } -static inline bool IsTunnelInWaySingleAxis(TileIndex tile, int z, bool chunnel_allowed, bool y_axis, TileIndexDiff tile_diff) +static inline bool IsTunnelInWaySingleAxis(TileIndex tile, int z, IsTunnelInWayFlags flags, bool y_axis, TileIndexDiff tile_diff) { const auto tunnels = tunnel_axis_height_index.equal_range(GetTunnelAxisHeightCacheKey(tile, z, y_axis)); for (auto it = tunnels.first; it != tunnels.second; ++it) { const Tunnel *t = it->second; if (t->tile_n > tile || tile > t->tile_s) continue; - if (t->is_chunnel && chunnel_allowed) { + if (!t->is_chunnel && (flags & ITIWF_CHUNNEL_ONLY)) { + continue; + } + if (t->is_chunnel && (flags & ITIWF_IGNORE_CHUNNEL)) { /* Only if tunnel was built over water is terraforming is allowed between portals. */ const TileIndexDiff delta = tile_diff * 4; // 4 tiles ramp. if (tile < t->tile_n + delta || t->tile_s - delta < tile) return true; @@ -128,7 +131,7 @@ static inline bool IsTunnelInWaySingleAxis(TileIndex tile, int z, bool chunnel_a * @param chunnel_allowed True if chunnel mid-parts are allowed, used when terraforming. * @return true if and only if there is a tunnel. */ -bool IsTunnelInWay(TileIndex tile, int z, bool chunnel_allowed) +bool IsTunnelInWay(TileIndex tile, int z, IsTunnelInWayFlags flags) { - return IsTunnelInWaySingleAxis(tile, z, chunnel_allowed, false, 1) || IsTunnelInWaySingleAxis(tile, z, chunnel_allowed, true, TileOffsByDiagDir(DIAGDIR_SE)); + return IsTunnelInWaySingleAxis(tile, z, flags, false, 1) || IsTunnelInWaySingleAxis(tile, z, flags, true, TileOffsByDiagDir(DIAGDIR_SE)); } diff --git a/src/tunnel_map.h b/src/tunnel_map.h index 41102cb27e..875775eff4 100644 --- a/src/tunnel_map.h +++ b/src/tunnel_map.h @@ -56,7 +56,16 @@ static inline TunnelID GetTunnelIndex(TileIndex t) } TileIndex GetOtherTunnelEnd(TileIndex); -bool IsTunnelInWay(TileIndex, int z, bool chunnel_allowed = false); + +/** Flags for miscellaneous industry tile specialities */ +enum IsTunnelInWayFlags { + ITIWF_NONE = 0, + ITIWF_IGNORE_CHUNNEL = 1 << 0, ///< Chunnel mid-parts are ignored, used when terraforming. + ITIWF_CHUNNEL_ONLY = 1 << 1, ///< Only check for chunnels +}; +DECLARE_ENUM_AS_BIT_SET(IsTunnelInWayFlags) + +bool IsTunnelInWay(TileIndex, int z, IsTunnelInWayFlags flags = ITIWF_NONE); /** * Set the index of tunnel tile. diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index f9a91535b5..f86a3e84a3 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -740,7 +740,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, head_tiles = 0; found_tunnel_tile = INVALID_TILE; } - if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z, true)) { + if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z, ITIWF_IGNORE_CHUNNEL)) { if (found_tunnel_tile == INVALID_TILE || is_chunnel) { // Remember the first or the last when we pass a tunnel. found_tunnel_tile = end_tile; head_tiles = 0; @@ -749,6 +749,26 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, head_tiles++; tiles++; } + + if (is_chunnel && !_cheats.crossing_tunnels.value) { + /* + * Chunnel check: second pass + * + * Make sure that we don't intersect with any other chunnels + */ + + TileIndex check_tile = start_tile; + for (;;) { + check_tile += delta; + if (check_tile == end_tile) break; + + if (IsTunnelInWay(check_tile, start_z, ITIWF_CHUNNEL_ONLY)) { + _build_tunnel_endtile = check_tile; + return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY); + } + } + } + /* The cost of the digging. */ for (int i = tiles; i > 0; i--) { if (tiles == tiles_bump) {