# water_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: water_cmd.cpp 20148 2010-07-14 19:29:13Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "cmd_helper.h"
    00014 #include "landscape.h"
    00015 #include "viewport_func.h"
    00016 #include "command_func.h"
    00017 #include "town.h"
    00018 #include "news_func.h"
    00019 #include "depot_base.h"
    00020 #include "depot_func.h"
    00021 #include "water.h"
    00022 #include "industry_map.h"
    00023 #include "newgrf_canal.h"
    00024 #include "strings_func.h"
    00025 #include "functions.h"
    00026 #include "vehicle_func.h"
    00027 #include "sound_func.h"
    00028 #include "company_func.h"
    00029 #include "clear_map.h"
    00030 #include "tree_map.h"
    00031 #include "aircraft.h"
    00032 #include "effectvehicle_func.h"
    00033 #include "tunnelbridge_map.h"
    00034 #include "station_base.h"
    00035 #include "ai/ai.hpp"
    00036 #include "core/random_func.hpp"
    00037
    00038 #include "table/sprites.h"
    00039 #include "table/strings.h"
    00040
    00044 static const uint8 _flood_from_dirs[] = {
    00045   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
    00046   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
    00047   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
    00048   (1 << DIR_NE),                                                 // SLOPE_SW
    00049   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
    00050   0,                                                             // SLOPE_EW
    00051   (1 << DIR_NW),                                                 // SLOPE_SE
    00052   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
    00053   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
    00054   (1 << DIR_SE),                                                 // SLOPE_NW
    00055   0,                                                             // SLOPE_NS
    00056   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
    00057   (1 << DIR_SW),                                                 // SLOPE_NE
    00058   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
    00059   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
    00060 };
    00061
    00068 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
    00069 {
    00070   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
    00071 }
    00072
    00079 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
    00080 {
    00081   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    00082     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
    00083   }
    00084 }
    00085
    00086
    00095 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00096 {
    00097   Axis axis = Extract<Axis, 0, 1>(p1);
    00098
    00099   TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
    00100
    00101   if (!IsWaterTile(tile) || !IsWaterTile(tile2)) {
    00102     return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
    00103   }
    00104
    00105   if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
    00106
    00107   if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
    00108     /* Prevent depots on rapids */
    00109     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
    00110   }
    00111
    00112   WaterClass wc1 = GetWaterClass(tile);
    00113   WaterClass wc2 = GetWaterClass(tile2);
    00114   CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00115   if (ret.Failed()) return CMD_ERROR;
    00116   ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00117   if (ret.Failed()) return CMD_ERROR;
    00118
    00119   if (!Depot::CanAllocateItem()) return CMD_ERROR;
    00120
    00121   if (flags & DC_EXEC) {
    00122     Depot *depot = new Depot(tile);
    00123     depot->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
    00124
    00125     MakeShipDepot(tile,  _current_company, depot->index, DEPOT_NORTH, axis, wc1);
    00126     MakeShipDepot(tile2, _current_company, depot->index, DEPOT_SOUTH, axis, wc2);
    00127     MarkTileDirtyByTile(tile);
    00128     MarkTileDirtyByTile(tile2);
    00129   }
    00130
    00131   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
    00132 }
    00133
    00134 void MakeWaterKeepingClass(TileIndex tile, Owner o)
    00135 {
    00136   assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile) || IsOilRig(tile))) || IsTileType(tile, MP_INDUSTRY));
    00137
    00138   WaterClass wc = GetWaterClass(tile);
    00139
    00140   /* Autoslope might turn an originally canal or river tile into land */
    00141   uint z;
    00142   if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
    00143
    00144   if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
    00145
    00146   switch (wc) {
    00147     case WATER_CLASS_SEA:   MakeSea(tile);                break;
    00148     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
    00149     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
    00150     default:                DoClearSquare(tile);          break;
    00151   }
    00152 }
    00153
    00154 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
    00155 {
    00156   if (!IsShipDepot(tile)) return CMD_ERROR;
    00157   if (!CheckTileOwnership(tile)) return CMD_ERROR;
    00158
    00159   TileIndex tile2 = GetOtherShipDepotTile(tile);
    00160
    00161   /* do not check for ship on tile when company goes bankrupt */
    00162   if (!(flags & DC_BANKRUPT)) {
    00163     if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
    00164   }
    00165
    00166   if (flags & DC_EXEC) {
    00167     /* Kill the depot, which is registered at the northernmost tile. Use that one */
    00168     delete Depot::GetByTile(tile);
    00169
    00170     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
    00171     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
    00172     MarkTileDirtyByTile(tile);
    00173     MarkTileDirtyByTile(tile2);
    00174   }
    00175
    00176   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
    00177 }
    00178
    00180 static CommandCost DoBuildShiplift(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
    00181 {
    00182   CommandCost ret;
    00183   int delta;
    00184
    00185   /* middle tile */
    00186   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00187   if (ret.Failed()) return CMD_ERROR;
    00188
    00189   delta = TileOffsByDiagDir(dir);
    00190   /* lower tile */
    00191   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
    00192
    00193   ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00194   if (ret.Failed()) return CMD_ERROR;
    00195   if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
    00196     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00197   }
    00198
    00199   /* upper tile */
    00200   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
    00201
    00202   ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00203   if (ret.Failed()) return CMD_ERROR;
    00204   if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
    00205     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00206   }
    00207
    00208   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
    00209       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
    00210       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
    00211     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
    00212   }
    00213
    00214   if (flags & DC_EXEC) {
    00215     MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
    00216     MarkTileDirtyByTile(tile);
    00217     MarkTileDirtyByTile(tile - delta);
    00218     MarkTileDirtyByTile(tile + delta);
    00219     MarkCanalsAndRiversAroundDirty(tile - delta);
    00220     MarkCanalsAndRiversAroundDirty(tile + delta);
    00221   }
    00222
    00223   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER] * 22 >> 3);
    00224 }
    00225
    00226 static CommandCost RemoveShiplift(TileIndex tile, DoCommandFlag flags)
    00227 {
    00228   TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
    00229
    00230   if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR;
    00231
    00232   /* make sure no vehicle is on the tile. */
    00233   if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta))
    00234     return CMD_ERROR;
    00235
    00236   if (flags & DC_EXEC) {
    00237     DoClearSquare(tile);
    00238     MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
    00239     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
    00240     MarkTileDirtyByTile(tile - delta);
    00241     MarkTileDirtyByTile(tile + delta);
    00242     MarkCanalsAndRiversAroundDirty(tile - delta);
    00243     MarkCanalsAndRiversAroundDirty(tile + delta);
    00244   }
    00245
    00246   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER] * 2);
    00247 }
    00248
    00257 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00258 {
    00259   DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
    00260   if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00261
    00262   /* Disallow building of locks on river rapids */
    00263   if (IsWaterTile(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
    00264
    00265   return DoBuildShiplift(tile, dir, flags);
    00266 }
    00267
    00276 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00277 {
    00278   CommandCost cost(EXPENSES_CONSTRUCTION);
    00279
    00280   if (p1 >= MapSize() || p2 > 2) return CMD_ERROR;
    00281
    00282   /* Outside of the editor you can only build canals, not oceans */
    00283   if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
    00284
    00285   TileArea ta(tile, p1);
    00286
    00287   /* Outside the editor you can only drag canals, and not areas */
    00288   if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
    00289
    00290   TILE_AREA_LOOP(tile, ta) {
    00291     CommandCost ret;
    00292
    00293     Slope slope = GetTileSlope(tile, NULL);
    00294     if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
    00295       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
    00296     }
    00297
    00298     /* can't make water of water! */
    00299     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
    00300
    00301     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00302     if (ret.Failed()) return ret;
    00303     cost.AddCost(ret);
    00304
    00305     if (flags & DC_EXEC) {
    00306       if (TileHeight(tile) == 0 && p2 == 1) {
    00307         MakeSea(tile);
    00308       } else if (p2 == 2) {
    00309         MakeRiver(tile, Random());
    00310       } else {
    00311         MakeCanal(tile, _current_company, Random());
    00312       }
    00313       MarkTileDirtyByTile(tile);
    00314       MarkCanalsAndRiversAroundDirty(tile);
    00315     }
    00316
    00317     cost.AddCost(_price[PR_CLEAR_WATER]);
    00318   }
    00319
    00320   if (cost.GetCost() == 0) {
    00321     return_cmd_error(STR_ERROR_ALREADY_BUILT);
    00322   } else {
    00323     return cost;
    00324   }
    00325 }
    00326
    00327 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
    00328 {
    00329   switch (GetWaterTileType(tile)) {
    00330     case WATER_TILE_CLEAR:
    00331       if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
    00332
    00333       /* Make sure freeform edges are allowed or it's not an edge tile. */
    00334       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
    00335           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
    00336         return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
    00337       }
    00338
    00339       /* Make sure no vehicle is on the tile */
    00340       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00341
    00342       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
    00343
    00344       if (flags & DC_EXEC) {
    00345         DoClearSquare(tile);
    00346         MarkCanalsAndRiversAroundDirty(tile);
    00347       }
    00348       return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00349
    00350     case WATER_TILE_COAST: {
    00351       Slope slope = GetTileSlope(tile, NULL);
    00352
    00353       /* Make sure no vehicle is on the tile */
    00354       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00355
    00356       if (flags & DC_EXEC) {
    00357         DoClearSquare(tile);
    00358         MarkCanalsAndRiversAroundDirty(tile);
    00359       }
    00360       if (IsSlopeWithOneCornerRaised(slope)) {
    00361         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00362       } else {
    00363         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
    00364       }
    00365     }
    00366
    00367     case WATER_TILE_LOCK: {
    00368       static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
    00369         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
    00370         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
    00371         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
    00372       };
    00373
    00374       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00375       if (_current_company == OWNER_WATER) return CMD_ERROR;
    00376       /* move to the middle tile.. */
    00377       return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
    00378     }
    00379
    00380     case WATER_TILE_DEPOT:
    00381       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00382       return RemoveShipDepot(tile, flags);
    00383
    00384     default:
    00385       NOT_REACHED();
    00386   }
    00387 }
    00388
    00397 static bool IsWateredTile(TileIndex tile, Direction from)
    00398 {
    00399   switch (GetTileType(tile)) {
    00400     case MP_WATER:
    00401       switch (GetWaterTileType(tile)) {
    00402         default: NOT_REACHED();
    00403         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
    00404         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
    00405
    00406         case WATER_TILE_COAST:
    00407           switch (GetTileSlope(tile, NULL)) {
    00408             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00409             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00410             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00411             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00412             default: return false;
    00413           }
    00414       }
    00415
    00416     case MP_RAILWAY:
    00417       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00418         assert(IsPlainRail(tile));
    00419         switch (GetTileSlope(tile, NULL)) {
    00420           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00421           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00422           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00423           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00424           default: return false;
    00425         }
    00426       }
    00427       return false;
    00428
    00429     case MP_STATION:
    00430       if (IsOilRig(tile)) {
    00431         /* Do not draw waterborders inside of industries.
    00432          * Note: There is no easy way to detect the industry of an oilrig tile. */
    00433         TileIndex src_tile = tile + TileOffsByDir(from);
    00434         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00435             (IsTileType(src_tile, MP_INDUSTRY))) return true;
    00436
    00437         return GetWaterClass(tile) != WATER_CLASS_INVALID;
    00438       }
    00439       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
    00440
    00441     case MP_INDUSTRY: {
    00442       /* Do not draw waterborders inside of industries.
    00443        * Note: There is no easy way to detect the industry of an oilrig tile. */
    00444       TileIndex src_tile = tile + TileOffsByDir(from);
    00445       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00446           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
    00447
    00448       return IsIndustryTileOnWater(tile);
    00449     }
    00450
    00451     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
    00452
    00453     default:          return false;
    00454   }
    00455 }
    00456
    00457 static void DrawWaterEdges(SpriteID base, TileIndex tile)
    00458 {
    00459   uint wa;
    00460
    00461   /* determine the edges around with water. */
    00462   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
    00463   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
    00464   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
    00465   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
    00466
    00467   if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
    00468   if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
    00469   if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
    00470   if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
    00471
    00472   /* right corner */
    00473   switch (wa & 0x03) {
    00474     case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
    00475     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
    00476   }
    00477
    00478   /* bottom corner */
    00479   switch (wa & 0x06) {
    00480     case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
    00481     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
    00482   }
    00483
    00484   /* left corner */
    00485   switch (wa & 0x0C) {
    00486     case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
    00487     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
    00488   }
    00489
    00490   /* upper corner */
    00491   switch (wa & 0x09) {
    00492     case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
    00493     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
    00494   }
    00495 }
    00496
    00498 static void DrawSeaWater(TileIndex tile)
    00499 {
    00500   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00501 }
    00502
    00504 static void DrawCanalWater(TileIndex tile)
    00505 {
    00506   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00507
    00508   /* Test for custom graphics, else use the default */
    00509   SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
    00510   if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
    00511
    00512   DrawWaterEdges(dikes_base, tile);
    00513 }
    00514
    00515 struct LocksDrawTileStruct {
    00516   int8 delta_x, delta_y, delta_z;
    00517   byte width, height, depth;
    00518   SpriteID image;
    00519 };
    00520
    00521 #include "table/water_land.h"
    00522
    00523 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
    00524   PaletteID palette, uint base, bool draw_ground)
    00525 {
    00526   SpriteID image;
    00527   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
    00528   SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
    00529
    00530   /* If no custom graphics, use defaults */
    00531   if (water_base == 0) water_base = SPR_CANALS_BASE;
    00532   if (locks_base == 0) {
    00533     locks_base = SPR_SHIPLIFT_BASE;
    00534   } else {
    00535     /* If using custom graphics, ignore the variation on height */
    00536     base = 0;
    00537   }
    00538
    00539   image = wdts++->image;
    00540   if (image < 4) image += water_base;
    00541   if (draw_ground) DrawGroundSprite(image, PAL_NONE);
    00542
    00543   /* End now if buildings are invisible */
    00544   if (IsInvisibilitySet(TO_BUILDINGS)) return;
    00545
    00546   for (; wdts->delta_x != 0x80; wdts++) {
    00547     AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
    00548       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
    00549       wdts->size_x, wdts->size_y,
    00550       wdts->size_z, ti->z + wdts->delta_z,
    00551       IsTransparencySet(TO_BUILDINGS));
    00552   }
    00553 }
    00554
    00555 static void DrawRiverWater(const TileInfo *ti)
    00556 {
    00557   SpriteID image = SPR_FLAT_WATER_TILE;
    00558   SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
    00559
    00560   if (ti->tileh != SLOPE_FLAT) {
    00561     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
    00562     if (image == 0) {
    00563       switch (ti->tileh) {
    00564         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
    00565         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
    00566         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
    00567         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
    00568         default:       image = SPR_FLAT_WATER_TILE;    break;
    00569       }
    00570     } else {
    00571       switch (ti->tileh) {
    00572         default: NOT_REACHED();
    00573         case SLOPE_SE:             edges_base += 12; break;
    00574         case SLOPE_NE: image += 1; edges_base += 24; break;
    00575         case SLOPE_SW: image += 2; edges_base += 36; break;
    00576         case SLOPE_NW: image += 3; edges_base += 48; break;
    00577       }
    00578     }
    00579   }
    00580
    00581   DrawGroundSprite(image, PAL_NONE);
    00582
    00583   /* Draw river edges if available. */
    00584   if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
    00585 }
    00586
    00587 void DrawShoreTile(Slope tileh)
    00588 {
    00589   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
    00590    * This allows to calculate the proper sprite to display for this Slope */
    00591   static const byte tileh_to_shoresprite[32] = {
    00592     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
    00593     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
    00594   };
    00595
    00596   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
    00597   assert(tileh != SLOPE_FLAT);     // Shore is never flat
    00598
    00599   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
    00600
    00601   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
    00602 }
    00603
    00604 void DrawWaterClassGround(const TileInfo *ti)
    00605 {
    00606   switch (GetWaterClass(ti->tile)) {
    00607     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
    00608     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
    00609     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
    00610     default: NOT_REACHED();
    00611   }
    00612 }
    00613
    00614 static void DrawTile_Water(TileInfo *ti)
    00615 {
    00616   switch (GetWaterTileType(ti->tile)) {
    00617     case WATER_TILE_CLEAR:
    00618       DrawWaterClassGround(ti);
    00619       DrawBridgeMiddle(ti);
    00620       break;
    00621
    00622     case WATER_TILE_COAST: {
    00623       DrawShoreTile(ti->tileh);
    00624       DrawBridgeMiddle(ti);
    00625     } break;
    00626
    00627     case WATER_TILE_LOCK: {
    00628       const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
    00629       DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
    00630     } break;
    00631
    00632     case WATER_TILE_DEPOT:
    00633       DrawWaterClassGround(ti);
    00634       DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
    00635       break;
    00636   }
    00637 }
    00638
    00639 void DrawShipDepotSprite(int x, int y, int image)
    00640 {
    00641   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
    00642
    00643   DrawSprite(wdts++->image, PAL_NONE, x, y);
    00644
    00645   for (; wdts->delta_x != 0x80; wdts++) {
    00646     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
    00647     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
    00648   }
    00649 }
    00650
    00651
    00652 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
    00653 {
    00654   uint z;
    00655   Slope tileh = GetTileSlope(tile, &z);
    00656
    00657   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00658 }
    00659
    00660 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
    00661 {
    00662   return FOUNDATION_NONE;
    00663 }
    00664
    00665 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
    00666 {
    00667   switch (GetWaterTileType(tile)) {
    00668     case WATER_TILE_CLEAR:
    00669       switch (GetWaterClass(tile)) {
    00670         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
    00671         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
    00672         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
    00673         default: NOT_REACHED(); break;
    00674       }
    00675       break;
    00676     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
    00677     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
    00678     case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;         break;
    00679     default: NOT_REACHED(); break;
    00680   }
    00681
    00682   td->owner[0] = GetTileOwner(tile);
    00683 }
    00684
    00685 static void FloodVehicle(Vehicle *v);
    00686
    00693 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
    00694 {
    00695   byte z = *(byte*)data;
    00696
    00697   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00698   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
    00699
    00700   FloodVehicle(v);
    00701   return NULL;
    00702 }
    00703
    00709 static void FloodVehicles(TileIndex tile)
    00710 {
    00711   byte z = 0;
    00712
    00713   if (IsAirportTile(tile)) {
    00714     const Station *st = Station::GetByTile(tile);
    00715     const AirportSpec *as = st->GetAirportSpec();
    00716     z = 1 + st->Airport()->delta_z;
    00717     for (uint x = 0; x < as->size_x; x++) {
    00718       for (uint y = 0; y < as->size_y; y++) {
    00719         tile = TILE_ADDXY(st->airport_tile, x, y);
    00720         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00721       }
    00722     }
    00723
    00724     /* No vehicle could be flooded on this airport anymore */
    00725     return;
    00726   }
    00727
    00728   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
    00729   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
    00730     const Station *st = Station::GetByTile(tile);
    00731
    00732     TILE_AREA_LOOP(t, st->train_station) {
    00733       if (st->TileBelongsToRailStation(t)) {
    00734         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00735       }
    00736     }
    00737
    00738     return;
    00739   }
    00740
    00741   if (!IsBridgeTile(tile)) {
    00742     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00743     return;
    00744   }
    00745
    00746   TileIndex end = GetOtherBridgeEnd(tile);
    00747   z = GetBridgeHeight(tile);
    00748
    00749   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00750   FindVehicleOnPos(end, &z, &FloodVehicleProc);
    00751 }
    00752
    00753 static void FloodVehicle(Vehicle *v)
    00754 {
    00755   if ((v->vehstatus & VS_CRASHED) != 0) return;
    00756   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_AIRCRAFT) return;
    00757
    00758   if (v->type == VEH_AIRCRAFT) {
    00759     /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
    00760      * because that's always the shadow. Except for the heliport, because
    00761      * that station has a big z_offset for the aircraft. */
    00762     if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) return;
    00763     const Station *st = Station::GetByTile(v->tile);
    00764     const AirportFTAClass *airport = st->Airport();
    00765
    00766     if (v->z_pos != airport->delta_z + 1) return;
    00767   } else {
    00768     v = v->First();
    00769   }
    00770
    00771   uint pass = v->Crash(true);
    00772
    00773   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
    00774   SetDParam(0, pass);
    00775   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
    00776     NS_ACCIDENT,
    00777     v->index);
    00778   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    00779   SndPlayVehicleFx(SND_12_EXPLOSION, v);
    00780 }
    00781
    00787 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
    00788 {
    00789   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
    00790    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
    00791    * FLOOD_PASSIVE: (not used)
    00792    * FLOOD_NONE:    canals, rivers, everything else
    00793    */
    00794   switch (GetTileType(tile)) {
    00795     case MP_WATER:
    00796       if (IsCoast(tile)) {
    00797         Slope tileh = GetTileSlope(tile, NULL);
    00798         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00799       } else {
    00800         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
    00801       }
    00802
    00803     case MP_RAILWAY:
    00804       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00805         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00806       }
    00807       return FLOOD_NONE;
    00808
    00809     case MP_TREES:
    00810       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
    00811
    00812     case MP_STATION:
    00813       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
    00814         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
    00815       }
    00816       return FLOOD_NONE;
    00817
    00818     case MP_INDUSTRY:
    00819       return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
    00820
    00821     default:
    00822       return FLOOD_NONE;
    00823   }
    00824 }
    00825
    00829 void DoFloodTile(TileIndex target)
    00830 {
    00831   assert(!IsTileType(target, MP_WATER));
    00832
    00833   bool flooded = false; // Will be set to true if something is changed.
    00834
    00835   _current_company = OWNER_WATER;
    00836
    00837   Slope tileh = GetTileSlope(target, NULL);
    00838   if (tileh != SLOPE_FLAT) {
    00839     /* make coast.. */
    00840     switch (GetTileType(target)) {
    00841       case MP_RAILWAY: {
    00842         if (!IsPlainRail(target)) break;
    00843         FloodVehicles(target);
    00844         flooded = FloodHalftile(target);
    00845         break;
    00846       }
    00847
    00848       case MP_TREES:
    00849         if (!IsSlopeWithOneCornerRaised(tileh)) {
    00850           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
    00851           MarkTileDirtyByTile(target);
    00852           flooded = true;
    00853           break;
    00854         }
    00855       /* FALL THROUGH */
    00856       case MP_CLEAR:
    00857         if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00858           MakeShore(target);
    00859           MarkTileDirtyByTile(target);
    00860           flooded = true;
    00861         }
    00862         break;
    00863
    00864       default:
    00865         break;
    00866     }
    00867   } else {
    00868     /* Flood vehicles */
    00869     FloodVehicles(target);
    00870
    00871     /* flood flat tile */
    00872     if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00873       MakeSea(target);
    00874       MarkTileDirtyByTile(target);
    00875       flooded = true;
    00876     }
    00877   }
    00878
    00879   if (flooded) {
    00880     /* Mark surrounding canal tiles dirty too to avoid glitches */
    00881     MarkCanalsAndRiversAroundDirty(target);
    00882
    00883     /* update signals if needed */
    00884     UpdateSignalsInBuffer();
    00885   }
    00886
    00887   _current_company = OWNER_NONE;
    00888 }
    00889
    00893 static void DoDryUp(TileIndex tile)
    00894 {
    00895   _current_company = OWNER_WATER;
    00896
    00897   switch (GetTileType(tile)) {
    00898     case MP_RAILWAY:
    00899       assert(IsPlainRail(tile));
    00900       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
    00901
    00902       RailGroundType new_ground;
    00903       switch (GetTrackBits(tile)) {
    00904         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
    00905         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
    00906         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
    00907         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
    00908         default: NOT_REACHED();
    00909       }
    00910       SetRailGroundType(tile, new_ground);
    00911       MarkTileDirtyByTile(tile);
    00912       break;
    00913
    00914     case MP_TREES:
    00915       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
    00916       MarkTileDirtyByTile(tile);
    00917       break;
    00918
    00919     case MP_WATER:
    00920       assert(IsCoast(tile));
    00921
    00922       if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00923         MakeClear(tile, CLEAR_GRASS, 3);
    00924         MarkTileDirtyByTile(tile);
    00925       }
    00926       break;
    00927
    00928     default: NOT_REACHED();
    00929   }
    00930
    00931   _current_company = OWNER_NONE;
    00932 }
    00933
    00940 void TileLoop_Water(TileIndex tile)
    00941 {
    00942   switch (GetFloodingBehaviour(tile)) {
    00943     case FLOOD_ACTIVE:
    00944       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    00945         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
    00946         if (dest == INVALID_TILE) continue;
    00947         /* do not try to flood water tiles - increases performance a lot */
    00948         if (IsTileType(dest, MP_WATER)) continue;
    00949
    00950         uint z_dest;
    00951         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    00952         if (z_dest > 0) continue;
    00953
    00954         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
    00955
    00956         DoFloodTile(dest);
    00957       }
    00958       break;
    00959
    00960     case FLOOD_DRYUP: {
    00961       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    00962       uint check_dirs = _flood_from_dirs[slope_here];
    00963       uint dir;
    00964       FOR_EACH_SET_BIT(dir, check_dirs) {
    00965         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
    00966         if (dest == INVALID_TILE) continue;
    00967
    00968         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
    00969         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
    00970       }
    00971       DoDryUp(tile);
    00972       break;
    00973     }
    00974
    00975     default: return;
    00976   }
    00977 }
    00978
    00979 void ConvertGroundTilesIntoWaterTiles()
    00980 {
    00981   TileIndex tile;
    00982   uint z;
    00983   Slope slope;
    00984
    00985   for (tile = 0; tile < MapSize(); ++tile) {
    00986     slope = GetTileSlope(tile, &z);
    00987     if (IsTileType(tile, MP_CLEAR) && z == 0) {
    00988       /* Make both water for tiles at level 0
    00989        * and make shore, as that looks much better
    00990        * during the generation. */
    00991       switch (slope) {
    00992         case SLOPE_FLAT:
    00993           MakeSea(tile);
    00994           break;
    00995
    00996         case SLOPE_N:
    00997         case SLOPE_E:
    00998         case SLOPE_S:
    00999         case SLOPE_W:
    01000           MakeShore(tile);
    01001           break;
    01002
    01003         default:
    01004           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
    01005           uint dir;
    01006           FOR_EACH_SET_BIT(dir, check_dirs) {
    01007             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
    01008             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
    01009             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
    01010               MakeShore(tile);
    01011               break;
    01012             }
    01013           }
    01014           break;
    01015       }
    01016     }
    01017   }
    01018 }
    01019
    01020 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    01021 {
    01022   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
    01023
    01024   TrackBits ts;
    01025
    01026   if (mode != TRANSPORT_WATER) return 0;
    01027
    01028   switch (GetWaterTileType(tile)) {
    01029     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
    01030     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
    01031     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
    01032     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
    01033     default: return 0;
    01034   }
    01035   if (TileX(tile) == 0) {
    01036     /* NE border: remove tracks that connects NE tile edge */
    01037     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
    01038   }
    01039   if (TileY(tile) == 0) {
    01040     /* NW border: remove tracks that connects NW tile edge */
    01041     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
    01042   }
    01043   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
    01044 }
    01045
    01046 static bool ClickTile_Water(TileIndex tile)
    01047 {
    01048   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
    01049     TileIndex tile2 = GetOtherShipDepotTile(tile);
    01050
    01051     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
    01052     return true;
    01053   }
    01054   return false;
    01055 }
    01056
    01057 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
    01058 {
    01059   if (!IsTileOwner(tile, old_owner)) return;
    01060
    01061   if (new_owner != INVALID_OWNER) {
    01062     SetTileOwner(tile, new_owner);
    01063     return;
    01064   }
    01065
    01066   /* Remove depot */
    01067   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
    01068
    01069   /* Set owner of canals and locks ... and also canal under dock there was before.
    01070    * Check if the new owner after removing depot isn't OWNER_WATER. */
    01071   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
    01072 }
    01073
    01074 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
    01075 {
    01076   return VETSB_CONTINUE;
    01077 }
    01078
    01079 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
    01080 {
    01081   /* Canals can't be terraformed */
    01082   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
    01083
    01084   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    01085 }
    01086
    01087
    01088 extern const TileTypeProcs _tile_type_water_procs = {
    01089   DrawTile_Water,           // draw_tile_proc
    01090   GetSlopeZ_Water,          // get_slope_z_proc
    01091   ClearTile_Water,          // clear_tile_proc
    01092   NULL,                     // add_accepted_cargo_proc
    01093   GetTileDesc_Water,        // get_tile_desc_proc
    01094   GetTileTrackStatus_Water, // get_tile_track_status_proc
    01095   ClickTile_Water,          // click_tile_proc
    01096   NULL,                     // animate_tile_proc
    01097   TileLoop_Water,           // tile_loop_clear
    01098   ChangeTileOwner_Water,    // change_tile_owner_clear
    01099   NULL,                     // add_produced_cargo_proc
    01100   VehicleEnter_Water,       // vehicle_enter_tile_proc
    01101   GetFoundation_Water,      // get_foundation_proc
    01102   TerraformTile_Water,      // terraform_tile_proc
    01103 };