water_cmd.cpp

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