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