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