# water_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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 "vehicle_func.h"
    00026 #include "sound_func.h"
    00027 #include "company_func.h"
    00028 #include "clear_map.h"
    00029 #include "tree_map.h"
    00030 #include "aircraft.h"
    00031 #include "effectvehicle_func.h"
    00032 #include "tunnelbridge_map.h"
    00033 #include "station_base.h"
    00034 #include "ai/ai.hpp"
    00035 #include "core/random_func.hpp"
    00036 #include "core/backup_type.hpp"
    00037 #include "date_func.h"
    00038
    00039 #include "table/strings.h"
    00040
    00044 static const uint8 _flood_from_dirs[] = {
    00045   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
    00046   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
    00047   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
    00048   (1 << DIR_NE),                                                 // SLOPE_SW
    00049   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
    00050   0,                                                             // SLOPE_EW
    00051   (1 << DIR_NW),                                                 // SLOPE_SE
    00052   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
    00053   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
    00054   (1 << DIR_SE),                                                 // SLOPE_NW
    00055   0,                                                             // SLOPE_NS
    00056   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
    00057   (1 << DIR_SW),                                                 // SLOPE_NE
    00058   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
    00059   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
    00060 };
    00061
    00068 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
    00069 {
    00070   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
    00071 }
    00072
    00079 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
    00080 {
    00081   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    00082     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
    00083   }
    00084 }
    00085
    00086
    00096 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00097 {
    00098   Axis axis = Extract<Axis, 0, 1>(p1);
    00099
    00100   TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
    00101
    00102   if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
    00103     return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
    00104   }
    00105
    00106   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
    00107     (MayHaveBridgeAbove(tile2) && IsBridgeAbove(tile2))) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
    00108
    00109   if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
    00110     /* Prevent depots on rapids */
    00111     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
    00112   }
    00113
    00114   if (!Depot::CanAllocateItem()) return CMD_ERROR;
    00115
    00116   WaterClass wc1 = GetWaterClass(tile);
    00117   WaterClass wc2 = GetWaterClass(tile2);
    00118   CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
    00119
    00120   bool add_cost = !IsWaterTile(tile);
    00121   CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
    00122   if (ret.Failed()) return ret;
    00123   if (add_cost) {
    00124     cost.AddCost(ret);
    00125   }
    00126   add_cost = !IsWaterTile(tile2);
    00127   ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
    00128   if (ret.Failed()) return ret;
    00129   if (add_cost) {
    00130     cost.AddCost(ret);
    00131   }
    00132
    00133   if (flags & DC_EXEC) {
    00134     Depot *depot = new Depot(tile);
    00135     depot->build_date = _date;
    00136
    00137     MakeShipDepot(tile,  _current_company, depot->index, DEPOT_NORTH, axis, wc1);
    00138     MakeShipDepot(tile2, _current_company, depot->index, DEPOT_SOUTH, axis, wc2);
    00139     MarkTileDirtyByTile(tile);
    00140     MarkTileDirtyByTile(tile2);
    00141     MakeDefaultName(depot);
    00142   }
    00143
    00144   return cost;
    00145 }
    00146
    00147 void MakeWaterKeepingClass(TileIndex tile, Owner o)
    00148 {
    00149   WaterClass wc = GetWaterClass(tile);
    00150
    00151   /* Autoslope might turn an originally canal or river tile into land */
    00152   uint z;
    00153   if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
    00154
    00155   if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
    00156
    00157   /* Zero map array and terminate animation */
    00158   DoClearSquare(tile);
    00159
    00160   /* Maybe change to water */
    00161   switch (wc) {
    00162     case WATER_CLASS_SEA:   MakeSea(tile);                break;
    00163     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
    00164     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
    00165     default: break;
    00166   }
    00167
    00168   MarkTileDirtyByTile(tile);
    00169 }
    00170
    00171 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
    00172 {
    00173   if (!IsShipDepot(tile)) return CMD_ERROR;
    00174
    00175   CommandCost ret = CheckTileOwnership(tile);
    00176   if (ret.Failed()) return ret;
    00177
    00178   TileIndex tile2 = GetOtherShipDepotTile(tile);
    00179
    00180   /* do not check for ship on tile when company goes bankrupt */
    00181   if (!(flags & DC_BANKRUPT)) {
    00182     CommandCost ret = EnsureNoVehicleOnGround(tile);
    00183     if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
    00184     if (ret.Failed()) return ret;
    00185   }
    00186
    00187   if (flags & DC_EXEC) {
    00188     delete Depot::GetByTile(tile);
    00189
    00190     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
    00191     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
    00192   }
    00193
    00194   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
    00195 }
    00196
    00204 static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
    00205 {
    00206   CommandCost cost(EXPENSES_CONSTRUCTION);
    00207
    00208   /* middle tile */
    00209   CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00210   if (ret.Failed()) return ret;
    00211   cost.AddCost(ret);
    00212
    00213   int delta = TileOffsByDiagDir(dir);
    00214   /* lower tile */
    00215   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
    00216
    00217   if (!IsWaterTile(tile - delta)) {
    00218     ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00219     if (ret.Failed()) return ret;
    00220     cost.AddCost(ret);
    00221     cost.AddCost(_price[PR_BUILD_CANAL]);
    00222   }
    00223   if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
    00224     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00225   }
    00226
    00227   /* upper tile */
    00228   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
    00229
    00230   if (!IsWaterTile(tile + delta)) {
    00231     ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00232     if (ret.Failed()) return ret;
    00233     cost.AddCost(ret);
    00234     cost.AddCost(_price[PR_BUILD_CANAL]);
    00235   }
    00236   if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
    00237     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00238   }
    00239
    00240   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
    00241       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
    00242       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
    00243     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
    00244   }
    00245
    00246   if (flags & DC_EXEC) {
    00247     MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
    00248     MarkTileDirtyByTile(tile);
    00249     MarkTileDirtyByTile(tile - delta);
    00250     MarkTileDirtyByTile(tile + delta);
    00251     MarkCanalsAndRiversAroundDirty(tile - delta);
    00252     MarkCanalsAndRiversAroundDirty(tile + delta);
    00253   }
    00254   cost.AddCost(_price[PR_BUILD_LOCK]);
    00255
    00256   return cost;
    00257 }
    00258
    00265 static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags)
    00266 {
    00267   if (GetTileOwner(tile) != OWNER_NONE) {
    00268     CommandCost ret = CheckTileOwnership(tile);
    00269     if (ret.Failed()) return ret;
    00270   }
    00271
    00272   TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
    00273
    00274   /* make sure no vehicle is on the tile. */
    00275   CommandCost ret = EnsureNoVehicleOnGround(tile);
    00276   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
    00277   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
    00278   if (ret.Failed()) return ret;
    00279
    00280   if (flags & DC_EXEC) {
    00281     DoClearSquare(tile);
    00282     MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
    00283     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
    00284     MarkCanalsAndRiversAroundDirty(tile - delta);
    00285     MarkCanalsAndRiversAroundDirty(tile + delta);
    00286   }
    00287
    00288   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
    00289 }
    00290
    00300 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00301 {
    00302   DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
    00303   if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
    00304
    00305   /* Disallow building of locks on river rapids */
    00306   if (IsWaterTile(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
    00307
    00308   return DoBuildLock(tile, dir, flags);
    00309 }
    00310
    00320 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00321 {
    00322   WaterClass wc = Extract<WaterClass, 0, 2>(p2);
    00323   if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
    00324
    00325   /* Outside of the editor you can only build canals, not oceans */
    00326   if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
    00327
    00328   TileArea ta(tile, p1);
    00329
    00330   /* Outside the editor you can only drag canals, and not areas */
    00331   if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
    00332
    00333   CommandCost cost(EXPENSES_CONSTRUCTION);
    00334   TILE_AREA_LOOP(tile, ta) {
    00335     CommandCost ret;
    00336
    00337     Slope slope = GetTileSlope(tile, NULL);
    00338     if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
    00339       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
    00340     }
    00341
    00342     /* can't make water of water! */
    00343     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
    00344
    00345     ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
    00346     if (ret.Failed()) return ret;
    00347     cost.AddCost(ret);
    00348
    00349     if (flags & DC_EXEC) {
    00350       switch (wc) {
    00351         case WATER_CLASS_RIVER:
    00352           MakeRiver(tile, Random());
    00353           break;
    00354
    00355         case WATER_CLASS_SEA:
    00356           if (TileHeight(tile) == 0) {
    00357             MakeSea(tile);
    00358             break;
    00359           }
    00360           /* FALL THROUGH */
    00361
    00362         default:
    00363           MakeCanal(tile, _current_company, Random());
    00364           break;
    00365       }
    00366       MarkTileDirtyByTile(tile);
    00367       MarkCanalsAndRiversAroundDirty(tile);
    00368     }
    00369
    00370     cost.AddCost(_price[PR_BUILD_CANAL]);
    00371   }
    00372
    00373   if (cost.GetCost() == 0) {
    00374     return_cmd_error(STR_ERROR_ALREADY_BUILT);
    00375   } else {
    00376     return cost;
    00377   }
    00378 }
    00379
    00380 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
    00381 {
    00382   switch (GetWaterTileType(tile)) {
    00383     case WATER_TILE_CLEAR: {
    00384       if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
    00385
    00386       Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
    00387       /* Make sure freeform edges are allowed or it's not an edge tile. */
    00388       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
    00389           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
    00390         return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
    00391       }
    00392
    00393       /* Check to see if crossing-water tunnel present. */
    00394       if (GetTileZ(tile) == 0 && IsTunnelInWay(tile, 0)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST);
    00395
    00396       /* Make sure no vehicle is on the tile */
    00397       CommandCost ret = EnsureNoVehicleOnGround(tile);
    00398       if (ret.Failed()) return ret;
    00399
    00400       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE) {
    00401         CommandCost ret = CheckTileOwnership(tile);
    00402         if (ret.Failed()) return ret;
    00403       }
    00404
    00405       if (flags & DC_EXEC) {
    00406         DoClearSquare(tile);
    00407         MarkCanalsAndRiversAroundDirty(tile);
    00408       }
    00409
    00410       return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
    00411     }
    00412
    00413     case WATER_TILE_COAST: {
    00414       Slope slope = GetTileSlope(tile, NULL);
    00415
    00416       /* Make sure no vehicle is on the tile */
    00417       CommandCost ret = EnsureNoVehicleOnGround(tile);
    00418       if (ret.Failed()) return ret;
    00419
    00420       if (flags & DC_EXEC) {
    00421         DoClearSquare(tile);
    00422         MarkCanalsAndRiversAroundDirty(tile);
    00423       }
    00424       if (IsSlopeWithOneCornerRaised(slope)) {
    00425         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00426       } else {
    00427         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
    00428       }
    00429     }
    00430
    00431     case WATER_TILE_LOCK: {
    00432       static const TileIndexDiffC _lock_tomiddle_offs[] = {
    00433         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
    00434         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
    00435         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
    00436       };
    00437
    00438       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00439       if (_current_company == OWNER_WATER) return CMD_ERROR;
    00440       /* move to the middle tile.. */
    00441       return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetSection(tile)]), flags);
    00442     }
    00443
    00444     case WATER_TILE_DEPOT:
    00445       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00446       return RemoveShipDepot(tile, flags);
    00447
    00448     default:
    00449       NOT_REACHED();
    00450   }
    00451 }
    00452
    00461 static bool IsWateredTile(TileIndex tile, Direction from)
    00462 {
    00463   switch (GetTileType(tile)) {
    00464     case MP_WATER:
    00465       switch (GetWaterTileType(tile)) {
    00466         default: NOT_REACHED();
    00467         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
    00468         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
    00469
    00470         case WATER_TILE_COAST:
    00471           switch (GetTileSlope(tile, NULL)) {
    00472             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00473             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00474             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00475             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00476             default: return false;
    00477           }
    00478       }
    00479
    00480     case MP_RAILWAY:
    00481       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00482         assert(IsPlainRail(tile));
    00483         switch (GetTileSlope(tile, NULL)) {
    00484           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00485           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00486           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00487           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00488           default: return false;
    00489         }
    00490       }
    00491       return false;
    00492
    00493     case MP_STATION:
    00494       if (IsOilRig(tile)) {
    00495         /* Do not draw waterborders inside of industries.
    00496          * Note: There is no easy way to detect the industry of an oilrig tile. */
    00497         TileIndex src_tile = tile + TileOffsByDir(from);
    00498         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00499             (IsTileType(src_tile, MP_INDUSTRY))) return true;
    00500
    00501         return IsTileOnWater(tile);
    00502       }
    00503       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
    00504
    00505     case MP_INDUSTRY: {
    00506       /* Do not draw waterborders inside of industries.
    00507        * Note: There is no easy way to detect the industry of an oilrig tile. */
    00508       TileIndex src_tile = tile + TileOffsByDir(from);
    00509       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00510           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
    00511
    00512       return IsTileOnWater(tile);
    00513     }
    00514
    00515     case MP_OBJECT: return IsTileOnWater(tile);
    00516
    00517     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
    00518
    00519     default:          return false;
    00520   }
    00521 }
    00522
    00530 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
    00531 {
    00532   if (base != SPR_FLAT_WATER_TILE) {
    00533     /* Only call offset callback if the sprite is NewGRF-provided. */
    00534     offset = GetCanalSpriteOffset(feature, tile, offset);
    00535   }
    00536   DrawGroundSprite(base + offset, PAL_NONE);
    00537 }
    00538
    00545 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
    00546 {
    00547   CanalFeature feature;
    00548   SpriteID base = 0;
    00549   if (canal) {
    00550     feature = CF_DIKES;
    00551     base = GetCanalSprite(CF_DIKES, tile);
    00552     if (base == 0) base = SPR_CANAL_DIKES_BASE;
    00553   } else {
    00554     feature = CF_RIVER_EDGE;
    00555     base = GetCanalSprite(CF_RIVER_EDGE, tile);
    00556     if (base == 0) return; // Don't draw if no sprites provided.
    00557   }
    00558
    00559   uint wa;
    00560
    00561   /* determine the edges around with water. */
    00562   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
    00563   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
    00564   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
    00565   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
    00566
    00567   if (!(wa & 1)) DrawWaterSprite(base, offset,     feature, tile);
    00568   if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
    00569   if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
    00570   if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
    00571
    00572   /* right corner */
    00573   switch (wa & 0x03) {
    00574     case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
    00575     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
    00576   }
    00577
    00578   /* bottom corner */
    00579   switch (wa & 0x06) {
    00580     case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
    00581     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
    00582   }
    00583
    00584   /* left corner */
    00585   switch (wa & 0x0C) {
    00586     case  0: DrawWaterSprite(base, offset + 6, feature, tile); break;
    00587     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
    00588   }
    00589
    00590   /* upper corner */
    00591   switch (wa & 0x09) {
    00592     case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
    00593     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
    00594   }
    00595 }
    00596
    00598 static void DrawSeaWater(TileIndex tile)
    00599 {
    00600   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00601 }
    00602
    00604 static void DrawCanalWater(TileIndex tile)
    00605 {
    00606   SpriteID image = SPR_FLAT_WATER_TILE;
    00607   if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00608     /* First water slope sprite is flat water. */
    00609     image = GetCanalSprite(CF_WATERSLOPE, tile);
    00610     if (image == 0) image = SPR_FLAT_WATER_TILE;
    00611   }
    00612   DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
    00613
    00614   DrawWaterEdges(true, 0, tile);
    00615 }
    00616
    00617 #include "table/water_land.h"
    00618
    00628 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
    00629 {
    00630   /* Don't draw if buildings are invisible. */
    00631   if (IsInvisibilitySet(TO_BUILDINGS)) return;
    00632
    00633   for (; !dtss->IsTerminator(); dtss++) {
    00634     uint tile_offs = offset + dtss->image.sprite;
    00635     if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
    00636     AddSortableSpriteToDraw(base + tile_offs, palette,
    00637       ti->x + dtss->delta_x, ti->y + dtss->delta_y,
    00638       dtss->size_x, dtss->size_y,
    00639       dtss->size_z, ti->z + dtss->delta_z,
    00640       IsTransparencySet(TO_BUILDINGS));
    00641   }
    00642 }
    00643
    00645 static void DrawWaterLock(const TileInfo *ti)
    00646 {
    00647   int section = GetSection(ti->tile);
    00648   const DrawTileSprites &dts = _lock_display_data[section];
    00649
    00650   /* Draw ground sprite. */
    00651   SpriteID image = dts.ground.sprite;
    00652
    00653   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
    00654   if (water_base == 0) {
    00655     /* Use default sprites. */
    00656     water_base = SPR_CANALS_BASE;
    00657   } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00658     /* NewGRF supplies a flat sprite as first sprite. */
    00659     if (image == SPR_FLAT_WATER_TILE) {
    00660       image = water_base;
    00661     } else {
    00662       image++;
    00663     }
    00664   }
    00665
    00666   if (image < 5) image += water_base;
    00667   DrawGroundSprite(image, PAL_NONE);
    00668
    00669   /* Draw structures. */
    00670   uint     zoffs = 0;
    00671   SpriteID base  = GetCanalSprite(CF_LOCKS, ti->tile);
    00672
    00673   if (base == 0) {
    00674     /* If no custom graphics, use defaults. */
    00675     base = SPR_LOCK_BASE;
    00676     uint8 z_threshold = section >= 8 ? 8 : 0;
    00677     zoffs = ti->z > z_threshold ? 24 : 0;
    00678   }
    00679
    00680   DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
    00681 }
    00682
    00684 static void DrawWaterDepot(const TileInfo *ti)
    00685 {
    00686   DrawWaterClassGround(ti);
    00687   DrawWaterTileStruct(ti, _shipdepot_display_data[GetSection(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
    00688 }
    00689
    00690 static void DrawRiverWater(const TileInfo *ti)
    00691 {
    00692   SpriteID image = SPR_FLAT_WATER_TILE;
    00693   uint     offset = 0;
    00694   uint     edges_offset = 0;
    00695
    00696   if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00697     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
    00698     if (image == 0) {
    00699       switch (ti->tileh) {
    00700         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
    00701         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
    00702         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
    00703         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
    00704         default:       image = SPR_FLAT_WATER_TILE;    break;
    00705       }
    00706     } else {
    00707       /* Flag bit 0 indicates that the first sprite is flat water. */
    00708       offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
    00709
    00710       switch (ti->tileh) {
    00711         case SLOPE_SE:              edges_offset += 12; break;
    00712         case SLOPE_NE: offset += 1; edges_offset += 24; break;
    00713         case SLOPE_SW: offset += 2; edges_offset += 36; break;
    00714         case SLOPE_NW: offset += 3; edges_offset += 48; break;
    00715         default:       offset  = 0; break;
    00716       }
    00717
    00718       offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
    00719     }
    00720   }
    00721
    00722   DrawGroundSprite(image + offset, PAL_NONE);
    00723
    00724   /* Draw river edges if available. */
    00725   DrawWaterEdges(false, edges_offset, ti->tile);
    00726 }
    00727
    00728 void DrawShoreTile(Slope tileh)
    00729 {
    00730   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
    00731    * This allows to calculate the proper sprite to display for this Slope */
    00732   static const byte tileh_to_shoresprite[32] = {
    00733     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
    00734     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
    00735   };
    00736
    00737   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
    00738   assert(tileh != SLOPE_FLAT);     // Shore is never flat
    00739
    00740   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
    00741
    00742   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
    00743 }
    00744
    00745 void DrawWaterClassGround(const TileInfo *ti)
    00746 {
    00747   switch (GetWaterClass(ti->tile)) {
    00748     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
    00749     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
    00750     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
    00751     default: NOT_REACHED();
    00752   }
    00753 }
    00754
    00755 static void DrawTile_Water(TileInfo *ti)
    00756 {
    00757   switch (GetWaterTileType(ti->tile)) {
    00758     case WATER_TILE_CLEAR:
    00759       DrawWaterClassGround(ti);
    00760       DrawBridgeMiddle(ti);
    00761       break;
    00762
    00763     case WATER_TILE_COAST: {
    00764       DrawShoreTile(ti->tileh);
    00765       DrawBridgeMiddle(ti);
    00766       break;
    00767     }
    00768
    00769     case WATER_TILE_LOCK:
    00770       DrawWaterLock(ti);
    00771       break;
    00772
    00773     case WATER_TILE_DEPOT:
    00774       DrawWaterDepot(ti);
    00775       break;
    00776   }
    00777 }
    00778
    00779 void DrawShipDepotSprite(int x, int y, int image)
    00780 {
    00781   const DrawTileSprites &dts = _shipdepot_display_data[image];
    00782
    00783   DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
    00784   DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
    00785 }
    00786
    00787
    00788 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
    00789 {
    00790   uint z;
    00791   Slope tileh = GetTileSlope(tile, &z);
    00792
    00793   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00794 }
    00795
    00796 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
    00797 {
    00798   return FOUNDATION_NONE;
    00799 }
    00800
    00801 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
    00802 {
    00803   switch (GetWaterTileType(tile)) {
    00804     case WATER_TILE_CLEAR:
    00805       switch (GetWaterClass(tile)) {
    00806         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
    00807         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
    00808         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
    00809         default: NOT_REACHED(); break;
    00810       }
    00811       break;
    00812     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
    00813     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
    00814     case WATER_TILE_DEPOT:
    00815       td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
    00816       td->build_date = Depot::GetByTile(tile)->build_date;
    00817       break;
    00818     default: NOT_REACHED(); break;
    00819   }
    00820
    00821   td->owner[0] = GetTileOwner(tile);
    00822 }
    00823
    00829 static void FloodVehicle(Vehicle *v)
    00830 {
    00831   uint pass = v->Crash(true);
    00832
    00833   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
    00834   SetDParam(0, pass);
    00835   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NS_ACCIDENT, v->index);
    00836   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    00837   SndPlayVehicleFx(SND_12_EXPLOSION, v);
    00838 }
    00839
    00846 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
    00847 {
    00848   if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
    00849
    00850   switch (v->type) {
    00851     default: break;
    00852
    00853     case VEH_AIRCRAFT: {
    00854       if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
    00855       if (v->subtype == AIR_SHADOW) break;
    00856
    00857       /* We compare v->z_pos against delta_z + 1 because the shadow
    00858        * is at delta_z and the actual aircraft at delta_z + 1. */
    00859       const Station *st = Station::GetByTile(v->tile);
    00860       const AirportFTAClass *airport = st->airport.GetFTA();
    00861       if (v->z_pos != airport->delta_z + 1) break;
    00862
    00863       FloodVehicle(v);
    00864       break;
    00865     }
    00866
    00867     case VEH_TRAIN:
    00868     case VEH_ROAD: {
    00869       int z = *(byte*)data;
    00870       if (v->z_pos > z) break;
    00871       FloodVehicle(v->First());
    00872       break;
    00873     }
    00874   }
    00875
    00876   return NULL;
    00877 }
    00878
    00884 static void FloodVehicles(TileIndex tile)
    00885 {
    00886   int z = 0;
    00887
    00888   if (IsAirportTile(tile)) {
    00889     const Station *st = Station::GetByTile(tile);
    00890     TILE_AREA_LOOP(tile, st->airport) {
    00891       if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00892     }
    00893
    00894     /* No vehicle could be flooded on this airport anymore */
    00895     return;
    00896   }
    00897
    00898   if (!IsBridgeTile(tile)) {
    00899     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00900     return;
    00901   }
    00902
    00903   TileIndex end = GetOtherBridgeEnd(tile);
    00904   z = GetBridgeHeight(tile);
    00905
    00906   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00907   FindVehicleOnPos(end, &z, &FloodVehicleProc);
    00908 }
    00909
    00915 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
    00916 {
    00917   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
    00918    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
    00919    * FLOOD_PASSIVE: (not used)
    00920    * FLOOD_NONE:    canals, rivers, everything else
    00921    */
    00922   switch (GetTileType(tile)) {
    00923     case MP_WATER:
    00924       if (IsCoast(tile)) {
    00925         Slope tileh = GetTileSlope(tile, NULL);
    00926         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00927       }
    00928       /* FALL THROUGH */
    00929     case MP_STATION:
    00930     case MP_INDUSTRY:
    00931     case MP_OBJECT:
    00932       return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
    00933
    00934     case MP_RAILWAY:
    00935       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00936         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00937       }
    00938       return FLOOD_NONE;
    00939
    00940     case MP_TREES:
    00941       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
    00942
    00943     default:
    00944       return FLOOD_NONE;
    00945   }
    00946 }
    00947
    00951 void DoFloodTile(TileIndex target)
    00952 {
    00953   assert(!IsTileType(target, MP_WATER));
    00954
    00955   bool flooded = false; // Will be set to true if something is changed.
    00956
    00957   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
    00958
    00959   Slope tileh = GetTileSlope(target, NULL);
    00960   if (tileh != SLOPE_FLAT) {
    00961     /* make coast.. */
    00962     switch (GetTileType(target)) {
    00963       case MP_RAILWAY: {
    00964         if (!IsPlainRail(target)) break;
    00965         FloodVehicles(target);
    00966         flooded = FloodHalftile(target);
    00967         break;
    00968       }
    00969
    00970       case MP_TREES:
    00971         if (!IsSlopeWithOneCornerRaised(tileh)) {
    00972           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
    00973           MarkTileDirtyByTile(target);
    00974           flooded = true;
    00975           break;
    00976         }
    00977         /* FALL THROUGH */
    00978
    00979       case MP_CLEAR:
    00980         if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00981           MakeShore(target);
    00982           MarkTileDirtyByTile(target);
    00983           flooded = true;
    00984         }
    00985         break;
    00986
    00987       default:
    00988         break;
    00989     }
    00990   } else {
    00991     /* Flood vehicles */
    00992     FloodVehicles(target);
    00993
    00994     /* flood flat tile */
    00995     if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00996       MakeSea(target);
    00997       MarkTileDirtyByTile(target);
    00998       flooded = true;
    00999     }
    01000   }
    01001
    01002   if (flooded) {
    01003     /* Mark surrounding canal tiles dirty too to avoid glitches */
    01004     MarkCanalsAndRiversAroundDirty(target);
    01005
    01006     /* update signals if needed */
    01007     UpdateSignalsInBuffer();
    01008   }
    01009
    01010   cur_company.Restore();
    01011 }
    01012
    01016 static void DoDryUp(TileIndex tile)
    01017 {
    01018   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
    01019
    01020   switch (GetTileType(tile)) {
    01021     case MP_RAILWAY:
    01022       assert(IsPlainRail(tile));
    01023       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
    01024
    01025       RailGroundType new_ground;
    01026       switch (GetTrackBits(tile)) {
    01027         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
    01028         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
    01029         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
    01030         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
    01031         default: NOT_REACHED();
    01032       }
    01033       SetRailGroundType(tile, new_ground);
    01034       MarkTileDirtyByTile(tile);
    01035       break;
    01036
    01037     case MP_TREES:
    01038       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
    01039       MarkTileDirtyByTile(tile);
    01040       break;
    01041
    01042     case MP_WATER:
    01043       assert(IsCoast(tile));
    01044
    01045       if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    01046         MakeClear(tile, CLEAR_GRASS, 3);
    01047         MarkTileDirtyByTile(tile);
    01048       }
    01049       break;
    01050
    01051     default: NOT_REACHED();
    01052   }
    01053
    01054   cur_company.Restore();
    01055 }
    01056
    01063 void TileLoop_Water(TileIndex tile)
    01064 {
    01065   switch (GetFloodingBehaviour(tile)) {
    01066     case FLOOD_ACTIVE:
    01067       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    01068         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
    01069         if (dest == INVALID_TILE) continue;
    01070         /* do not try to flood water tiles - increases performance a lot */
    01071         if (IsTileType(dest, MP_WATER)) continue;
    01072
    01073         uint z_dest;
    01074         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01075         if (z_dest > 0) continue;
    01076
    01077         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
    01078
    01079         DoFloodTile(dest);
    01080       }
    01081       break;
    01082
    01083     case FLOOD_DRYUP: {
    01084       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01085       uint dir;
    01086       FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
    01087         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
    01088         if (dest == INVALID_TILE) continue;
    01089
    01090         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
    01091         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
    01092       }
    01093       DoDryUp(tile);
    01094       break;
    01095     }
    01096
    01097     default: return;
    01098   }
    01099 }
    01100
    01101 void ConvertGroundTilesIntoWaterTiles()
    01102 {
    01103   uint z;
    01104
    01105   for (TileIndex tile = 0; tile < MapSize(); ++tile) {
    01106     Slope slope = GetTileSlope(tile, &z);
    01107     if (IsTileType(tile, MP_CLEAR) && z == 0) {
    01108       /* Make both water for tiles at level 0
    01109        * and make shore, as that looks much better
    01110        * during the generation. */
    01111       switch (slope) {
    01112         case SLOPE_FLAT:
    01113           MakeSea(tile);
    01114           break;
    01115
    01116         case SLOPE_N:
    01117         case SLOPE_E:
    01118         case SLOPE_S:
    01119         case SLOPE_W:
    01120           MakeShore(tile);
    01121           break;
    01122
    01123         default:
    01124           uint dir;
    01125           FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
    01126             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
    01127             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
    01128             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
    01129               MakeShore(tile);
    01130               break;
    01131             }
    01132           }
    01133           break;
    01134       }
    01135     }
    01136   }
    01137 }
    01138
    01139 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    01140 {
    01141   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
    01142
    01143   TrackBits ts;
    01144
    01145   if (mode != TRANSPORT_WATER) return 0;
    01146
    01147   switch (GetWaterTileType(tile)) {
    01148     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
    01149     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
    01150     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
    01151     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
    01152     default: return 0;
    01153   }
    01154   if (TileX(tile) == 0) {
    01155     /* NE border: remove tracks that connects NE tile edge */
    01156     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
    01157   }
    01158   if (TileY(tile) == 0) {
    01159     /* NW border: remove tracks that connects NW tile edge */
    01160     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
    01161   }
    01162   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
    01163 }
    01164
    01165 static bool ClickTile_Water(TileIndex tile)
    01166 {
    01167   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
    01168     ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
    01169     return true;
    01170   }
    01171   return false;
    01172 }
    01173
    01174 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
    01175 {
    01176   if (!IsTileOwner(tile, old_owner)) return;
    01177
    01178   if (new_owner != INVALID_OWNER) {
    01179     SetTileOwner(tile, new_owner);
    01180     return;
    01181   }
    01182
    01183   /* Remove depot */
    01184   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
    01185
    01186   /* Set owner of canals and locks ... and also canal under dock there was before.
    01187    * Check if the new owner after removing depot isn't OWNER_WATER. */
    01188   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
    01189 }
    01190
    01191 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
    01192 {
    01193   return VETSB_CONTINUE;
    01194 }
    01195
    01196 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
    01197 {
    01198   /* Canals can't be terraformed */
    01199   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
    01200
    01201   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    01202 }
    01203
    01204
    01205 extern const TileTypeProcs _tile_type_water_procs = {
    01206   DrawTile_Water,           // draw_tile_proc
    01207   GetSlopeZ_Water,          // get_slope_z_proc
    01208   ClearTile_Water,          // clear_tile_proc
    01209   NULL,                     // add_accepted_cargo_proc
    01210   GetTileDesc_Water,        // get_tile_desc_proc
    01211   GetTileTrackStatus_Water, // get_tile_track_status_proc
    01212   ClickTile_Water,          // click_tile_proc
    01213   NULL,                     // animate_tile_proc
    01214   TileLoop_Water,           // tile_loop_clear
    01215   ChangeTileOwner_Water,    // change_tile_owner_clear
    01216   NULL,                     // add_produced_cargo_proc
    01217   VehicleEnter_Water,       // vehicle_enter_tile_proc
    01218   GetFoundation_Water,      // get_foundation_proc
    01219   TerraformTile_Water,      // terraform_tile_proc
    01220 };