1 /* $Id: tunnel_map.cpp 23167 2011-11-08 19:44:41Z rubidium $ */
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file tunnel_map.cpp Map accessors for tunnels. */
13 #include "tunnelbridge_map.h"
15 #include "core/pool_func.hpp"
17 #include <unordered_map>
19 #include "safeguards.h"
21 /** All tunnel portals tucked away in a pool. */
22 TunnelPool
_tunnel_pool("Tunnel");
23 INSTANTIATE_POOL_METHODS(Tunnel
)
25 static std::unordered_map
<TileIndex
, TunnelID
> tunnel_tile_index_map
;
26 static std::unordered_multimap
<uint64
, Tunnel
*> tunnel_axis_height_index
;
28 static uint64
GetTunnelAxisHeightCacheKey(TileIndex tile
, uint8 height
, bool y_axis
) {
30 // tunnel extends along Y axis (DIAGDIR_SE from north end), has same X values
31 return TileX(tile
) | (((uint64
) height
) << 24) | (((uint64
) 1) << 32);
33 // tunnel extends along X axis (DIAGDIR_SW from north end), has same Y values
34 return TileY(tile
) | (((uint64
) height
) << 24);
38 static inline uint64
GetTunnelAxisHeightCacheKey(const Tunnel
* t
) {
39 return GetTunnelAxisHeightCacheKey(t
->tile_n
, t
->height
, t
->tile_s
- t
->tile_n
> MapMaxX());
43 * Clean up a tunnel tile
47 if (CleaningPool()) return;
49 if (this->index
>= TUNNEL_ID_MAP_LOOKUP
) {
50 tunnel_tile_index_map
.erase(this->tile_n
);
51 tunnel_tile_index_map
.erase(this->tile_s
);
54 auto range
= tunnel_axis_height_index
.equal_range(GetTunnelAxisHeightCacheKey(this));
55 bool have_erased
= false;
56 for (auto it
= range
.first
; it
!= range
.second
; ++it
) {
57 if (it
->second
== this) {
58 tunnel_axis_height_index
.erase(it
);
67 * Update tunnel indexes
69 void Tunnel::UpdateIndexes()
71 if (this->index
>= TUNNEL_ID_MAP_LOOKUP
) {
72 tunnel_tile_index_map
[this->tile_n
] = this->index
;
73 tunnel_tile_index_map
[this->tile_s
] = this->index
;
76 tunnel_axis_height_index
.emplace(GetTunnelAxisHeightCacheKey(this), this);
80 * Tunnel pool is about to be cleaned
82 void Tunnel::PreCleanPool()
84 tunnel_tile_index_map
.clear();
85 tunnel_axis_height_index
.clear();
88 TunnelID
GetTunnelIndexByLookup(TileIndex t
)
90 auto iter
= tunnel_tile_index_map
.find(t
);
91 assert_msg(iter
!= tunnel_tile_index_map
.end(), "tile: 0x%X", t
);
97 * Gets the other end of the tunnel. Where a vehicle would reappear when it
98 * enters at the given tile.
99 * @param tile the tile to search from.
100 * @return the tile of the other end of the tunnel.
102 TileIndex
GetOtherTunnelEnd(TileIndex tile
)
104 Tunnel
* t
= Tunnel::GetByTile(tile
);
105 return t
->tile_n
== tile
? t
->tile_s
: t
->tile_n
;
108 static inline bool IsTunnelInWaySingleAxis(TileIndex tile
, int z
, IsTunnelInWayFlags flags
, bool y_axis
, TileIndexDiff tile_diff
)
110 const auto tunnels
= tunnel_axis_height_index
.equal_range(GetTunnelAxisHeightCacheKey(tile
, z
, y_axis
));
111 for (auto it
= tunnels
.first
; it
!= tunnels
.second
; ++it
) {
112 const Tunnel
*t
= it
->second
;
113 if (t
->tile_n
> tile
|| tile
> t
->tile_s
) continue;
115 if (!t
->is_chunnel
&& (flags
& ITIWF_CHUNNEL_ONLY
)) {
118 if (t
->is_chunnel
&& (flags
& ITIWF_IGNORE_CHUNNEL
)) {
119 /* Only if tunnel was built over water is terraforming is allowed between portals. */
120 const TileIndexDiff delta
= tile_diff
* 4; // 4 tiles ramp.
121 if (tile
< t
->tile_n
+ delta
|| t
->tile_s
- delta
< tile
) return true;
131 * Is there a tunnel in the way in any direction?
132 * @param tile the tile to search from.
133 * @param z the 'z' to search on.
134 * @param chunnel_allowed True if chunnel mid-parts are allowed, used when terraforming.
135 * @return true if and only if there is a tunnel.
137 bool IsTunnelInWay(TileIndex tile
, int z
, IsTunnelInWayFlags flags
)
139 return IsTunnelInWaySingleAxis(tile
, z
, flags
, false, 1) || IsTunnelInWaySingleAxis(tile
, z
, flags
, true, TileOffsByDiagDir(DIAGDIR_SE
));