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