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