# water_cmd.cpp

Go to the documentation of this file.

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