# water_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: water_cmd.cpp 22991 2011-10-04 20:06:23Z 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 "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 + delta));
    00283     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
    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       /* Make sure no vehicle is on the tile */
    00394       CommandCost ret = EnsureNoVehicleOnGround(tile);
    00395       if (ret.Failed()) return ret;
    00396
    00397       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE) {
    00398         CommandCost ret = CheckTileOwnership(tile);
    00399         if (ret.Failed()) return ret;
    00400       }
    00401
    00402       if (flags & DC_EXEC) {
    00403         DoClearSquare(tile);
    00404         MarkCanalsAndRiversAroundDirty(tile);
    00405       }
    00406
    00407       return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
    00408     }
    00409
    00410     case WATER_TILE_COAST: {
    00411       Slope slope = GetTileSlope(tile, NULL);
    00412
    00413       /* Make sure no vehicle is on the tile */
    00414       CommandCost ret = EnsureNoVehicleOnGround(tile);
    00415       if (ret.Failed()) return ret;
    00416
    00417       if (flags & DC_EXEC) {
    00418         DoClearSquare(tile);
    00419         MarkCanalsAndRiversAroundDirty(tile);
    00420       }
    00421       if (IsSlopeWithOneCornerRaised(slope)) {
    00422         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
    00423       } else {
    00424         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
    00425       }
    00426     }
    00427
    00428     case WATER_TILE_LOCK: {
    00429       static const TileIndexDiffC _lock_tomiddle_offs[] = {
    00430         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
    00431         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
    00432         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
    00433       };
    00434
    00435       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00436       if (_current_company == OWNER_WATER) return CMD_ERROR;
    00437       /* move to the middle tile.. */
    00438       return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetSection(tile)]), flags);
    00439     }
    00440
    00441     case WATER_TILE_DEPOT:
    00442       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
    00443       return RemoveShipDepot(tile, flags);
    00444
    00445     default:
    00446       NOT_REACHED();
    00447   }
    00448 }
    00449
    00458 static bool IsWateredTile(TileIndex tile, Direction from)
    00459 {
    00460   switch (GetTileType(tile)) {
    00461     case MP_WATER:
    00462       switch (GetWaterTileType(tile)) {
    00463         default: NOT_REACHED();
    00464         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
    00465         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
    00466
    00467         case WATER_TILE_COAST:
    00468           switch (GetTileSlope(tile, NULL)) {
    00469             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00470             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00471             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00472             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00473             default: return false;
    00474           }
    00475       }
    00476
    00477     case MP_RAILWAY:
    00478       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00479         assert(IsPlainRail(tile));
    00480         switch (GetTileSlope(tile, NULL)) {
    00481           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00482           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00483           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00484           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00485           default: return false;
    00486         }
    00487       }
    00488       return false;
    00489
    00490     case MP_STATION:
    00491       if (IsOilRig(tile)) {
    00492         /* Do not draw waterborders inside of industries.
    00493          * Note: There is no easy way to detect the industry of an oilrig tile. */
    00494         TileIndex src_tile = tile + TileOffsByDir(from);
    00495         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00496             (IsTileType(src_tile, MP_INDUSTRY))) return true;
    00497
    00498         return IsTileOnWater(tile);
    00499       }
    00500       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
    00501
    00502     case MP_INDUSTRY: {
    00503       /* Do not draw waterborders inside of industries.
    00504        * Note: There is no easy way to detect the industry of an oilrig tile. */
    00505       TileIndex src_tile = tile + TileOffsByDir(from);
    00506       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00507           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
    00508
    00509       return IsTileOnWater(tile);
    00510     }
    00511
    00512     case MP_OBJECT: return IsTileOnWater(tile);
    00513
    00514     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
    00515
    00516     default:          return false;
    00517   }
    00518 }
    00519
    00527 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
    00528 {
    00529   if (base != SPR_FLAT_WATER_TILE) {
    00530     /* Only call offset callback if the sprite is NewGRF-provided. */
    00531     offset = GetCanalSpriteOffset(feature, tile, offset);
    00532   }
    00533   DrawGroundSprite(base + offset, PAL_NONE);
    00534 }
    00535
    00542 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
    00543 {
    00544   CanalFeature feature;
    00545   SpriteID base = 0;
    00546   if (canal) {
    00547     feature = CF_DIKES;
    00548     base = GetCanalSprite(CF_DIKES, tile);
    00549     if (base == 0) base = SPR_CANAL_DIKES_BASE;
    00550   } else {
    00551     feature = CF_RIVER_EDGE;
    00552     base = GetCanalSprite(CF_RIVER_EDGE, tile);
    00553     if (base == 0) return; // Don't draw if no sprites provided.
    00554   }
    00555
    00556   uint wa;
    00557
    00558   /* determine the edges around with water. */
    00559   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
    00560   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
    00561   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
    00562   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
    00563
    00564   if (!(wa & 1)) DrawWaterSprite(base, offset,     feature, tile);
    00565   if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
    00566   if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
    00567   if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
    00568
    00569   /* right corner */
    00570   switch (wa & 0x03) {
    00571     case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
    00572     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
    00573   }
    00574
    00575   /* bottom corner */
    00576   switch (wa & 0x06) {
    00577     case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
    00578     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
    00579   }
    00580
    00581   /* left corner */
    00582   switch (wa & 0x0C) {
    00583     case  0: DrawWaterSprite(base, offset + 6, feature, tile); break;
    00584     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
    00585   }
    00586
    00587   /* upper corner */
    00588   switch (wa & 0x09) {
    00589     case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
    00590     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
    00591   }
    00592 }
    00593
    00595 static void DrawSeaWater(TileIndex tile)
    00596 {
    00597   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00598 }
    00599
    00601 static void DrawCanalWater(TileIndex tile)
    00602 {
    00603   SpriteID image = SPR_FLAT_WATER_TILE;
    00604   if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00605     /* First water slope sprite is flat water. */
    00606     image = GetCanalSprite(CF_WATERSLOPE, tile);
    00607     if (image == 0) image = SPR_FLAT_WATER_TILE;
    00608   }
    00609   DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
    00610
    00611   DrawWaterEdges(true, 0, tile);
    00612 }
    00613
    00614 struct LocksDrawTileStruct {
    00615   int8 delta_x, delta_y, delta_z;
    00616   byte width, height, depth;
    00617   SpriteID image;
    00618 };
    00619
    00620 #include "table/water_land.h"
    00621
    00631 static void DrawWaterTileStruct(const TileInfo *ti, const WaterDrawTileStruct *wdts, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
    00632 {
    00633   /* Don't draw if buildings are invisible. */
    00634   if (IsInvisibilitySet(TO_BUILDINGS)) return;
    00635
    00636   for (; wdts->delta_x != 0x80; wdts++) {
    00637     uint tile_offs = offset + wdts->image;
    00638     if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
    00639     AddSortableSpriteToDraw(base + tile_offs, palette,
    00640       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
    00641       wdts->size_x, wdts->size_y,
    00642       wdts->size_z, ti->z + wdts->delta_z,
    00643       IsTransparencySet(TO_BUILDINGS));
    00644   }
    00645 }
    00646
    00648 static void DrawWaterLock(const TileInfo *ti)
    00649 {
    00650   int section = GetSection(ti->tile);
    00651   const WaterDrawTileStruct *wdts = _lock_display_seq[section];
    00652
    00653   /* Draw ground sprite. */
    00654   SpriteID image = wdts++->image;
    00655
    00656   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
    00657   if (water_base == 0) {
    00658     /* Use default sprites. */
    00659     water_base = SPR_CANALS_BASE;
    00660   } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00661     /* NewGRF supplies a flat sprite as first sprite. */
    00662     if (image == SPR_FLAT_WATER_TILE) {
    00663       image = water_base;
    00664     } else {
    00665       image++;
    00666     }
    00667   }
    00668
    00669   if (image < 5) image += water_base;
    00670   DrawGroundSprite(image, PAL_NONE);
    00671
    00672   /* Draw structures. */
    00673   uint     zoffs = 0;
    00674   SpriteID base  = GetCanalSprite(CF_LOCKS, ti->tile);
    00675
    00676   if (base == 0) {
    00677     /* If no custom graphics, use defaults. */
    00678     base = SPR_LOCK_BASE;
    00679     uint8 z_threshold = section >= 8 ? 8 : 0;
    00680     zoffs = ti->z > z_threshold ? 24 : 0;
    00681   }
    00682
    00683   DrawWaterTileStruct(ti, wdts, base, zoffs, PAL_NONE, CF_LOCKS);
    00684 }
    00685
    00687 static void DrawWaterDepot(const TileInfo *ti)
    00688 {
    00689   DrawWaterClassGround(ti);
    00690   /* Skip first entry in _shipdepot_display_seq as this is the ground sprite. */
    00691   DrawWaterTileStruct(ti, _shipdepot_display_seq[GetSection(ti->tile)] + 1, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
    00692 }
    00693
    00694 static void DrawRiverWater(const TileInfo *ti)
    00695 {
    00696   SpriteID image = SPR_FLAT_WATER_TILE;
    00697   uint     offset = 0;
    00698   uint     edges_offset = 0;
    00699
    00700   if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
    00701     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
    00702     if (image == 0) {
    00703       switch (ti->tileh) {
    00704         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
    00705         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
    00706         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
    00707         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
    00708         default:       image = SPR_FLAT_WATER_TILE;    break;
    00709       }
    00710     } else {
    00711       /* Flag bit 0 indicates that the first sprite is flat water. */
    00712       offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
    00713
    00714       switch (ti->tileh) {
    00715         case SLOPE_SE:              edges_offset += 12; break;
    00716         case SLOPE_NE: offset += 1; edges_offset += 24; break;
    00717         case SLOPE_SW: offset += 2; edges_offset += 36; break;
    00718         case SLOPE_NW: offset += 3; edges_offset += 48; break;
    00719         default:       offset  = 0; break;
    00720       }
    00721
    00722       offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
    00723     }
    00724   }
    00725
    00726   DrawGroundSprite(image + offset, PAL_NONE);
    00727
    00728   /* Draw river edges if available. */
    00729   DrawWaterEdges(false, edges_offset, ti->tile);
    00730 }
    00731
    00732 void DrawShoreTile(Slope tileh)
    00733 {
    00734   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
    00735    * This allows to calculate the proper sprite to display for this Slope */
    00736   static const byte tileh_to_shoresprite[32] = {
    00737     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
    00738     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
    00739   };
    00740
    00741   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
    00742   assert(tileh != SLOPE_FLAT);     // Shore is never flat
    00743
    00744   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
    00745
    00746   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
    00747 }
    00748
    00749 void DrawWaterClassGround(const TileInfo *ti)
    00750 {
    00751   switch (GetWaterClass(ti->tile)) {
    00752     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
    00753     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
    00754     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
    00755     default: NOT_REACHED();
    00756   }
    00757 }
    00758
    00759 static void DrawTile_Water(TileInfo *ti)
    00760 {
    00761   switch (GetWaterTileType(ti->tile)) {
    00762     case WATER_TILE_CLEAR:
    00763       DrawWaterClassGround(ti);
    00764       DrawBridgeMiddle(ti);
    00765       break;
    00766
    00767     case WATER_TILE_COAST: {
    00768       DrawShoreTile(ti->tileh);
    00769       DrawBridgeMiddle(ti);
    00770       break;
    00771     }
    00772
    00773     case WATER_TILE_LOCK:
    00774       DrawWaterLock(ti);
    00775       break;
    00776
    00777     case WATER_TILE_DEPOT:
    00778       DrawWaterDepot(ti);
    00779       break;
    00780   }
    00781 }
    00782
    00783 void DrawShipDepotSprite(int x, int y, int image)
    00784 {
    00785   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
    00786
    00787   DrawSprite(wdts++->image, PAL_NONE, x, y);
    00788
    00789   for (; wdts->delta_x != 0x80; wdts++) {
    00790     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
    00791     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
    00792   }
    00793 }
    00794
    00795
    00796 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
    00797 {
    00798   uint z;
    00799   Slope tileh = GetTileSlope(tile, &z);
    00800
    00801   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00802 }
    00803
    00804 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
    00805 {
    00806   return FOUNDATION_NONE;
    00807 }
    00808
    00809 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
    00810 {
    00811   switch (GetWaterTileType(tile)) {
    00812     case WATER_TILE_CLEAR:
    00813       switch (GetWaterClass(tile)) {
    00814         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
    00815         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
    00816         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
    00817         default: NOT_REACHED(); break;
    00818       }
    00819       break;
    00820     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
    00821     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
    00822     case WATER_TILE_DEPOT:
    00823       td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
    00824       td->build_date = Depot::GetByTile(tile)->build_date;
    00825       break;
    00826     default: NOT_REACHED(); break;
    00827   }
    00828
    00829   td->owner[0] = GetTileOwner(tile);
    00830 }
    00831
    00837 static void FloodVehicle(Vehicle *v)
    00838 {
    00839   uint pass = v->Crash(true);
    00840
    00841   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
    00842   SetDParam(0, pass);
    00843   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NS_ACCIDENT, v->index);
    00844   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    00845   SndPlayVehicleFx(SND_12_EXPLOSION, v);
    00846 }
    00847
    00854 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
    00855 {
    00856   if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
    00857
    00858   switch (v->type) {
    00859     default: break;
    00860
    00861     case VEH_AIRCRAFT: {
    00862       if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
    00863       if (v->subtype == AIR_SHADOW) break;
    00864
    00865       /* We compare v->z_pos against delta_z + 1 because the shadow
    00866        * is at delta_z and the actual aircraft at delta_z + 1. */
    00867       const Station *st = Station::GetByTile(v->tile);
    00868       const AirportFTAClass *airport = st->airport.GetFTA();
    00869       if (v->z_pos != airport->delta_z + 1) break;
    00870
    00871       FloodVehicle(v);
    00872       break;
    00873     }
    00874
    00875     case VEH_TRAIN:
    00876     case VEH_ROAD: {
    00877       byte z = *(byte*)data;
    00878       if (v->z_pos > z) break;
    00879       FloodVehicle(v->First());
    00880       break;
    00881     }
    00882   }
    00883
    00884   return NULL;
    00885 }
    00886
    00892 static void FloodVehicles(TileIndex tile)
    00893 {
    00894   byte z = 0;
    00895
    00896   if (IsAirportTile(tile)) {
    00897     const Station *st = Station::GetByTile(tile);
    00898     TILE_AREA_LOOP(tile, st->airport) {
    00899       if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00900     }
    00901
    00902     /* No vehicle could be flooded on this airport anymore */
    00903     return;
    00904   }
    00905
    00906   if (!IsBridgeTile(tile)) {
    00907     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00908     return;
    00909   }
    00910
    00911   TileIndex end = GetOtherBridgeEnd(tile);
    00912   z = GetBridgeHeight(tile);
    00913
    00914   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00915   FindVehicleOnPos(end, &z, &FloodVehicleProc);
    00916 }
    00917
    00923 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
    00924 {
    00925   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
    00926    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
    00927    * FLOOD_PASSIVE: (not used)
    00928    * FLOOD_NONE:    canals, rivers, everything else
    00929    */
    00930   switch (GetTileType(tile)) {
    00931     case MP_WATER:
    00932       if (IsCoast(tile)) {
    00933         Slope tileh = GetTileSlope(tile, NULL);
    00934         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00935       }
    00936       /* FALL THROUGH */
    00937     case MP_STATION:
    00938     case MP_INDUSTRY:
    00939     case MP_OBJECT:
    00940       return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
    00941
    00942     case MP_RAILWAY:
    00943       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00944         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00945       }
    00946       return FLOOD_NONE;
    00947
    00948     case MP_TREES:
    00949       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
    00950
    00951     default:
    00952       return FLOOD_NONE;
    00953   }
    00954 }
    00955
    00959 void DoFloodTile(TileIndex target)
    00960 {
    00961   assert(!IsTileType(target, MP_WATER));
    00962
    00963   bool flooded = false; // Will be set to true if something is changed.
    00964
    00965   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
    00966
    00967   Slope tileh = GetTileSlope(target, NULL);
    00968   if (tileh != SLOPE_FLAT) {
    00969     /* make coast.. */
    00970     switch (GetTileType(target)) {
    00971       case MP_RAILWAY: {
    00972         if (!IsPlainRail(target)) break;
    00973         FloodVehicles(target);
    00974         flooded = FloodHalftile(target);
    00975         break;
    00976       }
    00977
    00978       case MP_TREES:
    00979         if (!IsSlopeWithOneCornerRaised(tileh)) {
    00980           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
    00981           MarkTileDirtyByTile(target);
    00982           flooded = true;
    00983           break;
    00984         }
    00985         /* FALL THROUGH */
    00986
    00987       case MP_CLEAR:
    00988         if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    00989           MakeShore(target);
    00990           MarkTileDirtyByTile(target);
    00991           flooded = true;
    00992         }
    00993         break;
    00994
    00995       default:
    00996         break;
    00997     }
    00998   } else {
    00999     /* Flood vehicles */
    01000     FloodVehicles(target);
    01001
    01002     /* flood flat tile */
    01003     if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    01004       MakeSea(target);
    01005       MarkTileDirtyByTile(target);
    01006       flooded = true;
    01007     }
    01008   }
    01009
    01010   if (flooded) {
    01011     /* Mark surrounding canal tiles dirty too to avoid glitches */
    01012     MarkCanalsAndRiversAroundDirty(target);
    01013
    01014     /* update signals if needed */
    01015     UpdateSignalsInBuffer();
    01016   }
    01017
    01018   cur_company.Restore();
    01019 }
    01020
    01024 static void DoDryUp(TileIndex tile)
    01025 {
    01026   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
    01027
    01028   switch (GetTileType(tile)) {
    01029     case MP_RAILWAY:
    01030       assert(IsPlainRail(tile));
    01031       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
    01032
    01033       RailGroundType new_ground;
    01034       switch (GetTrackBits(tile)) {
    01035         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
    01036         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
    01037         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
    01038         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
    01039         default: NOT_REACHED();
    01040       }
    01041       SetRailGroundType(tile, new_ground);
    01042       MarkTileDirtyByTile(tile);
    01043       break;
    01044
    01045     case MP_TREES:
    01046       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
    01047       MarkTileDirtyByTile(tile);
    01048       break;
    01049
    01050     case MP_WATER:
    01051       assert(IsCoast(tile));
    01052
    01053       if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
    01054         MakeClear(tile, CLEAR_GRASS, 3);
    01055         MarkTileDirtyByTile(tile);
    01056       }
    01057       break;
    01058
    01059     default: NOT_REACHED();
    01060   }
    01061
    01062   cur_company.Restore();
    01063 }
    01064
    01071 void TileLoop_Water(TileIndex tile)
    01072 {
    01073   switch (GetFloodingBehaviour(tile)) {
    01074     case FLOOD_ACTIVE:
    01075       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    01076         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
    01077         if (dest == INVALID_TILE) continue;
    01078         /* do not try to flood water tiles - increases performance a lot */
    01079         if (IsTileType(dest, MP_WATER)) continue;
    01080
    01081         uint z_dest;
    01082         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01083         if (z_dest > 0) continue;
    01084
    01085         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
    01086
    01087         DoFloodTile(dest);
    01088       }
    01089       break;
    01090
    01091     case FLOOD_DRYUP: {
    01092       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01093       uint dir;
    01094       FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
    01095         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
    01096         if (dest == INVALID_TILE) continue;
    01097
    01098         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
    01099         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
    01100       }
    01101       DoDryUp(tile);
    01102       break;
    01103     }
    01104
    01105     default: return;
    01106   }
    01107 }
    01108
    01109 void ConvertGroundTilesIntoWaterTiles()
    01110 {
    01111   uint z;
    01112
    01113   for (TileIndex tile = 0; tile < MapSize(); ++tile) {
    01114     Slope slope = GetTileSlope(tile, &z);
    01115     if (IsTileType(tile, MP_CLEAR) && z == 0) {
    01116       /* Make both water for tiles at level 0
    01117        * and make shore, as that looks much better
    01118        * during the generation. */
    01119       switch (slope) {
    01120         case SLOPE_FLAT:
    01121           MakeSea(tile);
    01122           break;
    01123
    01124         case SLOPE_N:
    01125         case SLOPE_E:
    01126         case SLOPE_S:
    01127         case SLOPE_W:
    01128           MakeShore(tile);
    01129           break;
    01130
    01131         default:
    01132           uint dir;
    01133           FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
    01134             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
    01135             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
    01136             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
    01137               MakeShore(tile);
    01138               break;
    01139             }
    01140           }
    01141           break;
    01142       }
    01143     }
    01144   }
    01145 }
    01146
    01147 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    01148 {
    01149   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
    01150
    01151   TrackBits ts;
    01152
    01153   if (mode != TRANSPORT_WATER) return 0;
    01154
    01155   switch (GetWaterTileType(tile)) {
    01156     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
    01157     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
    01158     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
    01159     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
    01160     default: return 0;
    01161   }
    01162   if (TileX(tile) == 0) {
    01163     /* NE border: remove tracks that connects NE tile edge */
    01164     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
    01165   }
    01166   if (TileY(tile) == 0) {
    01167     /* NW border: remove tracks that connects NW tile edge */
    01168     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
    01169   }
    01170   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
    01171 }
    01172
    01173 static bool ClickTile_Water(TileIndex tile)
    01174 {
    01175   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
    01176     ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
    01177     return true;
    01178   }
    01179   return false;
    01180 }
    01181
    01182 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
    01183 {
    01184   if (!IsTileOwner(tile, old_owner)) return;
    01185
    01186   if (new_owner != INVALID_OWNER) {
    01187     SetTileOwner(tile, new_owner);
    01188     return;
    01189   }
    01190
    01191   /* Remove depot */
    01192   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
    01193
    01194   /* Set owner of canals and locks ... and also canal under dock there was before.
    01195    * Check if the new owner after removing depot isn't OWNER_WATER. */
    01196   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
    01197 }
    01198
    01199 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
    01200 {
    01201   return VETSB_CONTINUE;
    01202 }
    01203
    01204 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
    01205 {
    01206   /* Canals can't be terraformed */
    01207   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
    01208
    01209   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    01210 }
    01211
    01212
    01213 extern const TileTypeProcs _tile_type_water_procs = {
    01214   DrawTile_Water,           // draw_tile_proc
    01215   GetSlopeZ_Water,          // get_slope_z_proc
    01216   ClearTile_Water,          // clear_tile_proc
    01217   NULL,                     // add_accepted_cargo_proc
    01218   GetTileDesc_Water,        // get_tile_desc_proc
    01219   GetTileTrackStatus_Water, // get_tile_track_status_proc
    01220   ClickTile_Water,          // click_tile_proc
    01221   NULL,                     // animate_tile_proc
    01222   TileLoop_Water,           // tile_loop_clear
    01223   ChangeTileOwner_Water,    // change_tile_owner_clear
    01224   NULL,                     // add_produced_cargo_proc
    01225   VehicleEnter_Water,       // vehicle_enter_tile_proc
    01226   GetFoundation_Water,      // get_foundation_proc
    01227   TerraformTile_Water,      // terraform_tile_proc
    01228 };