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 #include "newgrf_generic.h"
00042 
00043 #include "table/strings.h"
00044 
00048 static const uint8 _flood_from_dirs[] = {
00049   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
00050   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
00051   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
00052   (1 << DIR_NE),                                                 // SLOPE_SW
00053   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
00054   0,                                                             // SLOPE_EW
00055   (1 << DIR_NW),                                                 // SLOPE_SE
00056   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
00057   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
00058   (1 << DIR_SE),                                                 // SLOPE_NW
00059   0,                                                             // SLOPE_NS
00060   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
00061   (1 << DIR_SW),                                                 // SLOPE_NE
00062   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
00063   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
00064 };
00065 
00072 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00073 {
00074   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00075 }
00076 
00083 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00084 {
00085   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00086     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00087   }
00088 }
00089 
00090 
00100 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00101 {
00102   Axis axis = Extract<Axis, 0, 1>(p1);
00103 
00104   TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00105 
00106   if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
00107     return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
00108   }
00109 
00110   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00111     (MayHaveBridgeAbove(tile2) && IsBridgeAbove(tile2))) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00112 
00113   if (GetTileSlope(tile) != SLOPE_FLAT || GetTileSlope(tile2) != SLOPE_FLAT) {
00114     /* Prevent depots on rapids */
00115     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00116   }
00117 
00118   if (!Depot::CanAllocateItem()) return CMD_ERROR;
00119 
00120   WaterClass wc1 = GetWaterClass(tile);
00121   WaterClass wc2 = GetWaterClass(tile2);
00122   CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
00123 
00124   bool add_cost = !IsWaterTile(tile);
00125   CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00126   if (ret.Failed()) return ret;
00127   if (add_cost) {
00128     cost.AddCost(ret);
00129   }
00130   add_cost = !IsWaterTile(tile2);
00131   ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00132   if (ret.Failed()) return ret;
00133   if (add_cost) {
00134     cost.AddCost(ret);
00135   }
00136 
00137   if (flags & DC_EXEC) {
00138     Depot *depot = new Depot(tile);
00139     depot->build_date = _date;
00140 
00141     if (wc1 == WATER_CLASS_CANAL || wc2 == WATER_CLASS_CANAL) {
00142       /* Update infrastructure counts after the unconditional clear earlier. */
00143       Company::Get(_current_company)->infrastructure.water += wc1 == WATER_CLASS_CANAL && wc2 == WATER_CLASS_CANAL ? 2 : 1;
00144     }
00145     Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR;
00146     DirtyCompanyInfrastructureWindows(_current_company);
00147 
00148     MakeShipDepot(tile,  _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
00149     MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
00150     MarkTileDirtyByTile(tile);
00151     MarkTileDirtyByTile(tile2);
00152     MakeDefaultName(depot);
00153   }
00154 
00155   return cost;
00156 }
00157 
00158 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00159 {
00160   WaterClass wc = GetWaterClass(tile);
00161 
00162   /* Autoslope might turn an originally canal or river tile into land */
00163   int z;
00164   if (GetTileSlope(tile, &z) != SLOPE_FLAT) {
00165     if (wc == WATER_CLASS_CANAL) {
00166       /* If we clear the canal, we have to remove it from the infrastructure count as well. */
00167       Company *c = Company::GetIfValid(o);
00168       if (c != NULL) {
00169         c->infrastructure.water--;
00170         DirtyCompanyInfrastructureWindows(c->index);
00171       }
00172     }
00173     wc = WATER_CLASS_INVALID;
00174   }
00175 
00176   if (wc == WATER_CLASS_SEA && z > 0) {
00177     /* Update company infrastructure count. */
00178     Company *c = Company::GetIfValid(o);
00179     if (c != NULL) {
00180       c->infrastructure.water++;
00181       DirtyCompanyInfrastructureWindows(c->index);
00182     }
00183 
00184     wc = WATER_CLASS_CANAL;
00185   }
00186 
00187   /* Zero map array and terminate animation */
00188   DoClearSquare(tile);
00189 
00190   /* Maybe change to water */
00191   switch (wc) {
00192     case WATER_CLASS_SEA:   MakeSea(tile);                break;
00193     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00194     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
00195     default: break;
00196   }
00197 
00198   MarkTileDirtyByTile(tile);
00199 }
00200 
00201 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
00202 {
00203   if (!IsShipDepot(tile)) return CMD_ERROR;
00204 
00205   CommandCost ret = CheckTileOwnership(tile);
00206   if (ret.Failed()) return ret;
00207 
00208   TileIndex tile2 = GetOtherShipDepotTile(tile);
00209 
00210   /* do not check for ship on tile when company goes bankrupt */
00211   if (!(flags & DC_BANKRUPT)) {
00212     CommandCost ret = EnsureNoVehicleOnGround(tile);
00213     if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
00214     if (ret.Failed()) return ret;
00215   }
00216 
00217   if (flags & DC_EXEC) {
00218     delete Depot::GetByTile(tile);
00219 
00220     Company *c = Company::GetIfValid(GetTileOwner(tile));
00221     if (c != NULL) {
00222       c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR;
00223       DirtyCompanyInfrastructureWindows(c->index);
00224     }
00225 
00226     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
00227     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00228   }
00229 
00230   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
00231 }
00232 
00240 static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
00241 {
00242   CommandCost cost(EXPENSES_CONSTRUCTION);
00243 
00244   int delta = TileOffsByDiagDir(dir);
00245   CommandCost ret = EnsureNoVehicleOnGround(tile);
00246   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
00247   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
00248   if (ret.Failed()) return ret;
00249 
00250   /* middle tile */
00251   WaterClass wc_middle = IsWaterTile(tile) ? GetWaterClass(tile) : WATER_CLASS_CANAL;
00252   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00253   if (ret.Failed()) return ret;
00254   cost.AddCost(ret);
00255 
00256   /* lower tile */
00257   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00258 
00259   if (!IsWaterTile(tile - delta)) {
00260     ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00261     if (ret.Failed()) return ret;
00262     cost.AddCost(ret);
00263     cost.AddCost(_price[PR_BUILD_CANAL]);
00264   }
00265   if (GetTileSlope(tile - delta) != SLOPE_FLAT) {
00266     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00267   }
00268 
00269   /* upper tile */
00270   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
00271 
00272   if (!IsWaterTile(tile + delta)) {
00273     ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00274     if (ret.Failed()) return ret;
00275     cost.AddCost(ret);
00276     cost.AddCost(_price[PR_BUILD_CANAL]);
00277   }
00278   if (GetTileSlope(tile + delta) != SLOPE_FLAT) {
00279     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00280   }
00281 
00282   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00283       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00284       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00285     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00286   }
00287 
00288   if (flags & DC_EXEC) {
00289     /* Update company infrastructure counts. */
00290     Company *c = Company::GetIfValid(_current_company);
00291     if (c != NULL) {
00292       /* Counts for the 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 -= 3 * LOCK_DEPOT_TILE_FACTOR; // 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, NT_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   bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
01262 
01263   /* No need to dirty company windows here, we'll redraw the whole screen anyway. */
01264   if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
01265   if (new_owner != INVALID_OWNER) {
01266     if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
01267     /* Only subtract from the old owner here if the new owner is valid,
01268      * otherwise we clear ship depots and canal water below. */
01269     if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
01270       Company::Get(old_owner)->infrastructure.water--;
01271       Company::Get(new_owner)->infrastructure.water++;
01272     }
01273     if (IsShipDepot(tile)) {
01274       Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
01275       Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
01276     }
01277 
01278     SetTileOwner(tile, new_owner);
01279     return;
01280   }
01281 
01282   /* Remove depot */
01283   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01284 
01285   /* Set owner of canals and locks ... and also canal under dock there was before.
01286    * Check if the new owner after removing depot isn't OWNER_WATER. */
01287   if (IsTileOwner(tile, old_owner)) {
01288     if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
01289     SetTileOwner(tile, OWNER_NONE);
01290   }
01291 }
01292 
01293 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01294 {
01295   return VETSB_CONTINUE;
01296 }
01297 
01298 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
01299 {
01300   /* Canals can't be terraformed */
01301   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01302 
01303   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01304 }
01305 
01306 
01307 extern const TileTypeProcs _tile_type_water_procs = {
01308   DrawTile_Water,           // draw_tile_proc
01309   GetSlopePixelZ_Water,     // get_slope_z_proc
01310   ClearTile_Water,          // clear_tile_proc
01311   NULL,                     // add_accepted_cargo_proc
01312   GetTileDesc_Water,        // get_tile_desc_proc
01313   GetTileTrackStatus_Water, // get_tile_track_status_proc
01314   ClickTile_Water,          // click_tile_proc
01315   NULL,                     // animate_tile_proc
01316   TileLoop_Water,           // tile_loop_proc
01317   ChangeTileOwner_Water,    // change_tile_owner_proc
01318   NULL,                     // add_produced_cargo_proc
01319   VehicleEnter_Water,       // vehicle_enter_tile_proc
01320   GetFoundation_Water,      // get_foundation_proc
01321   TerraformTile_Water,      // terraform_tile_proc
01322 };