# water_cmd.cpp

Go to the documentation of this file.

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