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