Add: Overlay cargo icon in vehicle/depot list when holding shift+ctrl. (#12938)
[openttd-github.git] / src / map.cpp
blob0308640bf0a20e15d06f73976198ffb5d19a2d84
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file map.cpp Base functions related to the map and distances on them. */
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "core/alloc_func.hpp"
13 #include "water_map.h"
14 #include "error_func.h"
15 #include "string_func.h"
16 #include "pathfinder/water_regions.h"
18 #include "safeguards.h"
20 /* static */ uint Map::log_x; ///< 2^_map_log_x == _map_size_x
21 /* static */ uint Map::log_y; ///< 2^_map_log_y == _map_size_y
22 /* static */ uint Map::size_x; ///< Size of the map along the X
23 /* static */ uint Map::size_y; ///< Size of the map along the Y
24 /* static */ uint Map::size; ///< The number of tiles on the map
25 /* static */ uint Map::tile_mask; ///< _map_size - 1 (to mask the mapsize)
27 /* static */ Tile::TileBase *Tile::base_tiles = nullptr; ///< Base tiles of the map
28 /* static */ Tile::TileExtended *Tile::extended_tiles = nullptr; ///< Extended tiles of the map
31 /**
32 * (Re)allocates a map with the given dimension
33 * @param size_x the width of the map along the NE/SW edge
34 * @param size_y the 'height' of the map along the SE/NW edge
36 /* static */ void Map::Allocate(uint size_x, uint size_y)
38 /* Make sure that the map size is within the limits and that
39 * size of both axes is a power of 2. */
40 if (!IsInsideMM(size_x, MIN_MAP_SIZE, MAX_MAP_SIZE + 1) ||
41 !IsInsideMM(size_y, MIN_MAP_SIZE, MAX_MAP_SIZE + 1) ||
42 (size_x & (size_x - 1)) != 0 ||
43 (size_y & (size_y - 1)) != 0) {
44 FatalError("Invalid map size");
47 Debug(map, 1, "Allocating map of size {}x{}", size_x, size_y);
49 Map::log_x = FindFirstBit(size_x);
50 Map::log_y = FindFirstBit(size_y);
51 Map::size_x = size_x;
52 Map::size_y = size_y;
53 Map::size = size_x * size_y;
54 Map::tile_mask = Map::size - 1;
56 free(Tile::base_tiles);
57 free(Tile::extended_tiles);
59 Tile::base_tiles = CallocT<Tile::TileBase>(Map::size);
60 Tile::extended_tiles = CallocT<Tile::TileExtended>(Map::size);
62 AllocateWaterRegions();
66 #ifdef _DEBUG
67 TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
69 int dx = offset & Map::MaxX();
70 if (dx >= (int)Map::SizeX() / 2) dx -= Map::SizeX();
71 int dy = (offset - dx) / (int)Map::SizeX();
73 uint32_t x = TileX(tile) + dx;
74 uint32_t y = TileY(tile) + dy;
76 assert(x < Map::SizeX());
77 assert(y < Map::SizeY());
78 assert(TileXY(x, y) == Map::WrapToMap(tile + offset));
80 return TileXY(x, y);
82 #endif
84 /**
85 * This function checks if we add addx/addy to tile, if we
86 * do wrap around the edges. For example, tile = (10,2) and
87 * addx = +3 and addy = -4. This function will now return
88 * INVALID_TILE, because the y is wrapped. This is needed in
89 * for example, farmland. When the tile is not wrapped,
90 * the result will be tile + TileDiffXY(addx, addy)
92 * @param tile the 'starting' point of the adding
93 * @param addx the amount of tiles in the X direction to add
94 * @param addy the amount of tiles in the Y direction to add
95 * @return translated tile, or INVALID_TILE when it would've wrapped.
97 TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
99 uint x = TileX(tile) + addx;
100 uint y = TileY(tile) + addy;
102 /* Disallow void tiles at the north border. */
103 if ((x == 0 || y == 0) && _settings_game.construction.freeform_edges) return INVALID_TILE;
105 /* Are we about to wrap? */
106 if (x >= Map::MaxX() || y >= Map::MaxY()) return INVALID_TILE;
108 return TileXY(x, y);
111 /** 'Lookup table' for tile offsets given a DiagDirection */
112 extern const TileIndexDiffC _tileoffs_by_diagdir[] = {
113 {-1, 0}, ///< DIAGDIR_NE
114 { 0, 1}, ///< DIAGDIR_SE
115 { 1, 0}, ///< DIAGDIR_SW
116 { 0, -1} ///< DIAGDIR_NW
119 /** 'Lookup table' for tile offsets given a Direction */
120 extern const TileIndexDiffC _tileoffs_by_dir[] = {
121 {-1, -1}, ///< DIR_N
122 {-1, 0}, ///< DIR_NE
123 {-1, 1}, ///< DIR_E
124 { 0, 1}, ///< DIR_SE
125 { 1, 1}, ///< DIR_S
126 { 1, 0}, ///< DIR_SW
127 { 1, -1}, ///< DIR_W
128 { 0, -1} ///< DIR_NW
132 * Gets the Manhattan distance between the two given tiles.
133 * The Manhattan distance is the sum of the delta of both the
134 * X and Y component.
135 * Also known as L1-Norm
136 * @param t0 the start tile
137 * @param t1 the end tile
138 * @return the distance
140 uint DistanceManhattan(TileIndex t0, TileIndex t1)
142 const uint dx = Delta(TileX(t0), TileX(t1));
143 const uint dy = Delta(TileY(t0), TileY(t1));
144 return dx + dy;
149 * Gets the 'Square' distance between the two given tiles.
150 * The 'Square' distance is the square of the shortest (straight line)
151 * distance between the two tiles.
152 * Also known as euclidian- or L2-Norm squared.
153 * @param t0 the start tile
154 * @param t1 the end tile
155 * @return the distance
157 uint DistanceSquare(TileIndex t0, TileIndex t1)
159 const int dx = TileX(t0) - TileX(t1);
160 const int dy = TileY(t0) - TileY(t1);
161 return dx * dx + dy * dy;
166 * Gets the biggest distance component (x or y) between the two given tiles.
167 * Also known as L-Infinity-Norm.
168 * @param t0 the start tile
169 * @param t1 the end tile
170 * @return the distance
172 uint DistanceMax(TileIndex t0, TileIndex t1)
174 const uint dx = Delta(TileX(t0), TileX(t1));
175 const uint dy = Delta(TileY(t0), TileY(t1));
176 return std::max(dx, dy);
181 * Gets the biggest distance component (x or y) between the two given tiles
182 * plus the Manhattan distance, i.e. two times the biggest distance component
183 * and once the smallest component.
184 * @param t0 the start tile
185 * @param t1 the end tile
186 * @return the distance
188 uint DistanceMaxPlusManhattan(TileIndex t0, TileIndex t1)
190 const uint dx = Delta(TileX(t0), TileX(t1));
191 const uint dy = Delta(TileY(t0), TileY(t1));
192 return dx > dy ? 2 * dx + dy : 2 * dy + dx;
196 * Param the minimum distance to an edge
197 * @param tile the tile to get the distance from
198 * @return the distance from the edge in tiles
200 uint DistanceFromEdge(TileIndex tile)
202 const uint xl = TileX(tile);
203 const uint yl = TileY(tile);
204 const uint xh = Map::SizeX() - 1 - xl;
205 const uint yh = Map::SizeY() - 1 - yl;
206 const uint minl = std::min(xl, yl);
207 const uint minh = std::min(xh, yh);
208 return std::min(minl, minh);
212 * Gets the distance to the edge of the map in given direction.
213 * @param tile the tile to get the distance from
214 * @param dir the direction of interest
215 * @return the distance from the edge in tiles
217 uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir)
219 switch (dir) {
220 case DIAGDIR_NE: return TileX(tile) - (_settings_game.construction.freeform_edges ? 1 : 0);
221 case DIAGDIR_NW: return TileY(tile) - (_settings_game.construction.freeform_edges ? 1 : 0);
222 case DIAGDIR_SW: return Map::MaxX() - TileX(tile) - 1;
223 case DIAGDIR_SE: return Map::MaxY() - TileY(tile) - 1;
224 default: NOT_REACHED();
229 * Function performing a search around a center tile and going outward, thus in circle.
230 * Although it really is a square search...
231 * Every tile will be tested by means of the callback function proc,
232 * which will determine if yes or no the given tile meets criteria of search.
233 * @param tile to start the search from. Upon completion, it will return the tile matching the search
234 * @param size: number of tiles per side of the desired search area
235 * @param proc: callback testing function pointer.
236 * @param user_data to be passed to the callback function. Depends on the implementation
237 * @return result of the search
238 * @pre proc != nullptr
239 * @pre size > 0
241 bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
243 assert(proc != nullptr);
244 assert(size > 0);
246 if (size % 2 == 1) {
247 /* If the length of the side is uneven, the center has to be checked
248 * separately, as the pattern of uneven sides requires to go around the center */
249 if (proc(*tile, user_data)) return true;
251 /* If tile test is not successful, get one tile up,
252 * ready for a test in first circle around center tile */
253 *tile = TileAddByDir(*tile, DIR_N);
254 return CircularTileSearch(tile, size / 2, 1, 1, proc, user_data);
255 } else {
256 return CircularTileSearch(tile, size / 2, 0, 0, proc, user_data);
261 * Generalized circular search allowing for rectangles and a hole.
262 * Function performing a search around a center rectangle and going outward.
263 * The center rectangle is left out from the search. To do a rectangular search
264 * without a hole, set either h or w to zero.
265 * Every tile will be tested by means of the callback function proc,
266 * which will determine if yes or no the given tile meets criteria of search.
267 * @param tile to start the search from. Upon completion, it will return the tile matching the search.
268 * This tile should be directly north of the hole (if any).
269 * @param radius How many tiles to search outwards. Note: This is a radius and thus different
270 * from the size parameter of the other CircularTileSearch function, which is a diameter.
271 * @param w the width of the inner rectangle
272 * @param h the height of the inner rectangle
273 * @param proc callback testing function pointer.
274 * @param user_data to be passed to the callback function. Depends on the implementation
275 * @return result of the search
276 * @pre proc != nullptr
277 * @pre radius > 0
279 bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data)
281 assert(proc != nullptr);
282 assert(radius > 0);
284 uint x = TileX(*tile) + w + 1;
285 uint y = TileY(*tile);
287 const uint extent[DIAGDIR_END] = { w, h, w, h };
289 for (uint n = 0; n < radius; n++) {
290 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
291 /* Is the tile within the map? */
292 for (uint j = extent[dir] + n * 2 + 1; j != 0; j--) {
293 if (x < Map::SizeX() && y < Map::SizeY()) {
294 TileIndex t = TileXY(x, y);
295 /* Is the callback successful? */
296 if (proc(t, user_data)) {
297 /* Stop the search */
298 *tile = t;
299 return true;
303 /* Step to the next 'neighbour' in the circular line */
304 x += _tileoffs_by_diagdir[dir].x;
305 y += _tileoffs_by_diagdir[dir].y;
308 /* Jump to next circle to test */
309 x += _tileoffs_by_dir[DIR_W].x;
310 y += _tileoffs_by_dir[DIR_W].y;
313 *tile = INVALID_TILE;
314 return false;
318 * Finds the distance for the closest tile with water/land given a tile
319 * @param tile the tile to find the distance too
320 * @param water whether to find water or land
321 * @return distance to nearest water (max 0x7F) / land (max 0x1FF; 0x200 if there is no land)
323 uint GetClosestWaterDistance(TileIndex tile, bool water)
325 if (HasTileWaterGround(tile) == water) return 0;
327 uint max_dist = water ? 0x7F : 0x200;
329 int x = TileX(tile);
330 int y = TileY(tile);
332 uint max_x = Map::MaxX();
333 uint max_y = Map::MaxY();
334 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
336 /* go in a 'spiral' with increasing manhattan distance in each iteration */
337 for (uint dist = 1; dist < max_dist; dist++) {
338 /* next 'diameter' */
339 y--;
341 /* going counter-clockwise around this square */
342 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
343 static const int8_t ddx[DIAGDIR_END] = { -1, 1, 1, -1};
344 static const int8_t ddy[DIAGDIR_END] = { 1, 1, -1, -1};
346 int dx = ddx[dir];
347 int dy = ddy[dir];
349 /* each side of this square has length 'dist' */
350 for (uint a = 0; a < dist; a++) {
351 /* MP_VOID tiles are not checked (interval is [min; max) for IsInsideMM())*/
352 if (IsInsideMM(x, min_xy, max_x) && IsInsideMM(y, min_xy, max_y)) {
353 TileIndex t = TileXY(x, y);
354 if (HasTileWaterGround(t) == water) return dist;
356 x += dx;
357 y += dy;
362 if (!water) {
363 /* no land found - is this a water-only map? */
364 for (TileIndex t = 0; t < Map::Size(); t++) {
365 if (!IsTileType(t, MP_VOID) && !IsTileType(t, MP_WATER)) return 0x1FF;
369 return max_dist;