# water_cmd.cpp

Go to the documentation of this file.

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