OpenTTD
water_cmd.cpp
Go to the documentation of this file.
1 /* $Id: water_cmd.cpp 27893 2017-08-13 18:38:42Z frosch $ */
2 
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  */
9 
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 "industry_map.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 "clear_map.h"
29 #include "tree_map.h"
30 #include "aircraft.h"
31 #include "effectvehicle_func.h"
32 #include "tunnelbridge_map.h"
33 #include "station_base.h"
34 #include "ai/ai.hpp"
35 #include "game/game.hpp"
36 #include "core/random_func.hpp"
37 #include "core/backup_type.hpp"
38 #include "date_func.h"
39 #include "company_base.h"
40 #include "company_gui.h"
41 #include "newgrf_generic.h"
42 
43 #include "table/strings.h"
44 
45 #include "safeguards.h"
46 
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
66 };
67 
74 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
75 {
76  if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
77 }
78 
86 {
87  for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
89  }
90 }
91 
92 
102 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
103 {
104  Axis axis = Extract<Axis, 0, 1>(p1);
105 
106  TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
107 
108  if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
109  return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
110  }
111 
112  if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
113 
114  if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
115  /* Prevent depots on rapids */
116  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
117  }
118 
119  if (!Depot::CanAllocateItem()) return CMD_ERROR;
120 
121  WaterClass wc1 = GetWaterClass(tile);
122  WaterClass wc2 = GetWaterClass(tile2);
123  CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
124 
125  bool add_cost = !IsWaterTile(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);
130  }
131  add_cost = !IsWaterTile(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);
136  }
137 
138  if (flags & DC_EXEC) {
139  Depot *depot = new Depot(tile);
140  depot->build_date = _date;
141 
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;
145  }
146  Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR;
148 
149  MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
150  MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
151  MarkTileDirtyByTile(tile);
152  MarkTileDirtyByTile(tile2);
153  MakeDefaultName(depot);
154  }
155 
156  return cost;
157 }
158 
159 void MakeWaterKeepingClass(TileIndex tile, Owner o)
160 {
161  WaterClass wc = GetWaterClass(tile);
162 
163  /* Autoslope might turn an originally canal or river tile into land */
164  int z;
165  Slope slope = GetTileSlope(tile, &z);
166 
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. */
171  if (c != NULL) {
172  c->infrastructure.water--;
174  }
175  /* Sloped canals are locks and no natural water remains whatever the slope direction */
176  wc = WATER_CLASS_INVALID;
177  }
178 
179  /* Only river water should be restored on appropriate slopes. Other water would be invalid on slopes */
181  wc = WATER_CLASS_INVALID;
182  }
183  }
184 
185  if (wc == WATER_CLASS_SEA && z > 0) {
186  /* Update company infrastructure count. */
188  if (c != NULL) {
189  c->infrastructure.water++;
191  }
192 
193  wc = WATER_CLASS_CANAL;
194  }
195 
196  /* Zero map array and terminate animation */
197  DoClearSquare(tile);
198 
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;
205  }
206 
207  MarkTileDirtyByTile(tile);
208 }
209 
210 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
211 {
212  if (!IsShipDepot(tile)) return CMD_ERROR;
213 
214  CommandCost ret = CheckTileOwnership(tile);
215  if (ret.Failed()) return ret;
216 
217  TileIndex tile2 = GetOtherShipDepotTile(tile);
218 
219  /* do not check for ship on tile when company goes bankrupt */
220  if (!(flags & DC_BANKRUPT)) {
222  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
223  if (ret.Failed()) return ret;
224  }
225 
226  if (flags & DC_EXEC) {
227  delete Depot::GetByTile(tile);
228 
230  if (c != NULL) {
233  }
234 
235  MakeWaterKeepingClass(tile, GetTileOwner(tile));
236  MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
237  }
238 
239  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
240 }
241 
250 {
252 
253  int delta = TileOffsByDiagDir(dir);
255  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
256  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
257  if (ret.Failed()) return ret;
258 
259  /* middle tile */
260  WaterClass wc_middle = IsWaterTile(tile) ? GetWaterClass(tile) : WATER_CLASS_CANAL;
261  ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
262  if (ret.Failed()) return ret;
263  cost.AddCost(ret);
264 
265  /* lower tile */
266  if (!IsWaterTile(tile - delta)) {
267  ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
268  if (ret.Failed()) return ret;
269  cost.AddCost(ret);
270  cost.AddCost(_price[PR_BUILD_CANAL]);
271  }
272  if (!IsTileFlat(tile - delta)) {
273  return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
274  }
275  WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
276 
277  /* upper tile */
278  if (!IsWaterTile(tile + delta)) {
279  ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
280  if (ret.Failed()) return ret;
281  cost.AddCost(ret);
282  cost.AddCost(_price[PR_BUILD_CANAL]);
283  }
284  if (!IsTileFlat(tile + delta)) {
285  return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
286  }
287  WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
288 
289  if (IsBridgeAbove(tile) || IsBridgeAbove(tile - delta) || IsBridgeAbove(tile + delta)) {
290  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
291  }
292 
293  if (flags & DC_EXEC) {
294  /* Update company infrastructure counts. */
296  if (c != NULL) {
297  /* Counts for the water. */
298  if (!IsWaterTile(tile - delta)) c->infrastructure.water++;
299  if (!IsWaterTile(tile + delta)) c->infrastructure.water++;
300  /* Count for the lock itself. */
301  c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock is three tiles.
303  }
304 
305  MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
306  MarkTileDirtyByTile(tile);
307  MarkTileDirtyByTile(tile - delta);
308  MarkTileDirtyByTile(tile + delta);
309  MarkCanalsAndRiversAroundDirty(tile - delta);
310  MarkCanalsAndRiversAroundDirty(tile + delta);
311  }
312  cost.AddCost(_price[PR_BUILD_LOCK]);
313 
314  return cost;
315 }
316 
324 {
325  if (GetTileOwner(tile) != OWNER_NONE) {
326  CommandCost ret = CheckTileOwnership(tile);
327  if (ret.Failed()) return ret;
328  }
329 
331 
332  /* make sure no vehicle is on the tile. */
334  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
335  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
336  if (ret.Failed()) return ret;
337 
338  if (flags & DC_EXEC) {
339  /* Remove middle part from company infrastructure count. */
341  if (c != NULL) {
342  c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock.
344  }
345 
346  if (GetWaterClass(tile) == WATER_CLASS_RIVER) {
347  MakeRiver(tile, Random());
348  } else {
349  DoClearSquare(tile);
350  }
351  MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta));
352  MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
354  MarkCanalsAndRiversAroundDirty(tile - delta);
355  MarkCanalsAndRiversAroundDirty(tile + delta);
356  }
357 
358  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
359 }
360 
370 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
371 {
373  if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
374 
375  return DoBuildLock(tile, dir, flags);
376 }
377 
380 {
382  return false;
383 }
384 
394 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
395 {
396  WaterClass wc = Extract<WaterClass, 0, 2>(p2);
397  if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
398 
399  /* Outside of the editor you can only build canals, not oceans */
400  if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
401 
402  TileArea ta(tile, p1);
403 
404  /* Outside the editor you can only drag canals, and not areas */
405  if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
406 
408  TILE_AREA_LOOP(tile, ta) {
409  CommandCost ret;
410 
411  Slope slope = GetTileSlope(tile);
412  if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
413  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
414  }
415 
416  /* can't make water of water! */
417  if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
418 
419  bool water = IsWaterTile(tile);
420  ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
421  if (ret.Failed()) return ret;
422 
423  if (!water) cost.AddCost(ret);
424 
425  if (flags & DC_EXEC) {
426  switch (wc) {
427  case WATER_CLASS_RIVER:
428  MakeRiver(tile, Random());
429  if (_game_mode == GM_EDITOR) {
430  TileIndex tile2 = tile;
431  CircularTileSearch(&tile2, 5, RiverModifyDesertZone, NULL);
432  }
433  break;
434 
435  case WATER_CLASS_SEA:
436  if (TileHeight(tile) == 0) {
437  MakeSea(tile);
438  break;
439  }
440  FALLTHROUGH;
441 
442  default:
443  MakeCanal(tile, _current_company, Random());
445  Company::Get(_current_company)->infrastructure.water++;
447  }
448  break;
449  }
450  MarkTileDirtyByTile(tile);
452  }
453 
454  cost.AddCost(_price[PR_BUILD_CANAL]);
455  }
456 
457  if (cost.GetCost() == 0) {
458  return_cmd_error(STR_ERROR_ALREADY_BUILT);
459  } else {
460  return cost;
461  }
462 }
463 
464 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
465 {
466  switch (GetWaterTileType(tile)) {
467  case WATER_TILE_CLEAR: {
468  if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
469 
470  Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
471  /* Make sure freeform edges are allowed or it's not an edge tile. */
472  if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
473  !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
474  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
475  }
476 
477  /* Make sure no vehicle is on the tile */
479  if (ret.Failed()) return ret;
480 
481  Owner owner = GetTileOwner(tile);
482  if (owner != OWNER_WATER && owner != OWNER_NONE) {
483  CommandCost ret = CheckTileOwnership(tile);
484  if (ret.Failed()) return ret;
485  }
486 
487  if (flags & DC_EXEC) {
488  if (IsCanal(tile) && Company::IsValidID(owner)) {
489  Company::Get(owner)->infrastructure.water--;
491  }
492  DoClearSquare(tile);
494  }
495 
496  return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
497  }
498 
499  case WATER_TILE_COAST: {
500  Slope slope = GetTileSlope(tile);
501 
502  /* Make sure no vehicle is on the tile */
504  if (ret.Failed()) return ret;
505 
506  if (flags & DC_EXEC) {
507  DoClearSquare(tile);
509  }
510  if (IsSlopeWithOneCornerRaised(slope)) {
511  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
512  } else {
513  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
514  }
515  }
516 
517  case WATER_TILE_LOCK: {
518  static const TileIndexDiffC _lock_tomiddle_offs[][DIAGDIR_END] = {
519  /* NE SE SW NW */
520  { { 0, 0}, {0, 0}, { 0, 0}, {0, 0} }, // LOCK_PART_MIDDLE
521  { {-1, 0}, {0, 1}, { 1, 0}, {0, -1} }, // LOCK_PART_LOWER
522  { { 1, 0}, {0, -1}, {-1, 0}, {0, 1} }, // LOCK_PART_UPPER
523  };
524 
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  return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetLockPart(tile)][GetLockDirection(tile)]), flags);
529  }
530 
531  case WATER_TILE_DEPOT:
532  if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
533  return RemoveShipDepot(tile, flags);
534 
535  default:
536  NOT_REACHED();
537  }
538 }
539 
549 {
550  switch (GetTileType(tile)) {
551  case MP_WATER:
552  switch (GetWaterTileType(tile)) {
553  default: NOT_REACHED();
554  case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
556 
557  case WATER_TILE_COAST:
558  switch (GetTileSlope(tile)) {
559  case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
560  case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
561  case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
562  case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
563  default: return false;
564  }
565  }
566 
567  case MP_RAILWAY:
568  if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
569  assert(IsPlainRail(tile));
570  switch (GetTileSlope(tile)) {
571  case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
572  case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
573  case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
574  case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
575  default: return false;
576  }
577  }
578  return false;
579 
580  case MP_STATION:
581  if (IsOilRig(tile)) {
582  /* Do not draw waterborders inside of industries.
583  * Note: There is no easy way to detect the industry of an oilrig tile. */
584  TileIndex src_tile = tile + TileOffsByDir(from);
585  if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
586  (IsTileType(src_tile, MP_INDUSTRY))) return true;
587 
588  return IsTileOnWater(tile);
589  }
590  return (IsDock(tile) && IsTileFlat(tile)) || IsBuoy(tile);
591 
592  case MP_INDUSTRY: {
593  /* Do not draw waterborders inside of industries.
594  * Note: There is no easy way to detect the industry of an oilrig tile. */
595  TileIndex src_tile = tile + TileOffsByDir(from);
596  if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
597  (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
598 
599  return IsTileOnWater(tile);
600  }
601 
602  case MP_OBJECT: return IsTileOnWater(tile);
603 
605 
606  case MP_VOID: return true; // consider map border as water, esp. for rivers
607 
608  default: return false;
609  }
610 }
611 
619 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
620 {
621  if (base != SPR_FLAT_WATER_TILE) {
622  /* Only call offset callback if the sprite is NewGRF-provided. */
623  offset = GetCanalSpriteOffset(feature, tile, offset);
624  }
625  DrawGroundSprite(base + offset, PAL_NONE);
626 }
627 
634 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
635 {
636  CanalFeature feature;
637  SpriteID base = 0;
638  if (canal) {
639  feature = CF_DIKES;
640  base = GetCanalSprite(CF_DIKES, tile);
641  if (base == 0) base = SPR_CANAL_DIKES_BASE;
642  } else {
643  feature = CF_RIVER_EDGE;
644  base = GetCanalSprite(CF_RIVER_EDGE, tile);
645  if (base == 0) return; // Don't draw if no sprites provided.
646  }
647 
648  uint wa;
649 
650  /* determine the edges around with water. */
651  wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
652  wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
653  wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
654  wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
655 
656  if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
657  if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
658  if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
659  if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
660 
661  /* right corner */
662  switch (wa & 0x03) {
663  case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
664  case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
665  }
666 
667  /* bottom corner */
668  switch (wa & 0x06) {
669  case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
670  case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
671  }
672 
673  /* left corner */
674  switch (wa & 0x0C) {
675  case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
676  case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
677  }
678 
679  /* upper corner */
680  switch (wa & 0x09) {
681  case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
682  case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
683  }
684 }
685 
687 static void DrawSeaWater(TileIndex tile)
688 {
689  DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
690 }
691 
693 static void DrawCanalWater(TileIndex tile)
694 {
695  SpriteID image = SPR_FLAT_WATER_TILE;
696  if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
697  /* First water slope sprite is flat water. */
698  image = GetCanalSprite(CF_WATERSLOPE, tile);
699  if (image == 0) image = SPR_FLAT_WATER_TILE;
700  }
701  DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
702 
703  DrawWaterEdges(true, 0, tile);
704 }
705 
706 #include "table/water_land.h"
707 
717 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
718 {
719  /* Don't draw if buildings are invisible. */
720  if (IsInvisibilitySet(TO_BUILDINGS)) return;
721 
722  for (; !dtss->IsTerminator(); dtss++) {
723  uint tile_offs = offset + dtss->image.sprite;
724  if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
725  AddSortableSpriteToDraw(base + tile_offs, palette,
726  ti->x + dtss->delta_x, ti->y + dtss->delta_y,
727  dtss->size_x, dtss->size_y,
728  dtss->size_z, ti->z + dtss->delta_z,
730  }
731 }
732 
734 static void DrawWaterLock(const TileInfo *ti)
735 {
736  int part = GetLockPart(ti->tile);
737  const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)];
738 
739  /* Draw ground sprite. */
740  SpriteID image = dts.ground.sprite;
741 
742  SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
743  if (water_base == 0) {
744  /* Use default sprites. */
745  water_base = SPR_CANALS_BASE;
746  } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
747  /* NewGRF supplies a flat sprite as first sprite. */
748  if (image == SPR_FLAT_WATER_TILE) {
749  image = water_base;
750  } else {
751  image++;
752  }
753  }
754 
755  if (image < 5) image += water_base;
756  DrawGroundSprite(image, PAL_NONE);
757 
758  /* Draw structures. */
759  uint zoffs = 0;
760  SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
761 
762  if (base == 0) {
763  /* If no custom graphics, use defaults. */
764  base = SPR_LOCK_BASE;
765  uint8 z_threshold = part == LOCK_PART_UPPER ? 8 : 0;
766  zoffs = ti->z > z_threshold ? 24 : 0;
767  }
768 
769  DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
770 }
771 
773 static void DrawWaterDepot(const TileInfo *ti)
774 {
775  DrawWaterClassGround(ti);
776  DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
777 }
778 
779 static void DrawRiverWater(const TileInfo *ti)
780 {
781  SpriteID image = SPR_FLAT_WATER_TILE;
782  uint offset = 0;
783  uint edges_offset = 0;
784 
785  if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
786  image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
787  if (image == 0) {
788  switch (ti->tileh) {
789  case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
790  case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
791  case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
792  case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
793  default: image = SPR_FLAT_WATER_TILE; break;
794  }
795  } else {
796  /* Flag bit 0 indicates that the first sprite is flat water. */
797  offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
798 
799  switch (ti->tileh) {
800  case SLOPE_SE: edges_offset += 12; break;
801  case SLOPE_NE: offset += 1; edges_offset += 24; break;
802  case SLOPE_SW: offset += 2; edges_offset += 36; break;
803  case SLOPE_NW: offset += 3; edges_offset += 48; break;
804  default: offset = 0; break;
805  }
806 
807  offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
808  }
809  }
810 
811  DrawGroundSprite(image + offset, PAL_NONE);
812 
813  /* Draw river edges if available. */
814  DrawWaterEdges(false, edges_offset, ti->tile);
815 }
816 
817 void DrawShoreTile(Slope tileh)
818 {
819  /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
820  * This allows to calculate the proper sprite to display for this Slope */
821  static const byte tileh_to_shoresprite[32] = {
822  0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
823  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
824  };
825 
826  assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
827  assert(tileh != SLOPE_FLAT); // Shore is never flat
828 
829  assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
830 
831  DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
832 }
833 
834 void DrawWaterClassGround(const TileInfo *ti)
835 {
836  switch (GetWaterClass(ti->tile)) {
837  case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
838  case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
839  case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
840  default: NOT_REACHED();
841  }
842 }
843 
844 static void DrawTile_Water(TileInfo *ti)
845 {
846  switch (GetWaterTileType(ti->tile)) {
847  case WATER_TILE_CLEAR:
848  DrawWaterClassGround(ti);
849  DrawBridgeMiddle(ti);
850  break;
851 
852  case WATER_TILE_COAST: {
853  DrawShoreTile(ti->tileh);
854  DrawBridgeMiddle(ti);
855  break;
856  }
857 
858  case WATER_TILE_LOCK:
859  DrawWaterLock(ti);
860  break;
861 
862  case WATER_TILE_DEPOT:
863  DrawWaterDepot(ti);
864  break;
865  }
866 }
867 
868 void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part)
869 {
870  const DrawTileSprites &dts = _shipdepot_display_data[axis][part];
871 
872  DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
873  DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
874 }
875 
876 
877 static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y)
878 {
879  int z;
880  Slope tileh = GetTilePixelSlope(tile, &z);
881 
882  return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
883 }
884 
885 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
886 {
887  return FOUNDATION_NONE;
888 }
889 
890 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
891 {
892  switch (GetWaterTileType(tile)) {
893  case WATER_TILE_CLEAR:
894  switch (GetWaterClass(tile)) {
895  case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
896  case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
897  case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
898  default: NOT_REACHED(); break;
899  }
900  break;
901  case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
902  case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
903  case WATER_TILE_DEPOT:
904  td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
905  td->build_date = Depot::GetByTile(tile)->build_date;
906  break;
907  default: NOT_REACHED(); break;
908  }
909 
910  td->owner[0] = GetTileOwner(tile);
911 }
912 
918 static void FloodVehicle(Vehicle *v)
919 {
920  uint pass = v->Crash(true);
921 
922  AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
923  Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
924  SetDParam(0, pass);
925  AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NT_ACCIDENT, v->index);
927  if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
928 }
929 
936 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
937 {
938  if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
939 
940  switch (v->type) {
941  default: break;
942 
943  case VEH_AIRCRAFT: {
944  if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
945  if (v->subtype == AIR_SHADOW) break;
946 
947  /* We compare v->z_pos against delta_z + 1 because the shadow
948  * is at delta_z and the actual aircraft at delta_z + 1. */
949  const Station *st = Station::GetByTile(v->tile);
950  const AirportFTAClass *airport = st->airport.GetFTA();
951  if (v->z_pos != airport->delta_z + 1) break;
952 
953  FloodVehicle(v);
954  break;
955  }
956 
957  case VEH_TRAIN:
958  case VEH_ROAD: {
959  int z = *(int*)data;
960  if (v->z_pos > z) break;
961  FloodVehicle(v->First());
962  break;
963  }
964  }
965 
966  return NULL;
967 }
968 
974 static void FloodVehicles(TileIndex tile)
975 {
976  int z = 0;
977 
978  if (IsAirportTile(tile)) {
979  const Station *st = Station::GetByTile(tile);
980  TILE_AREA_LOOP(tile, st->airport) {
981  if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
982  }
983 
984  /* No vehicle could be flooded on this airport anymore */
985  return;
986  }
987 
988  if (!IsBridgeTile(tile)) {
990  return;
991  }
992 
993  TileIndex end = GetOtherBridgeEnd(tile);
994  z = GetBridgePixelHeight(tile);
995 
998 }
999 
1006 {
1007  /* FLOOD_ACTIVE: 'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
1008  * FLOOD_DRYUP: coast with more than one corner raised, coast with rail-track, coast with trees
1009  * FLOOD_PASSIVE: (not used)
1010  * FLOOD_NONE: canals, rivers, everything else
1011  */
1012  switch (GetTileType(tile)) {
1013  case MP_WATER:
1014  if (IsCoast(tile)) {
1015  Slope tileh = GetTileSlope(tile);
1017  }
1018  FALLTHROUGH;
1019  case MP_STATION:
1020  case MP_INDUSTRY:
1021  case MP_OBJECT:
1022  return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
1023 
1024  case MP_RAILWAY:
1025  if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
1027  }
1028  return FLOOD_NONE;
1029 
1030  case MP_TREES:
1031  return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
1032 
1033  default:
1034  return FLOOD_NONE;
1035  }
1036 }
1037 
1042 {
1043  assert(!IsTileType(target, MP_WATER));
1044 
1045  bool flooded = false; // Will be set to true if something is changed.
1046 
1047  Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
1048 
1049  Slope tileh = GetTileSlope(target);
1050  if (tileh != SLOPE_FLAT) {
1051  /* make coast.. */
1052  switch (GetTileType(target)) {
1053  case MP_RAILWAY: {
1054  if (!IsPlainRail(target)) break;
1055  FloodVehicles(target);
1056  flooded = FloodHalftile(target);
1057  break;
1058  }
1059 
1060  case MP_TREES:
1061  if (!IsSlopeWithOneCornerRaised(tileh)) {
1063  MarkTileDirtyByTile(target);
1064  flooded = true;
1065  break;
1066  }
1067  FALLTHROUGH;
1068 
1069  case MP_CLEAR:
1070  if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1071  MakeShore(target);
1072  MarkTileDirtyByTile(target);
1073  flooded = true;
1074  }
1075  break;
1076 
1077  default:
1078  break;
1079  }
1080  } else {
1081  /* Flood vehicles */
1082  FloodVehicles(target);
1083 
1084  /* flood flat tile */
1085  if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1086  MakeSea(target);
1087  MarkTileDirtyByTile(target);
1088  flooded = true;
1089  }
1090  }
1091 
1092  if (flooded) {
1093  /* Mark surrounding canal tiles dirty too to avoid glitches */
1095 
1096  /* update signals if needed */
1098  }
1099 
1100  cur_company.Restore();
1101 }
1102 
1106 static void DoDryUp(TileIndex tile)
1107 {
1108  Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
1109 
1110  switch (GetTileType(tile)) {
1111  case MP_RAILWAY:
1112  assert(IsPlainRail(tile));
1113  assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
1114 
1115  RailGroundType new_ground;
1116  switch (GetTrackBits(tile)) {
1117  case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
1118  case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
1119  case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
1120  case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
1121  default: NOT_REACHED();
1122  }
1123  SetRailGroundType(tile, new_ground);
1124  MarkTileDirtyByTile(tile);
1125  break;
1126 
1127  case MP_TREES:
1129  MarkTileDirtyByTile(tile);
1130  break;
1131 
1132  case MP_WATER:
1133  assert(IsCoast(tile));
1134 
1135  if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
1136  MakeClear(tile, CLEAR_GRASS, 3);
1137  MarkTileDirtyByTile(tile);
1138  }
1139  break;
1140 
1141  default: NOT_REACHED();
1142  }
1143 
1144  cur_company.Restore();
1145 }
1146 
1154 {
1155  if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile);
1156 
1157  switch (GetFloodingBehaviour(tile)) {
1158  case FLOOD_ACTIVE:
1159  for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
1160  TileIndex dest = tile + TileOffsByDir(dir);
1161  if (!IsValidTile(dest)) continue;
1162  /* do not try to flood water tiles - increases performance a lot */
1163  if (IsTileType(dest, MP_WATER)) continue;
1164 
1165  /* TREE_GROUND_SHORE is the sign of a previous flood. */
1166  if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
1167 
1168  int z_dest;
1169  Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
1170  if (z_dest > 0) continue;
1171 
1172  if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
1173 
1174  DoFloodTile(dest);
1175  }
1176  break;
1177 
1178  case FLOOD_DRYUP: {
1179  Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
1180  uint dir;
1181  FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
1182  TileIndex dest = tile + TileOffsByDir((Direction)dir);
1183  if (!IsValidTile(dest)) continue;
1184 
1185  FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
1186  if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
1187  }
1188  DoDryUp(tile);
1189  break;
1190  }
1191 
1192  default: return;
1193  }
1194 }
1195 
1196 void ConvertGroundTilesIntoWaterTiles()
1197 {
1198  int z;
1199 
1200  for (TileIndex tile = 0; tile < MapSize(); ++tile) {
1201  Slope slope = GetTileSlope(tile, &z);
1202  if (IsTileType(tile, MP_CLEAR) && z == 0) {
1203  /* Make both water for tiles at level 0
1204  * and make shore, as that looks much better
1205  * during the generation. */
1206  switch (slope) {
1207  case SLOPE_FLAT:
1208  MakeSea(tile);
1209  break;
1210 
1211  case SLOPE_N:
1212  case SLOPE_E:
1213  case SLOPE_S:
1214  case SLOPE_W:
1215  MakeShore(tile);
1216  break;
1217 
1218  default:
1219  uint dir;
1221  TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
1222  Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
1223  if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
1224  MakeShore(tile);
1225  break;
1226  }
1227  }
1228  break;
1229  }
1230  }
1231  }
1232 }
1233 
1234 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
1235 {
1236  static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
1237 
1238  TrackBits ts;
1239 
1240  if (mode != TRANSPORT_WATER) return 0;
1241 
1242  switch (GetWaterTileType(tile)) {
1243  case WATER_TILE_CLEAR: ts = IsTileFlat(tile) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
1244  case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break;
1245  case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
1246  case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
1247  default: return 0;
1248  }
1249  if (TileX(tile) == 0) {
1250  /* NE border: remove tracks that connects NE tile edge */
1252  }
1253  if (TileY(tile) == 0) {
1254  /* NW border: remove tracks that connects NW tile edge */
1256  }
1258 }
1259 
1260 static bool ClickTile_Water(TileIndex tile)
1261 {
1262  if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
1264  return true;
1265  }
1266  return false;
1267 }
1268 
1269 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
1270 {
1271  if (!IsTileOwner(tile, old_owner)) return;
1272 
1273  bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
1274 
1275  /* No need to dirty company windows here, we'll redraw the whole screen anyway. */
1276  if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1277  if (new_owner != INVALID_OWNER) {
1278  if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1279  /* Only subtract from the old owner here if the new owner is valid,
1280  * otherwise we clear ship depots and canal water below. */
1281  if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
1282  Company::Get(old_owner)->infrastructure.water--;
1283  Company::Get(new_owner)->infrastructure.water++;
1284  }
1285  if (IsShipDepot(tile)) {
1286  Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
1287  Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
1288  }
1289 
1290  SetTileOwner(tile, new_owner);
1291  return;
1292  }
1293 
1294  /* Remove depot */
1295  if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
1296 
1297  /* Set owner of canals and locks ... and also canal under dock there was before.
1298  * Check if the new owner after removing depot isn't OWNER_WATER. */
1299  if (IsTileOwner(tile, old_owner)) {
1300  if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
1301  SetTileOwner(tile, OWNER_NONE);
1302  }
1303 }
1304 
1305 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
1306 {
1307  return VETSB_CONTINUE;
1308 }
1309 
1310 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
1311 {
1312  /* Canals can't be terraformed */
1313  if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
1314 
1315  return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
1316 }
1317 
1318 
1319 extern const TileTypeProcs _tile_type_water_procs = {
1320  DrawTile_Water, // draw_tile_proc
1321  GetSlopePixelZ_Water, // get_slope_z_proc
1322  ClearTile_Water, // clear_tile_proc
1323  NULL, // add_accepted_cargo_proc
1324  GetTileDesc_Water, // get_tile_desc_proc
1325  GetTileTrackStatus_Water, // get_tile_track_status_proc
1326  ClickTile_Water, // click_tile_proc
1327  NULL, // animate_tile_proc
1328  TileLoop_Water, // tile_loop_proc
1329  ChangeTileOwner_Water, // change_tile_owner_proc
1330  NULL, // add_produced_cargo_proc
1331  VehicleEnter_Water, // vehicle_enter_tile_proc
1332  GetFoundation_Water, // get_foundation_proc
1333  TerraformTile_Water, // terraform_tile_proc
1334 };