# water_cmd.cpp

Go to the documentation of this file.

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