water_cmd.cpp

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