# water_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: water_cmd.cpp 18720 2010-01-04 18:37:47Z 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
    00300   if (p1 >= MapSize()) return CMD_ERROR;
    00301
    00302   /* Outside of the editor you can only build canals, not oceans */
    00303   if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
    00304
    00305   TileArea ta(tile, p1);
    00306
    00307   /* Outside the editor you can only drag canals, and not areas */
    00308   if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
    00309
    00310   TILE_AREA_LOOP(tile, ta) {
    00311     CommandCost ret;
    00312
    00313     Slope slope = GetTileSlope(tile, NULL);
    00314     if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
    00315       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
    00316     }
    00317
    00318     /* can't make water of water! */
    00319     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
    00320
    00321     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00322     if (CmdFailed(ret)) return ret;
    00323     cost.AddCost(ret);
    00324
    00325     if (flags & DC_EXEC) {
    00326       if (TileHeight(tile) == 0 && p2 == 1) {
    00327         MakeSea(tile);
    00328       } else if (p2 == 2) {
    00329         MakeRiver(tile, Random());
    00330       } else {
    00331         MakeCanal(tile, _current_company, Random());
    00332       }
    00333       MarkTileDirtyByTile(tile);
    00334       MarkCanalsAndRiversAroundDirty(tile);
    00335     }
    00336
    00337     cost.AddCost(_price[PR_CLEAR_WATER]);
    00338   }
    00339
    00340   if (cost.GetCost() == 0) {
    00341     return_cmd_error(STR_ERROR_ALREADY_BUILT);
    00342   } else {
    00343     return cost;
    00344   }
    00345 }
    00346
    00347 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
    00348 {
    00349   switch (GetWaterTileType(tile)) {
    00350     case WATER_TILE_CLEAR:
    00351       if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
    00352
    00353       /* Make sure freeform edges are allowed or it's not an edge tile. */
    00354       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
    00355           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
    00356         return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
    00357       }
    00358
    00359       /* Make sure no vehicle is on the tile */
    00360       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00361
    00362       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
    00363
    00364       if (flags & DC_EXEC) {
    00365         DoClearSquare(tile);
    00366         MarkCanalsAndRiversAroundDirty(tile);
    00367       }
    00368       return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00369
    00370     case WATER_TILE_COAST: {
    00371       Slope slope = GetTileSlope(tile, NULL);
    00372
    00373       /* Make sure no vehicle is on the tile */
    00374       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00375
    00376       if (flags & DC_EXEC) {
    00377         DoClearSquare(tile);
    00378         MarkCanalsAndRiversAroundDirty(tile);
    00379       }
    00380       if (IsSlopeWithOneCornerRaised(slope)) {
    00381         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00382       } else {
    00383         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
    00384       }
    00385     }
    00386
    00387     case WATER_TILE_LOCK: {
    00388       static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
    00389         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
    00390         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
    00391         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
    00392       };
    00393
    00394       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00395       if (_current_company == OWNER_WATER) return CMD_ERROR;
    00396       /* move to the middle tile.. */
    00397       return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
    00398     }
    00399
    00400     case WATER_TILE_DEPOT:
    00401       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00402       return RemoveShipDepot(tile, flags);
    00403
    00404     default:
    00405       NOT_REACHED();
    00406   }
    00407 }
    00408
    00417 static bool IsWateredTile(TileIndex tile, Direction from)
    00418 {
    00419   switch (GetTileType(tile)) {
    00420     case MP_WATER:
    00421       switch (GetWaterTileType(tile)) {
    00422         default: NOT_REACHED();
    00423         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
    00424         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
    00425
    00426         case WATER_TILE_COAST:
    00427           switch (GetTileSlope(tile, NULL)) {
    00428             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00429             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00430             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00431             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00432             default: return false;
    00433           }
    00434       }
    00435
    00436     case MP_RAILWAY:
    00437       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00438         assert(IsPlainRail(tile));
    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       return false;
    00448
    00449     case MP_STATION:
    00450       if (IsOilRig(tile)) {
    00451         /* Do not draw waterborders inside of industries.
    00452          * Note: There is no easy way to detect the industry of an oilrig tile. */
    00453         TileIndex src_tile = tile + TileOffsByDir(from);
    00454         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00455             (IsTileType(src_tile, MP_INDUSTRY))) return true;
    00456
    00457         return GetWaterClass(tile) != WATER_CLASS_INVALID;
    00458       }
    00459       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
    00460
    00461     case MP_INDUSTRY: {
    00462       /* Do not draw waterborders inside of industries.
    00463        * Note: There is no easy way to detect the industry of an oilrig tile. */
    00464       TileIndex src_tile = tile + TileOffsByDir(from);
    00465       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00466           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
    00467
    00468       return IsIndustryTileOnWater(tile);
    00469     }
    00470
    00471     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
    00472
    00473     default:          return false;
    00474   }
    00475 }
    00476
    00477 static void DrawWaterEdges(SpriteID base, TileIndex tile)
    00478 {
    00479   uint wa;
    00480
    00481   /* determine the edges around with water. */
    00482   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
    00483   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
    00484   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
    00485   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
    00486
    00487   if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
    00488   if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
    00489   if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
    00490   if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
    00491
    00492   /* right corner */
    00493   switch (wa & 0x03) {
    00494     case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
    00495     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
    00496   }
    00497
    00498   /* bottom corner */
    00499   switch (wa & 0x06) {
    00500     case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
    00501     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
    00502   }
    00503
    00504   /* left corner */
    00505   switch (wa & 0x0C) {
    00506     case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
    00507     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
    00508   }
    00509
    00510   /* upper corner */
    00511   switch (wa & 0x09) {
    00512     case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
    00513     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
    00514   }
    00515 }
    00516
    00518 static void DrawSeaWater(TileIndex tile)
    00519 {
    00520   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00521 }
    00522
    00524 static void DrawCanalWater(TileIndex tile)
    00525 {
    00526   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00527
    00528   /* Test for custom graphics, else use the default */
    00529   SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
    00530   if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
    00531
    00532   DrawWaterEdges(dikes_base, tile);
    00533 }
    00534
    00535 struct LocksDrawTileStruct {
    00536   int8 delta_x, delta_y, delta_z;
    00537   byte width, height, depth;
    00538   SpriteID image;
    00539 };
    00540
    00541 #include "table/water_land.h"
    00542
    00543 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
    00544   SpriteID palette, uint base, bool draw_ground)
    00545 {
    00546   SpriteID image;
    00547   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
    00548   SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
    00549
    00550   /* If no custom graphics, use defaults */
    00551   if (water_base == 0) water_base = SPR_CANALS_BASE;
    00552   if (locks_base == 0) {
    00553     locks_base = SPR_SHIPLIFT_BASE;
    00554   } else {
    00555     /* If using custom graphics, ignore the variation on height */
    00556     base = 0;
    00557   }
    00558
    00559   image = wdts++->image;
    00560   if (image < 4) image += water_base;
    00561   if (draw_ground) DrawGroundSprite(image, PAL_NONE);
    00562
    00563   /* End now if buildings are invisible */
    00564   if (IsInvisibilitySet(TO_BUILDINGS)) return;
    00565
    00566   for (; wdts->delta_x != 0x80; wdts++) {
    00567     AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
    00568       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
    00569       wdts->size_x, wdts->size_y,
    00570       wdts->size_z, ti->z + wdts->delta_z,
    00571       IsTransparencySet(TO_BUILDINGS));
    00572   }
    00573 }
    00574
    00575 static void DrawRiverWater(const TileInfo *ti)
    00576 {
    00577   SpriteID image = SPR_FLAT_WATER_TILE;
    00578   SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
    00579
    00580   if (ti->tileh != SLOPE_FLAT) {
    00581     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
    00582     if (image == 0) {
    00583       switch (ti->tileh) {
    00584         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
    00585         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
    00586         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
    00587         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
    00588         default:       image = SPR_FLAT_WATER_TILE;    break;
    00589       }
    00590     } else {
    00591       switch (ti->tileh) {
    00592         default: NOT_REACHED();
    00593         case SLOPE_SE:             edges_base += 12; break;
    00594         case SLOPE_NE: image += 1; edges_base += 24; break;
    00595         case SLOPE_SW: image += 2; edges_base += 36; break;
    00596         case SLOPE_NW: image += 3; edges_base += 48; break;
    00597       }
    00598     }
    00599   }
    00600
    00601   DrawGroundSprite(image, PAL_NONE);
    00602
    00603   /* Draw river edges if available. */
    00604   if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
    00605 }
    00606
    00607 void DrawShoreTile(Slope tileh)
    00608 {
    00609   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
    00610    * This allows to calculate the proper sprite to display for this Slope */
    00611   static const byte tileh_to_shoresprite[32] = {
    00612     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
    00613     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
    00614   };
    00615
    00616   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
    00617   assert(tileh != SLOPE_FLAT);     // Shore is never flat
    00618
    00619   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
    00620
    00621   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
    00622 }
    00623
    00624 void DrawWaterClassGround(const TileInfo *ti)
    00625 {
    00626   switch (GetWaterClass(ti->tile)) {
    00627     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
    00628     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
    00629     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
    00630     default: NOT_REACHED();
    00631   }
    00632 }
    00633
    00634 static void DrawTile_Water(TileInfo *ti)
    00635 {
    00636   switch (GetWaterTileType(ti->tile)) {
    00637     case WATER_TILE_CLEAR:
    00638       DrawWaterClassGround(ti);
    00639       DrawBridgeMiddle(ti);
    00640       break;
    00641
    00642     case WATER_TILE_COAST: {
    00643       DrawShoreTile(ti->tileh);
    00644       DrawBridgeMiddle(ti);
    00645     } break;
    00646
    00647     case WATER_TILE_LOCK: {
    00648       const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
    00649       DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
    00650     } break;
    00651
    00652     case WATER_TILE_DEPOT:
    00653       DrawWaterClassGround(ti);
    00654       DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
    00655       break;
    00656   }
    00657 }
    00658
    00659 void DrawShipDepotSprite(int x, int y, int image)
    00660 {
    00661   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
    00662
    00663   DrawSprite(wdts++->image, PAL_NONE, x, y);
    00664
    00665   for (; wdts->delta_x != 0x80; wdts++) {
    00666     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
    00667     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
    00668   }
    00669 }
    00670
    00671
    00672 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
    00673 {
    00674   uint z;
    00675   Slope tileh = GetTileSlope(tile, &z);
    00676
    00677   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00678 }
    00679
    00680 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
    00681 {
    00682   return FOUNDATION_NONE;
    00683 }
    00684
    00685 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
    00686 {
    00687   switch (GetWaterTileType(tile)) {
    00688     case WATER_TILE_CLEAR:
    00689       switch (GetWaterClass(tile)) {
    00690         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
    00691         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
    00692         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
    00693         default: NOT_REACHED(); break;
    00694       }
    00695       break;
    00696     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
    00697     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
    00698     case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;         break;
    00699     default: NOT_REACHED(); break;
    00700   }
    00701
    00702   td->owner[0] = GetTileOwner(tile);
    00703 }
    00704
    00705 static void FloodVehicle(Vehicle *v);
    00706
    00713 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
    00714 {
    00715   byte z = *(byte*)data;
    00716
    00717   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00718   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
    00719
    00720   FloodVehicle(v);
    00721   return NULL;
    00722 }
    00723
    00729 static void FloodVehicles(TileIndex tile)
    00730 {
    00731   byte z = 0;
    00732
    00733   if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
    00734     const Station *st = Station::GetByTile(tile);
    00735     const AirportFTAClass *airport = st->Airport();
    00736     z = 1 + airport->delta_z;
    00737     for (uint x = 0; x < airport->size_x; x++) {
    00738       for (uint y = 0; y < airport->size_y; y++) {
    00739         tile = TILE_ADDXY(st->airport_tile, x, y);
    00740         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00741       }
    00742     }
    00743
    00744     /* No vehicle could be flooded on this airport anymore */
    00745     return;
    00746   }
    00747
    00748   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
    00749   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
    00750     const Station *st = Station::GetByTile(tile);
    00751
    00752     TILE_AREA_LOOP(t, st->train_station) {
    00753       if (st->TileBelongsToRailStation(t)) {
    00754         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00755       }
    00756     }
    00757
    00758     return;
    00759   }
    00760
    00761   if (!IsBridgeTile(tile)) {
    00762     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00763     return;
    00764   }
    00765
    00766   TileIndex end = GetOtherBridgeEnd(tile);
    00767   z = GetBridgeHeight(tile);
    00768
    00769   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00770   FindVehicleOnPos(end, &z, &FloodVehicleProc);
    00771 }
    00772
    00773 static void FloodVehicle(Vehicle *v)
    00774 {
    00775   if ((v->vehstatus & VS_CRASHED) != 0) return;
    00776   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_AIRCRAFT) return;
    00777
    00778   if (v->type == VEH_AIRCRAFT) {
    00779     /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
    00780      * because that's always the shadow. Except for the heliport, because
    00781      * that station has a big z_offset for the aircraft. */
    00782     if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
    00783     const Station *st = Station::GetByTile(v->tile);
    00784     const AirportFTAClass *airport = st->Airport();
    00785
    00786     if (v->z_pos != airport->delta_z + 1) return;
    00787   } else {
    00788     v = v->First();
    00789   }
    00790
    00791   uint pass = v->Crash(true);
    00792
    00793   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
    00794   SetDParam(0, pass);
    00795   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
    00796     NS_ACCIDENT,
    00797     v->index);
    00798   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    00799   SndPlayVehicleFx(SND_12_EXPLOSION, v);
    00800 }
    00801
    00807 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
    00808 {
    00809   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
    00810    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
    00811    * FLOOD_PASSIVE: (not used)
    00812    * FLOOD_NONE:    canals, rivers, everything else
    00813    */
    00814   switch (GetTileType(tile)) {
    00815     case MP_WATER:
    00816       if (IsCoast(tile)) {
    00817         Slope tileh = GetTileSlope(tile, NULL);
    00818         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00819       } else {
    00820         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
    00821       }
    00822
    00823     case MP_RAILWAY:
    00824       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00825         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00826       }
    00827       return FLOOD_NONE;
    00828
    00829     case MP_TREES:
    00830       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
    00831
    00832     case MP_STATION:
    00833       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
    00834         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
    00835       }
    00836       return FLOOD_NONE;
    00837
    00838     case MP_INDUSTRY:
    00839       return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
    00840
    00841     default:
    00842       return FLOOD_NONE;
    00843   }
    00844 }
    00845
    00849 void DoFloodTile(TileIndex target)
    00850 {
    00851   assert(!IsTileType(target, MP_WATER));
    00852
    00853   bool flooded = false; // Will be set to true if something is changed.
    00854
    00855   _current_company = OWNER_WATER;
    00856
    00857   Slope tileh = GetTileSlope(target, NULL);
    00858   if (tileh != SLOPE_FLAT) {
    00859     /* make coast.. */
    00860     switch (GetTileType(target)) {
    00861       case MP_RAILWAY: {
    00862         if (!IsPlainRail(target)) break;
    00863         FloodVehicles(target);
    00864         flooded = FloodHalftile(target);
    00865         break;
    00866       }
    00867
    00868       case MP_TREES:
    00869         if (!IsSlopeWithOneCornerRaised(tileh)) {
    00870           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
    00871           MarkTileDirtyByTile(target);
    00872           flooded = true;
    00873           break;
    00874         }
    00875       /* FALL THROUGH */
    00876       case MP_CLEAR:
    00877         if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00878           MakeShore(target);
    00879           MarkTileDirtyByTile(target);
    00880           flooded = true;
    00881         }
    00882         break;
    00883
    00884       default:
    00885         break;
    00886     }
    00887   } else {
    00888     /* Flood vehicles */
    00889     FloodVehicles(target);
    00890
    00891     /* flood flat tile */
    00892     if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00893       MakeSea(target);
    00894       MarkTileDirtyByTile(target);
    00895       flooded = true;
    00896     }
    00897   }
    00898
    00899   if (flooded) {
    00900     /* Mark surrounding canal tiles dirty too to avoid glitches */
    00901     MarkCanalsAndRiversAroundDirty(target);
    00902
    00903     /* update signals if needed */
    00904     UpdateSignalsInBuffer();
    00905   }
    00906
    00907   _current_company = OWNER_NONE;
    00908 }
    00909
    00913 static void DoDryUp(TileIndex tile)
    00914 {
    00915   _current_company = OWNER_WATER;
    00916
    00917   switch (GetTileType(tile)) {
    00918     case MP_RAILWAY:
    00919       assert(IsPlainRail(tile));
    00920       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
    00921
    00922       RailGroundType new_ground;
    00923       switch (GetTrackBits(tile)) {
    00924         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
    00925         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
    00926         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
    00927         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
    00928         default: NOT_REACHED();
    00929       }
    00930       SetRailGroundType(tile, new_ground);
    00931       MarkTileDirtyByTile(tile);
    00932       break;
    00933
    00934     case MP_TREES:
    00935       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
    00936       MarkTileDirtyByTile(tile);
    00937       break;
    00938
    00939     case MP_WATER:
    00940       assert(IsCoast(tile));
    00941
    00942       if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00943         MakeClear(tile, CLEAR_GRASS, 3);
    00944         MarkTileDirtyByTile(tile);
    00945       }
    00946       break;
    00947
    00948     default: NOT_REACHED();
    00949   }
    00950
    00951   _current_company = OWNER_NONE;
    00952 }
    00953
    00960 void TileLoop_Water(TileIndex tile)
    00961 {
    00962   switch (GetFloodingBehaviour(tile)) {
    00963     case FLOOD_ACTIVE:
    00964       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    00965         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
    00966         if (dest == INVALID_TILE) continue;
    00967         /* do not try to flood water tiles - increases performance a lot */
    00968         if (IsTileType(dest, MP_WATER)) continue;
    00969
    00970         uint z_dest;
    00971         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    00972         if (z_dest > 0) continue;
    00973
    00974         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
    00975
    00976         DoFloodTile(dest);
    00977       }
    00978       break;
    00979
    00980     case FLOOD_DRYUP: {
    00981       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    00982       uint check_dirs = _flood_from_dirs[slope_here];
    00983       uint dir;
    00984       FOR_EACH_SET_BIT(dir, check_dirs) {
    00985         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
    00986         if (dest == INVALID_TILE) continue;
    00987
    00988         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
    00989         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
    00990       }
    00991       DoDryUp(tile);
    00992       break;
    00993     }
    00994
    00995     default: return;
    00996   }
    00997 }
    00998
    00999 void ConvertGroundTilesIntoWaterTiles()
    01000 {
    01001   TileIndex tile;
    01002   uint z;
    01003   Slope slope;
    01004
    01005   for (tile = 0; tile < MapSize(); ++tile) {
    01006     slope = GetTileSlope(tile, &z);
    01007     if (IsTileType(tile, MP_CLEAR) && z == 0) {
    01008       /* Make both water for tiles at level 0
    01009        * and make shore, as that looks much better
    01010        * during the generation. */
    01011       switch (slope) {
    01012         case SLOPE_FLAT:
    01013           MakeSea(tile);
    01014           break;
    01015
    01016         case SLOPE_N:
    01017         case SLOPE_E:
    01018         case SLOPE_S:
    01019         case SLOPE_W:
    01020           MakeShore(tile);
    01021           break;
    01022
    01023         default:
    01024           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
    01025           uint dir;
    01026           FOR_EACH_SET_BIT(dir, check_dirs) {
    01027             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
    01028             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
    01029             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
    01030               MakeShore(tile);
    01031               break;
    01032             }
    01033           }
    01034           break;
    01035       }
    01036     }
    01037   }
    01038 }
    01039
    01040 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    01041 {
    01042   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
    01043
    01044   TrackBits ts;
    01045
    01046   if (mode != TRANSPORT_WATER) return 0;
    01047
    01048   switch (GetWaterTileType(tile)) {
    01049     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
    01050     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
    01051     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
    01052     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
    01053     default: return 0;
    01054   }
    01055   if (TileX(tile) == 0) {
    01056     /* NE border: remove tracks that connects NE tile edge */
    01057     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
    01058   }
    01059   if (TileY(tile) == 0) {
    01060     /* NW border: remove tracks that connects NW tile edge */
    01061     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
    01062   }
    01063   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
    01064 }
    01065
    01066 static bool ClickTile_Water(TileIndex tile)
    01067 {
    01068   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
    01069     TileIndex tile2 = GetOtherShipDepotTile(tile);
    01070
    01071     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
    01072     return true;
    01073   }
    01074   return false;
    01075 }
    01076
    01077 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
    01078 {
    01079   if (!IsTileOwner(tile, old_owner)) return;
    01080
    01081   if (new_owner != INVALID_OWNER) {
    01082     SetTileOwner(tile, new_owner);
    01083     return;
    01084   }
    01085
    01086   /* Remove depot */
    01087   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
    01088
    01089   /* Set owner of canals and locks ... and also canal under dock there was before.
    01090    * Check if the new owner after removing depot isn't OWNER_WATER. */
    01091   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
    01092 }
    01093
    01094 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
    01095 {
    01096   return VETSB_CONTINUE;
    01097 }
    01098
    01099 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
    01100 {
    01101   /* Canals can't be terraformed */
    01102   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
    01103
    01104   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    01105 }
    01106
    01107
    01108 extern const TileTypeProcs _tile_type_water_procs = {
    01109   DrawTile_Water,           // draw_tile_proc
    01110   GetSlopeZ_Water,          // get_slope_z_proc
    01111   ClearTile_Water,          // clear_tile_proc
    01112   NULL,                     // add_accepted_cargo_proc
    01113   GetTileDesc_Water,        // get_tile_desc_proc
    01114   GetTileTrackStatus_Water, // get_tile_track_status_proc
    01115   ClickTile_Water,          // click_tile_proc
    01116   NULL,                     // animate_tile_proc
    01117   TileLoop_Water,           // tile_loop_clear
    01118   ChangeTileOwner_Water,    // change_tile_owner_clear
    01119   NULL,                     // add_produced_cargo_proc
    01120   VehicleEnter_Water,       // vehicle_enter_tile_proc
    01121   GetFoundation_Water,      // get_foundation_proc
    01122   TerraformTile_Water,      // terraform_tile_proc
    01123 };