# water_cmd.cpp

Go to the documentation of this file.

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