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