water_cmd.cpp

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