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