Translations update
[openttd/fttd.git] / src / water_cmd.cpp
blobf8d29568047c397f9b087709a36471977bdc3c5a
1 /* $Id$ */
3 /*
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/>.
8 */
10 /** @file water_cmd.cpp Handling of water tiles. */
12 #include "stdafx.h"
13 #include "cmd_helper.h"
14 #include "landscape.h"
15 #include "viewport_func.h"
16 #include "command_func.h"
17 #include "town.h"
18 #include "news_func.h"
19 #include "depot_base.h"
20 #include "depot_func.h"
21 #include "water.h"
22 #include "map/industry.h"
23 #include "newgrf_canal.h"
24 #include "strings_func.h"
25 #include "vehicle_func.h"
26 #include "sound_func.h"
27 #include "company_func.h"
28 #include "map/ground.h"
29 #include "map/slope.h"
30 #include "aircraft.h"
31 #include "effectvehicle_func.h"
32 #include "map/bridge.h"
33 #include "bridge.h"
34 #include "station_base.h"
35 #include "ai/ai.hpp"
36 #include "game/game.hpp"
37 #include "core/random_func.hpp"
38 #include "core/backup_type.hpp"
39 #include "date_func.h"
40 #include "company_base.h"
41 #include "company_gui.h"
42 #include "newgrf_generic.h"
43 #include "signalbuffer.h"
45 #include "table/strings.h"
47 /**
48 * Describes from which directions a specific slope can be flooded (if the tile is floodable at all).
50 static const uint8 _flood_from_dirs[] = {
51 (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
52 (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_W
53 (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_S
54 (1 << DIR_NE), // SLOPE_SW
55 (1 << DIR_NW) | (1 << DIR_SW), // SLOPE_E
56 0, // SLOPE_EW
57 (1 << DIR_NW), // SLOPE_SE
58 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_WSE, SLOPE_STEEP_S
59 (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_N
60 (1 << DIR_SE), // SLOPE_NW
61 0, // SLOPE_NS
62 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_NWS, SLOPE_STEEP_W
63 (1 << DIR_SW), // SLOPE_NE
64 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_ENW, SLOPE_STEEP_N
65 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW), // SLOPE_SEN, SLOPE_STEEP_E
68 /**
69 * Marks tile dirty if it is a canal or river tile.
70 * Called to avoid glitches when flooding tiles next to canal tile.
72 * @param tile tile to check
74 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
76 if (IsWaterTile(tile) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
79 /**
80 * Marks the tiles around a tile as dirty, if they are canals or rivers.
82 * @param tile The center of the tile where all other tiles are marked as dirty
83 * @ingroup dirty
85 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
87 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
88 MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
93 /**
94 * Build a ship depot.
95 * @param tile tile where ship depot is built
96 * @param flags type of operation
97 * @param p1 bit 0 depot orientation (Axis)
98 * @param p2 unused
99 * @param text unused
100 * @return the cost of this operation or an error
102 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
104 Axis axis = Extract<Axis, 0, 1>(p1);
106 TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
108 if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
109 return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
112 if (HasBridgeAbove(tile) || HasBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
114 if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
115 /* Prevent depots on rapids */
116 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
119 if (!Depot::CanAllocateItem()) return CMD_ERROR;
121 WaterClass wc1 = GetWaterClass(tile);
122 WaterClass wc2 = GetWaterClass(tile2);
123 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
125 bool add_cost = !IsPlainWaterTile(tile);
126 CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
127 if (ret.Failed()) return ret;
128 if (add_cost) {
129 cost.AddCost(ret);
131 add_cost = !IsPlainWaterTile(tile2);
132 ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
133 if (ret.Failed()) return ret;
134 if (add_cost) {
135 cost.AddCost(ret);
138 if (flags & DC_EXEC) {
139 Depot *depot = new Depot(tile);
140 depot->build_date = _date;
142 if (wc1 == WATER_CLASS_CANAL || wc2 == WATER_CLASS_CANAL) {
143 /* Update infrastructure counts after the unconditional clear earlier. */
144 Company::Get(_current_company)->infrastructure.water += wc1 == WATER_CLASS_CANAL && wc2 == WATER_CLASS_CANAL ? 2 : 1;
146 Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR;
147 DirtyCompanyInfrastructureWindows(_current_company);
149 MakeShipDepot(tile, _current_company, depot->index, ReverseDiagDir(AxisToDiagDir(axis)), wc1);
150 MakeShipDepot(tile2, _current_company, depot->index, AxisToDiagDir(axis), wc2);
151 MarkTileDirtyByTile(tile);
152 MarkTileDirtyByTile(tile2);
153 MakeDefaultName(depot);
156 return cost;
159 void MakeWaterKeepingClass(TileIndex tile, Owner o)
161 WaterClass wc = GetWaterClass(tile);
163 /* Autoslope might turn an originally canal or river tile into land */
164 int z;
165 Slope slope = GetTileSlope(tile, &z);
167 if (slope != SLOPE_FLAT) {
168 if (wc == WATER_CLASS_CANAL) {
169 /* If we clear the canal, we have to remove it from the infrastructure count as well. */
170 Company *c = Company::GetIfValid(o);
171 if (c != NULL) {
172 c->infrastructure.water--;
173 DirtyCompanyInfrastructureWindows(c->index);
175 /* Sloped canals are locks and no natural water remains whatever the slope direction */
176 wc = WATER_CLASS_INVALID;
179 /* Only river water should be restored on appropriate slopes. Other water would be invalid on slopes */
180 if (wc != WATER_CLASS_RIVER || GetInclinedSlopeDirection(slope) == INVALID_DIAGDIR) {
181 wc = WATER_CLASS_INVALID;
185 if (wc == WATER_CLASS_SEA && z > 0) {
186 /* Update company infrastructure count. */
187 Company *c = Company::GetIfValid(o);
188 if (c != NULL) {
189 c->infrastructure.water++;
190 DirtyCompanyInfrastructureWindows(c->index);
193 wc = WATER_CLASS_CANAL;
196 /* Zero map array and terminate animation */
197 DoClearSquare(tile);
199 /* Maybe change to water */
200 switch (wc) {
201 case WATER_CLASS_SEA: MakeSea(tile); break;
202 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
203 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
204 default: break;
207 MarkTileDirtyByTile(tile);
210 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
212 if (!IsShipDepot(tile)) return CMD_ERROR;
214 CommandCost ret = CheckTileOwnership(tile);
215 if (ret.Failed()) return ret;
217 TileIndex tile2 = GetOtherShipDepotTile(tile);
219 /* do not check for ship on tile when company goes bankrupt */
220 if (!(flags & DC_BANKRUPT)) {
221 CommandCost ret = EnsureNoVehicleOnGround(tile);
222 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
223 if (ret.Failed()) return ret;
226 if (flags & DC_EXEC) {
227 delete Depot::GetByTile(tile);
229 Company *c = Company::GetIfValid(GetTileOwner(tile));
230 if (c != NULL) {
231 c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR;
232 DirtyCompanyInfrastructureWindows(c->index);
235 MakeWaterKeepingClass(tile, GetTileOwner(tile));
236 MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
239 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
243 * Builds a lock.
244 * @param tile tile where to place the lock
245 * @param flags type of operation
246 * @param p1 unused
247 * @param p2 unused
248 * @param text unused
249 * @return the cost of this operation or an error
251 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
253 DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
254 if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
256 CommandCost cost(EXPENSES_CONSTRUCTION);
258 int delta = TileOffsByDiagDir(dir);
259 CommandCost ret = EnsureNoVehicleOnGround(tile);
260 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
261 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
262 if (ret.Failed()) return ret;
264 /* middle tile */
265 WaterClass wc_middle = IsPlainWaterTile(tile) ? GetWaterClass(tile) : WATER_CLASS_CANAL;
266 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
267 if (ret.Failed()) return ret;
268 cost.AddCost(ret);
270 /* lower tile */
271 if (!IsPlainWaterTile(tile - delta)) {
272 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
273 if (ret.Failed()) return ret;
274 cost.AddCost(ret);
275 cost.AddCost(_price[PR_BUILD_CANAL]);
277 if (!IsTileFlat(tile - delta)) {
278 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
280 WaterClass wc_lower = IsPlainWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
282 /* upper tile */
283 if (!IsPlainWaterTile(tile + delta)) {
284 ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
285 if (ret.Failed()) return ret;
286 cost.AddCost(ret);
287 cost.AddCost(_price[PR_BUILD_CANAL]);
289 if (!IsTileFlat(tile + delta)) {
290 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
292 WaterClass wc_upper = IsPlainWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
294 if (HasBridgeAbove(tile) || HasBridgeAbove(tile - delta) || HasBridgeAbove(tile + delta)) {
295 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
298 if (flags & DC_EXEC) {
299 /* Update company infrastructure counts. */
300 Company *c = Company::GetIfValid(_current_company);
301 if (c != NULL) {
302 /* Counts for the water. */
303 if (!IsPlainWaterTile(tile - delta)) c->infrastructure.water++;
304 if (!IsPlainWaterTile(tile + delta)) c->infrastructure.water++;
305 /* Count for the lock itself. */
306 c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock is three tiles.
307 DirtyCompanyInfrastructureWindows(_current_company);
310 MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
311 MarkTileDirtyByTile(tile);
312 MarkTileDirtyByTile(tile - delta);
313 MarkTileDirtyByTile(tile + delta);
314 MarkCanalsAndRiversAroundDirty(tile - delta);
315 MarkCanalsAndRiversAroundDirty(tile + delta);
317 cost.AddCost(_price[PR_BUILD_LOCK]);
319 return cost;
323 * Remove a lock.
324 * @param tile Central tile of the lock.
325 * @param flags Operation to perform.
326 * @return The cost in case of success, or an error code if it failed.
328 static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags)
330 if (GetTileOwner(tile) != OWNER_NONE) {
331 CommandCost ret = CheckTileOwnership(tile);
332 if (ret.Failed()) return ret;
335 TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
337 /* make sure no vehicle is on the tile. */
338 CommandCost ret = EnsureNoVehicleOnGround(tile);
339 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
340 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
341 if (ret.Failed()) return ret;
343 if (flags & DC_EXEC) {
344 /* Remove middle part from company infrastructure count. */
345 Company *c = Company::GetIfValid(GetTileOwner(tile));
346 if (c != NULL) {
347 c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock.
348 DirtyCompanyInfrastructureWindows(c->index);
351 if (GetWaterClass(tile) == WATER_CLASS_RIVER) {
352 MakeRiver(tile, Random());
353 } else {
354 DoClearSquare(tile);
356 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta));
357 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
358 MarkCanalsAndRiversAroundDirty(tile);
359 MarkCanalsAndRiversAroundDirty(tile - delta);
360 MarkCanalsAndRiversAroundDirty(tile + delta);
363 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
366 /** Create non-desert around a river tile. */
367 void RiverModifyDesertZone (TileIndex tile)
369 TileArea ta (tile);
370 ta.expand (2);
372 TILE_AREA_LOOP(t, ta) {
373 if (GetTropicZone(t) == TROPICZONE_DESERT) SetTropicZone (t, TROPICZONE_NORMAL);
378 * Build a piece of canal.
379 * @param tile end tile of stretch-dragging
380 * @param flags type of operation
381 * @param p1 start tile of stretch-dragging
382 * @param p2 waterclass to build. sea and river can only be built in scenario editor
383 * @param text unused
384 * @return the cost of this operation or an error
386 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
388 WaterClass wc = Extract<WaterClass, 0, 2>(p2);
389 if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
391 /* Outside of the editor you can only build canals, not oceans */
392 if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
394 TileArea ta(tile, p1);
396 /* Outside the editor you can only drag canals, and not areas */
397 if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
399 CommandCost cost(EXPENSES_CONSTRUCTION);
400 TILE_AREA_LOOP(tile, ta) {
401 CommandCost ret;
403 Slope slope = GetTileSlope(tile);
404 if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
405 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
408 /* can't make water of water! */
409 if (IsWaterTile(tile) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
411 bool water = IsPlainWaterTile(tile);
412 ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
413 if (ret.Failed()) return ret;
415 if (!water) cost.AddCost(ret);
417 if (flags & DC_EXEC) {
418 switch (wc) {
419 case WATER_CLASS_RIVER:
420 MakeRiver(tile, Random());
421 if (_game_mode == GM_EDITOR) {
422 RiverModifyDesertZone (tile);
424 break;
426 case WATER_CLASS_SEA:
427 if (TileHeight(tile) == 0) {
428 MakeSea(tile);
429 break;
431 /* FALL THROUGH */
433 default:
434 MakeCanal(tile, _current_company, Random());
435 if (Company::IsValidID(_current_company)) {
436 Company::Get(_current_company)->infrastructure.water++;
437 DirtyCompanyInfrastructureWindows(_current_company);
439 break;
441 MarkTileDirtyByTile(tile);
442 MarkCanalsAndRiversAroundDirty(tile);
445 cost.AddCost(_price[PR_BUILD_CANAL]);
448 if (cost.GetCost() == 0) {
449 return_cmd_error(STR_ERROR_ALREADY_BUILT);
450 } else {
451 return cost;
455 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
457 switch (GetWaterTileType(tile)) {
458 case WATER_TILE_CLEAR: {
459 if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
461 Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
462 /* Make sure freeform edges are allowed or it's not an edge tile. */
463 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
464 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
465 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
468 /* Make sure no vehicle is on the tile */
469 CommandCost ret = EnsureNoVehicleOnGround(tile);
470 if (ret.Failed()) return ret;
472 Owner owner = GetTileOwner(tile);
473 if (owner != OWNER_WATER && owner != OWNER_NONE) {
474 CommandCost ret = CheckTileOwnership(tile);
475 if (ret.Failed()) return ret;
478 if (flags & DC_EXEC) {
479 if (IsCanal(tile) && Company::IsValidID(owner)) {
480 Company::Get(owner)->infrastructure.water--;
481 DirtyCompanyInfrastructureWindows(owner);
483 DoClearSquare(tile);
484 MarkCanalsAndRiversAroundDirty(tile);
487 return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
490 case WATER_TILE_COAST: {
491 Slope slope = GetTileSlope(tile);
493 /* Make sure no vehicle is on the tile */
494 CommandCost ret = EnsureNoVehicleOnGround(tile);
495 if (ret.Failed()) return ret;
497 if (flags & DC_EXEC) {
498 DoClearSquare(tile);
499 MarkCanalsAndRiversAroundDirty(tile);
501 if (IsSlopeWithOneCornerRaised(slope)) {
502 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
503 } else {
504 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
508 case WATER_TILE_DEPOT:
509 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
510 return RemoveShipDepot(tile, flags);
512 case WATER_TILE_LOCK_MIDDLE:
513 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
514 if (_current_company == OWNER_WATER) return CMD_ERROR;
515 return RemoveLock(tile, flags);
517 case WATER_TILE_LOCK_LOWER:
518 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
519 if (_current_company == OWNER_WATER) return CMD_ERROR;
520 /* move to the middle tile.. */
521 tile += TileOffsByDiagDir(GetLockDirection(tile));
522 return RemoveLock(tile, flags);
524 case WATER_TILE_LOCK_UPPER:
525 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
526 if (_current_company == OWNER_WATER) return CMD_ERROR;
527 /* move to the middle tile.. */
528 tile -= TileOffsByDiagDir(GetLockDirection(tile));
529 return RemoveLock(tile, flags);
531 default:
532 NOT_REACHED();
537 * return true if a tile is a water tile wrt. a certain direction.
539 * @param tile The tile of interest.
540 * @param from The direction of interest.
541 * @return true iff the tile is water in the view of 'from'.
544 bool IsWateredTile(TileIndex tile, Direction from)
546 if (IsIndustryTile(tile)) {
547 /* Do not draw waterborders inside of industries.
548 * Note: There is no easy way to detect the industry of an oilrig tile. */
549 TileIndex src_tile = tile + TileOffsByDir(from);
550 if ((IsStationTile(src_tile) && IsOilRig(src_tile)) ||
551 (IsIndustryTile(src_tile) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
553 return IsTileOnWater(tile);
556 switch (GetTileType(tile)) {
557 case TT_GROUND: return IsTileSubtype(tile, TT_GROUND_VOID); // consider map border as water, esp. for rivers
559 case TT_WATER:
560 switch (GetWaterTileType(tile)) {
561 case WATER_TILE_CLEAR:
562 case WATER_TILE_DEPOT:
563 return true;
565 case WATER_TILE_COAST:
566 switch (GetTileSlope(tile)) {
567 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
568 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
569 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
570 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
571 default: return false;
574 default:
575 return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
578 case TT_RAILWAY:
579 if (IsTileSubtype(tile, TT_TRACK) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
580 switch (GetTileSlope(tile)) {
581 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
582 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
583 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
584 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
585 default: return false;
588 return false;
590 case TT_MISC:
591 return IsTileSubtype(tile, TT_MISC_AQUEDUCT) && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
593 case TT_STATION:
594 if (IsOilRig(tile)) {
595 /* Do not draw waterborders inside of industries.
596 * Note: There is no easy way to detect the industry of an oilrig tile. */
597 TileIndex src_tile = tile + TileOffsByDir(from);
598 if ((IsStationTile(src_tile) && IsOilRig(src_tile)) ||
599 (IsIndustryTile(src_tile))) return true;
601 return IsTileOnWater(tile);
603 return (IsDock(tile) && IsTileFlat(tile)) || IsBuoy(tile);
605 case TT_OBJECT: return IsTileOnWater(tile);
607 default: return false;
612 * Draw a water sprite, potentially with a NewGRF-modified sprite offset.
613 * @param base Sprite base.
614 * @param offset Sprite offset.
615 * @param feature The type of sprite that is drawn.
616 * @param tile Tile index to draw.
618 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
620 if (base != SPR_FLAT_WATER_TILE) {
621 /* Only call offset callback if the sprite is NewGRF-provided. */
622 offset = GetCanalSpriteOffset(feature, tile, offset);
624 DrawGroundSprite(base + offset, PAL_NONE);
628 * Draw canal or river edges.
629 * @param canal True if canal edges should be drawn, false for river edges.
630 * @param offset Sprite offset.
631 * @param tile Tile to draw.
633 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
635 CanalFeature feature;
636 SpriteID base = 0;
637 if (canal) {
638 feature = CF_DIKES;
639 base = GetCanalSprite(CF_DIKES, tile);
640 if (base == 0) base = SPR_CANAL_DIKES_BASE;
641 } else {
642 feature = CF_RIVER_EDGE;
643 base = GetCanalSprite(CF_RIVER_EDGE, tile);
644 if (base == 0) return; // Don't draw if no sprites provided.
647 uint wa;
649 /* determine the edges around with water. */
650 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
651 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
652 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
653 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
655 if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
656 if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
657 if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
658 if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
660 /* right corner */
661 switch (wa & 0x03) {
662 case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
663 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
666 /* bottom corner */
667 switch (wa & 0x06) {
668 case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
669 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
672 /* left corner */
673 switch (wa & 0x0C) {
674 case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
675 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
678 /* upper corner */
679 switch (wa & 0x09) {
680 case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
681 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
685 /** Draw a plain sea water tile with no edges */
686 static void DrawSeaWater(TileIndex tile)
688 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
691 /** draw a canal styled water tile with dikes around */
692 static void DrawCanalWater(TileIndex tile)
694 SpriteID image = SPR_FLAT_WATER_TILE;
695 if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
696 /* First water slope sprite is flat water. */
697 image = GetCanalSprite(CF_WATERSLOPE, tile);
698 if (image == 0) image = SPR_FLAT_WATER_TILE;
700 DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
702 DrawWaterEdges(true, 0, tile);
705 #include "table/water_land.h"
708 * Draw a build sprite sequence for water tiles.
709 * If buildings are invisible, nothing will be drawn.
710 * @param ti Tile info.
711 * @param dtss Sprite sequence to draw.
712 * @param base Base sprite.
713 * @param offset Additional sprite offset.
714 * @param palette Palette to use.
716 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
718 /* Don't draw if buildings are invisible. */
719 if (IsInvisibilitySet(TO_BUILDINGS)) return;
721 for (; !dtss->IsTerminator(); dtss++) {
722 uint tile_offs = offset + dtss->image.sprite;
723 if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
724 AddSortableSpriteToDraw(base + tile_offs, palette,
725 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
726 dtss->size_x, dtss->size_y,
727 dtss->size_z, ti->z + dtss->delta_z,
728 IsTransparencySet(TO_BUILDINGS));
732 /** Draw a lock tile. */
733 static void DrawWaterLock(const TileInfo *ti)
735 WaterTileType part = GetWaterTileType (ti->tile);
736 const DrawTileSprites &dts = _lock_display_data[part - WATER_TILE_LOCK_MIDDLE][GetLockDirection(ti->tile)];
738 /* Draw ground sprite. */
739 SpriteID image = dts.ground.sprite;
741 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
742 if (water_base == 0) {
743 /* Use default sprites. */
744 water_base = SPR_CANALS_BASE;
745 } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
746 /* NewGRF supplies a flat sprite as first sprite. */
747 if (image == SPR_FLAT_WATER_TILE) {
748 image = water_base;
749 } else {
750 image++;
754 if (image < 5) image += water_base;
755 DrawGroundSprite(image, PAL_NONE);
757 /* Draw structures. */
758 uint zoffs = 0;
759 SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
761 if (base == 0) {
762 /* If no custom graphics, use defaults. */
763 base = SPR_LOCK_BASE;
764 uint8 z_threshold = part == WATER_TILE_LOCK_UPPER ? 8 : 0;
765 zoffs = ti->z > z_threshold ? 24 : 0;
768 DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
771 /** Draw a ship depot tile. */
772 static void DrawWaterDepot(const TileInfo *ti)
774 DrawWaterClassGround(ti);
775 DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotDirection(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
778 static void DrawRiverWater(const TileInfo *ti)
780 SpriteID image = SPR_FLAT_WATER_TILE;
781 uint offset = 0;
782 uint edges_offset = 0;
784 if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
785 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
786 if (image == 0) {
787 switch (ti->tileh) {
788 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
789 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
790 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
791 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
792 default: image = SPR_FLAT_WATER_TILE; break;
794 } else {
795 /* Flag bit 0 indicates that the first sprite is flat water. */
796 offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
798 switch (ti->tileh) {
799 case SLOPE_SE: edges_offset += 12; break;
800 case SLOPE_NE: offset += 1; edges_offset += 24; break;
801 case SLOPE_SW: offset += 2; edges_offset += 36; break;
802 case SLOPE_NW: offset += 3; edges_offset += 48; break;
803 default: offset = 0; break;
806 offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
810 DrawGroundSprite(image + offset, PAL_NONE);
812 /* Draw river edges if available. */
813 DrawWaterEdges(false, edges_offset, ti->tile);
816 void DrawShoreTile(Slope tileh)
818 /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
819 * This allows to calculate the proper sprite to display for this Slope */
820 static const byte tileh_to_shoresprite[32] = {
821 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
825 assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
826 assert(tileh != SLOPE_FLAT); // Shore is never flat
828 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
830 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
833 void DrawWaterClassGround(const TileInfo *ti)
835 switch (GetWaterClass(ti->tile)) {
836 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
837 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
838 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
839 default: NOT_REACHED();
843 static void DrawTile_Water(TileInfo *ti)
845 switch (GetWaterTileType(ti->tile)) {
846 case WATER_TILE_CLEAR:
847 DrawWaterClassGround(ti);
848 DrawBridgeMiddle(ti);
849 break;
851 case WATER_TILE_COAST: {
852 DrawShoreTile(ti->tileh);
853 DrawBridgeMiddle(ti);
854 break;
857 case WATER_TILE_DEPOT:
858 DrawWaterDepot(ti);
859 break;
861 default:
862 DrawWaterLock(ti);
863 break;
867 void DrawShipDepotSprite(int x, int y, DiagDirection dir)
869 const DrawTileSprites &dts = _shipdepot_display_data[dir];
871 DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
872 DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
876 static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y)
878 int z;
879 Slope tileh = GetTilePixelSlope(tile, &z);
881 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
884 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
886 return FOUNDATION_NONE;
889 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
891 switch (GetWaterTileType(tile)) {
892 case WATER_TILE_CLEAR:
893 switch (GetWaterClass(tile)) {
894 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
895 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
896 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
897 default: NOT_REACHED(); break;
899 break;
900 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
901 case WATER_TILE_DEPOT:
902 td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
903 td->build_date = Depot::GetByTile(tile)->build_date;
904 break;
905 default: td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
908 td->owner[0] = GetTileOwner(tile);
912 * Handle the flooding of a vehicle. This sets the vehicle state to crashed,
913 * creates a newsitem and dirties the necessary windows.
914 * @param v The vehicle to flood.
916 static void FloodVehicle(Vehicle *v)
918 uint pass = v->Crash(true);
920 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
921 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
922 AddNewsItem<VehicleNewsItem> (STR_NEWS_DISASTER_FLOOD_VEHICLE,
923 NT_ACCIDENT, v->index, pass);
924 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
925 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
929 * Flood vehicles on a tile if we are allowed to flood them, i.e. when they are on the ground.
930 * @param tile The tile to flood.
931 * @param z The z of level to flood.
933 static void FloodTileVehicles(TileIndex tile, int z)
935 VehicleTileIterator iter (tile);
936 while (!iter.finished()) {
937 Vehicle *v = iter.next();
939 if ((v->vehstatus & VS_CRASHED) != 0) continue;
941 switch (v->type) {
942 default: break;
944 case VEH_TRAIN:
945 case VEH_ROAD:
946 if (v->z_pos <= z) FloodVehicle(v->First());
952 * Finds a vehicle to flood.
953 * It does not find vehicles that are already crashed on bridges, i.e. flooded.
954 * @param tile the tile where to find a vehicle to flood
956 static void FloodVehicles(TileIndex tile)
958 if (IsAirportTile(tile)) {
959 if (GetTileMaxZ(tile) != 0) return;
961 const Station *st = Station::GetByTile(tile);
962 TILE_AREA_LOOP(tile, st->airport) {
963 if (st->TileBelongsToAirport(tile)) {
964 VehicleTileIterator iter (tile);
965 while (!iter.finished()) {
966 Vehicle *v = iter.next();
968 if (v->type != VEH_AIRCRAFT) continue;
969 if (v->subtype == AIR_SHADOW) continue;
970 if ((v->vehstatus & VS_CRASHED) != 0) continue;
972 /* We compare v->z_pos against delta_z + 1 because the shadow
973 * is at delta_z and the actual aircraft at delta_z + 1. */
974 const AirportFTAClass *airport = st->airport.GetFTA();
975 if (v->z_pos == airport->delta_z + 1) FloodVehicle(v);
980 /* No vehicle could be flooded on this airport anymore */
981 return;
984 if (!IsBridgeHeadTile(tile)) {
985 FloodTileVehicles (tile, 0);
986 return;
989 int z = GetBridgePixelHeight(tile);
990 FloodTileVehicles (tile, z);
991 FloodTileVehicles (GetOtherBridgeEnd(tile), z);
995 * Returns the behaviour of a tile during flooding.
997 * @return Behaviour of the tile
999 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
1001 /* FLOOD_ACTIVE: 'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
1002 * FLOOD_DRYUP: coast with more than one corner raised, coast with rail-track, coast with trees
1003 * FLOOD_PASSIVE: (not used)
1004 * FLOOD_NONE: canals, rivers, everything else
1006 if (IsIndustryTile(tile)) {
1007 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
1010 switch (GetTileType(tile)) {
1011 case TT_WATER:
1012 if (IsCoast(tile)) {
1013 Slope tileh = GetTileSlope(tile);
1014 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
1016 /* FALL THROUGH */
1017 case TT_STATION:
1018 case TT_OBJECT:
1019 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
1021 case TT_RAILWAY:
1022 if (IsTileSubtype(tile, TT_TRACK) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
1023 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
1025 return FLOOD_NONE;
1027 case TT_GROUND:
1028 return (IsTreeTile(tile) && GetClearGround(tile) == GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
1030 default:
1031 return FLOOD_NONE;
1036 * Floods a tile.
1038 void DoFloodTile(TileIndex target)
1040 assert(!IsWaterTile(target));
1042 bool flooded = false; // Will be set to true if something is changed.
1044 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
1046 Slope tileh = GetTileSlope(target);
1047 if (tileh != SLOPE_FLAT) {
1048 /* make coast.. */
1049 switch (GetTileType(target)) {
1050 case TT_RAILWAY:
1051 if (IsTileSubtype(target, TT_TRACK)) {
1052 FloodVehicles(target);
1053 flooded = FloodHalftile(target);
1055 break;
1057 case TT_GROUND:
1058 if (IsTreeTile(target) && !IsSlopeWithOneCornerRaised(tileh)) {
1059 SetClearGroundDensity(target, GROUND_SHORE, 3, true);
1060 MarkTileDirtyByTile(target);
1061 flooded = true;
1062 break;
1064 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1065 MakeShore(target);
1066 MarkTileDirtyByTile(target);
1067 flooded = true;
1069 break;
1071 default:
1072 break;
1074 } else {
1075 /* Flood vehicles */
1076 FloodVehicles(target);
1078 /* flood flat tile */
1079 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1080 MakeSea(target);
1081 MarkTileDirtyByTile(target);
1082 flooded = true;
1086 if (flooded) {
1087 /* Mark surrounding canal tiles dirty too to avoid glitches */
1088 MarkCanalsAndRiversAroundDirty(target);
1090 /* update signals if needed */
1091 UpdateSignalsInBuffer();
1094 cur_company.Restore();
1098 * Drys a tile up.
1100 static void DoDryUp(TileIndex tile)
1102 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
1104 switch (GetTileType(tile)) {
1105 case TT_RAILWAY:
1106 assert(IsTileSubtype(tile, TT_TRACK));
1107 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
1109 RailGroundType new_ground;
1110 switch (GetTrackBits(tile)) {
1111 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
1112 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
1113 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
1114 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
1115 default: NOT_REACHED();
1117 SetRailGroundType(tile, new_ground);
1118 MarkTileDirtyByTile(tile);
1119 break;
1121 case TT_GROUND:
1122 assert(IsTreeTile(tile));
1123 SetClearGroundDensity(tile, GROUND_GRASS, 3, true);
1124 MarkTileDirtyByTile(tile);
1125 break;
1127 case TT_WATER:
1128 assert(IsCoast(tile));
1130 if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1131 MakeClear(tile, GROUND_GRASS, 3);
1132 MarkTileDirtyByTile(tile);
1134 break;
1136 default: NOT_REACHED();
1139 cur_company.Restore();
1143 * Let a water tile floods its diagonal adjoining tiles
1144 * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track()
1146 * @param tile the water/shore tile that floods
1148 void TileLoop_Water(TileIndex tile)
1150 if (IsWaterTile(tile)) AmbientSoundEffect(tile);
1152 switch (GetFloodingBehaviour(tile)) {
1153 case FLOOD_ACTIVE:
1154 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
1155 TileIndex dest = tile + TileOffsByDir(dir);
1156 if (!IsValidTile(dest)) continue;
1157 /* do not try to flood water tiles - increases performance a lot */
1158 if (IsWaterTile(dest)) continue;
1160 /* GROUND_SHORE is the sign of a previous flood. */
1161 if ((IsClearTile(dest) || IsTreeTile(dest)) && IsClearGround (dest, GROUND_SHORE)) continue;
1163 int z_dest;
1164 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
1165 if (z_dest > 0) continue;
1167 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
1169 DoFloodTile(dest);
1171 break;
1173 case FLOOD_DRYUP: {
1174 Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
1175 uint dir;
1176 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
1177 TileIndex dest = tile + TileOffsByDir((Direction)dir);
1178 if (!IsValidTile(dest)) continue;
1180 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
1181 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
1183 DoDryUp(tile);
1184 break;
1187 default: return;
1191 void ConvertGroundTilesIntoWaterTiles()
1193 int z;
1195 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
1196 Slope slope = GetTileSlope(tile, &z);
1197 if (IsGroundTile(tile) && z == 0) {
1198 /* Make both water for tiles at level 0
1199 * and make shore, as that looks much better
1200 * during the generation. */
1201 switch (slope) {
1202 case SLOPE_FLAT:
1203 MakeSea(tile);
1204 break;
1206 case SLOPE_N:
1207 case SLOPE_E:
1208 case SLOPE_S:
1209 case SLOPE_W:
1210 MakeShore(tile);
1211 break;
1213 default:
1214 uint dir;
1215 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
1216 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
1217 Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
1218 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
1219 MakeShore(tile);
1220 break;
1223 break;
1229 static TrackdirBits GetTileWaterwayStatus_Water(TileIndex tile, DiagDirection side)
1231 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
1233 TrackBits ts;
1235 switch (GetWaterTileType(tile)) {
1236 case WATER_TILE_CLEAR: ts = IsTileFlat(tile) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
1237 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break;
1238 case WATER_TILE_DEPOT: ts = DiagDirToDiagTrackBits(GetShipDepotDirection(tile)); break;
1239 default: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
1241 if (TileX(tile) == 0) {
1242 /* NE border: remove tracks that connects NE tile edge */
1243 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
1245 if (TileY(tile) == 0) {
1246 /* NW border: remove tracks that connects NW tile edge */
1247 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
1249 return TrackBitsToTrackdirBits(ts);
1252 static bool ClickTile_Water(TileIndex tile)
1254 if (IsShipDepot(tile)) {
1255 ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
1256 return true;
1258 return false;
1261 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
1263 if (!IsTileOwner(tile, old_owner)) return;
1265 bool is_lock_middle = GetWaterTileType(tile) == WATER_TILE_LOCK_MIDDLE;
1267 /* No need to dirty company windows here, we'll redraw the whole screen anyway. */
1268 if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1269 if (new_owner != INVALID_OWNER) {
1270 if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1271 /* Only subtract from the old owner here if the new owner is valid,
1272 * otherwise we clear ship depots and canal water below. */
1273 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
1274 Company::Get(old_owner)->infrastructure.water--;
1275 Company::Get(new_owner)->infrastructure.water++;
1277 if (IsShipDepot(tile)) {
1278 Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
1279 Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
1282 SetTileOwner(tile, new_owner);
1283 return;
1286 /* Remove depot */
1287 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
1289 /* Set owner of canals and locks ... and also canal under dock there was before.
1290 * Check if the new owner after removing depot isn't OWNER_WATER. */
1291 if (IsTileOwner(tile, old_owner)) {
1292 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
1293 SetTileOwner(tile, OWNER_NONE);
1297 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
1299 /* Canals can't be terraformed */
1300 if (IsPlainWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
1302 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
1306 extern const TileTypeProcs _tile_type_water_procs = {
1307 DrawTile_Water, // draw_tile_proc
1308 GetSlopePixelZ_Water, // get_slope_z_proc
1309 ClearTile_Water, // clear_tile_proc
1310 NULL, // add_accepted_cargo_proc
1311 GetTileDesc_Water, // get_tile_desc_proc
1312 NULL, // get_tile_railway_status_proc
1313 NULL, // get_tile_road_status_proc
1314 GetTileWaterwayStatus_Water, // get_tile_waterway_status_proc
1315 ClickTile_Water, // click_tile_proc
1316 NULL, // animate_tile_proc
1317 TileLoop_Water, // tile_loop_proc
1318 ChangeTileOwner_Water, // change_tile_owner_proc
1319 NULL, // add_produced_cargo_proc
1320 GetFoundation_Water, // get_foundation_proc
1321 TerraformTile_Water, // terraform_tile_proc