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