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