# water_cmd.cpp

Go to the documentation of this file.

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