# water_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: water_cmd.cpp 15534 2009-02-20 23:21:04Z frosch $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "cmd_helper.h"
    00008 #include "landscape.h"
    00009 #include "viewport_func.h"
    00010 #include "command_func.h"
    00011 #include "town.h"
    00012 #include "news_func.h"
    00013 #include "depot_base.h"
    00014 #include "depot_func.h"
    00015 #include "vehicle_gui.h"
    00016 #include "train.h"
    00017 #include "roadveh.h"
    00018 #include "water.h"
    00019 #include "industry_map.h"
    00020 #include "cargotype.h"
    00021 #include "newgrf_canal.h"
    00022 #include "transparency.h"
    00023 #include "strings_func.h"
    00024 #include "functions.h"
    00025 #include "window_func.h"
    00026 #include "vehicle_func.h"
    00027 #include "sound_func.h"
    00028 #include "company_func.h"
    00029 #include "clear_map.h"
    00030 #include "tree_map.h"
    00031 #include "aircraft.h"
    00032 #include "newgrf_cargo.h"
    00033 #include "effectvehicle_func.h"
    00034 #include "tunnelbridge_map.h"
    00035 #include "ai/ai.hpp"
    00036
    00037 #include "table/sprites.h"
    00038 #include "table/strings.h"
    00039
    00043 enum FloodingBehaviour {
    00044   FLOOD_NONE,
    00045   FLOOD_ACTIVE,
    00046   FLOOD_PASSIVE,
    00047   FLOOD_DRYUP,
    00048 };
    00049
    00053 static const uint8 _flood_from_dirs[] = {
    00054   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
    00055   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
    00056   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
    00057   (1 << DIR_NE),                                                 // SLOPE_SW
    00058   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
    00059   0,                                                             // SLOPE_EW
    00060   (1 << DIR_NW),                                                 // SLOPE_SE
    00061   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
    00062   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
    00063   (1 << DIR_SE),                                                 // SLOPE_NW
    00064   0,                                                             // SLOPE_NS
    00065   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
    00066   (1 << DIR_SW),                                                 // SLOPE_NE
    00067   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
    00068   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
    00069 };
    00070
    00077 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
    00078 {
    00079   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
    00080 }
    00081
    00088 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
    00089 {
    00090   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    00091     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
    00092   }
    00093 }
    00094
    00095
    00102 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00103 {
    00104   TileIndex tile2;
    00105
    00106   CommandCost ret;
    00107
    00108   Axis axis = Extract<Axis, 0>(p1);
    00109
    00110   tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
    00111
    00112   if (!IsWaterTile(tile) || !IsWaterTile(tile2)) {
    00113     return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
    00114   }
    00115
    00116   if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
    00117
    00118   if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
    00119     /* Prevent depots on rapids */
    00120     return_cmd_error(STR_0239_SITE_UNSUITABLE);
    00121   }
    00122
    00123   WaterClass wc1 = GetWaterClass(tile);
    00124   WaterClass wc2 = GetWaterClass(tile2);
    00125   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00126   if (CmdFailed(ret)) return CMD_ERROR;
    00127   ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00128   if (CmdFailed(ret)) return CMD_ERROR;
    00129
    00130   if (!Depot::CanAllocateItem()) return CMD_ERROR;
    00131
    00132   if (flags & DC_EXEC) {
    00133     Depot *depot = new Depot(tile);
    00134     depot->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
    00135
    00136     MakeShipDepot(tile,  _current_company, DEPOT_NORTH, axis, wc1);
    00137     MakeShipDepot(tile2, _current_company, DEPOT_SOUTH, axis, wc2);
    00138     MarkTileDirtyByTile(tile);
    00139     MarkTileDirtyByTile(tile2);
    00140   }
    00141
    00142   return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot);
    00143 }
    00144
    00145 void MakeWaterKeepingClass(TileIndex tile, Owner o)
    00146 {
    00147   assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile) || IsOilRig(tile))) || IsTileType(tile, MP_INDUSTRY));
    00148
    00149   WaterClass wc = GetWaterClass(tile);
    00150
    00151   /* Autoslope might turn an originally canal or river tile into land */
    00152   uint z;
    00153   if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
    00154
    00155   if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
    00156
    00157   switch (wc) {
    00158     case WATER_CLASS_SEA:   MakeWater(tile);              break;
    00159     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
    00160     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
    00161     default:                DoClearSquare(tile);          break;
    00162   }
    00163 }
    00164
    00165 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
    00166 {
    00167   if (!IsShipDepot(tile)) return CMD_ERROR;
    00168   if (!CheckTileOwnership(tile)) return CMD_ERROR;
    00169
    00170   TileIndex tile2 = GetOtherShipDepotTile(tile);
    00171
    00172   /* do not check for ship on tile when company goes bankrupt */
    00173   if (!(flags & DC_BANKRUPT)) {
    00174     if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
    00175   }
    00176
    00177   if (flags & DC_EXEC) {
    00178     /* Kill the depot, which is registered at the northernmost tile. Use that one */
    00179     delete GetDepotByTile(tile2 < tile ? tile2 : tile);
    00180
    00181     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
    00182     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
    00183     MarkTileDirtyByTile(tile);
    00184     MarkTileDirtyByTile(tile2);
    00185   }
    00186
    00187   return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_ship_depot);
    00188 }
    00189
    00191 static CommandCost DoBuildShiplift(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
    00192 {
    00193   CommandCost ret;
    00194   int delta;
    00195
    00196   /* middle tile */
    00197   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00198   if (CmdFailed(ret)) return CMD_ERROR;
    00199
    00200   delta = TileOffsByDiagDir(dir);
    00201   /* lower tile */
    00202   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
    00203
    00204   ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00205   if (CmdFailed(ret)) return CMD_ERROR;
    00206   if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
    00207     return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
    00208   }
    00209
    00210   /* upper tile */
    00211   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
    00212
    00213   ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00214   if (CmdFailed(ret)) return CMD_ERROR;
    00215   if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
    00216     return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
    00217   }
    00218
    00219   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
    00220       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
    00221       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
    00222     return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
    00223   }
    00224
    00225   if (flags & DC_EXEC) {
    00226     MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
    00227     MarkTileDirtyByTile(tile);
    00228     MarkTileDirtyByTile(tile - delta);
    00229     MarkTileDirtyByTile(tile + delta);
    00230     MarkCanalsAndRiversAroundDirty(tile - delta);
    00231     MarkCanalsAndRiversAroundDirty(tile + delta);
    00232   }
    00233
    00234   return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 22 >> 3);
    00235 }
    00236
    00237 static CommandCost RemoveShiplift(TileIndex tile, DoCommandFlag flags)
    00238 {
    00239   TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
    00240
    00241   if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR;
    00242
    00243   /* make sure no vehicle is on the tile. */
    00244   if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta))
    00245     return CMD_ERROR;
    00246
    00247   if (flags & DC_EXEC) {
    00248     DoClearSquare(tile);
    00249     MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
    00250     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
    00251     MarkTileDirtyByTile(tile - delta);
    00252     MarkTileDirtyByTile(tile + delta);
    00253     MarkCanalsAndRiversAroundDirty(tile - delta);
    00254     MarkCanalsAndRiversAroundDirty(tile + delta);
    00255   }
    00256
    00257   return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2);
    00258 }
    00259
    00266 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00267 {
    00268   DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
    00269   if (dir == INVALID_DIAGDIR) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
    00270
    00271   /* Disallow building of locks on river rapids */
    00272   if (IsWaterTile(tile)) return_cmd_error(STR_0239_SITE_UNSUITABLE);
    00273
    00274   return DoBuildShiplift(tile, dir, flags);
    00275 }
    00276
    00283 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00284 {
    00285   CommandCost cost(EXPENSES_CONSTRUCTION);
    00286   int size_x, size_y;
    00287   int x;
    00288   int y;
    00289   int sx, sy;
    00290
    00291   if (p1 >= MapSize()) return CMD_ERROR;
    00292
    00293   /* Outside of the editor you can only build canals, not oceans */
    00294   if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
    00295
    00296   x = TileX(tile);
    00297   y = TileY(tile);
    00298   sx = TileX(p1);
    00299   sy = TileY(p1);
    00300
    00301   if (x < sx) Swap(x, sx);
    00302   if (y < sy) Swap(y, sy);
    00303   size_x = (x - sx) + 1;
    00304   size_y = (y - sy) + 1;
    00305
    00306   /* Outside the editor you can only drag canals, and not areas */
    00307   if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
    00308
    00309   BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
    00310     CommandCost ret;
    00311
    00312     Slope slope = GetTileSlope(tile, NULL);
    00313     if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
    00314       return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
    00315     }
    00316
    00317     /* can't make water of water! */
    00318     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
    00319
    00320     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00321     if (CmdFailed(ret)) return ret;
    00322     cost.AddCost(ret);
    00323
    00324     if (flags & DC_EXEC) {
    00325       if (TileHeight(tile) == 0 && p2 == 1) {
    00326         MakeWater(tile);
    00327       } else if (p2 == 2) {
    00328         MakeRiver(tile, Random());
    00329       } else {
    00330         MakeCanal(tile, _current_company, Random());
    00331       }
    00332       MarkTileDirtyByTile(tile);
    00333       MarkCanalsAndRiversAroundDirty(tile);
    00334     }
    00335
    00336     cost.AddCost(_price.clear_water);
    00337   } END_TILE_LOOP(tile, size_x, size_y, 0);
    00338
    00339   if (cost.GetCost() == 0) {
    00340     return_cmd_error(STR_1007_ALREADY_BUILT);
    00341   } else {
    00342     return cost;
    00343   }
    00344 }
    00345
    00346 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
    00347 {
    00348   switch (GetWaterTileType(tile)) {
    00349     case WATER_TILE_CLEAR:
    00350       if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
    00351
    00352       /* Make sure freeform edges are allowed or it's not an edge tile. */
    00353       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
    00354           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
    00355         return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
    00356       }
    00357
    00358       /* Make sure no vehicle is on the tile */
    00359       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00360
    00361       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
    00362
    00363       if (flags & DC_EXEC) {
    00364         DoClearSquare(tile);
    00365         MarkCanalsAndRiversAroundDirty(tile);
    00366       }
    00367       return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
    00368
    00369     case WATER_TILE_COAST: {
    00370       Slope slope = GetTileSlope(tile, NULL);
    00371
    00372       /* Make sure no vehicle is on the tile */
    00373       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00374
    00375       if (flags & DC_EXEC) {
    00376         DoClearSquare(tile);
    00377         MarkCanalsAndRiversAroundDirty(tile);
    00378       }
    00379       if (IsSlopeWithOneCornerRaised(slope)) {
    00380         return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
    00381       } else {
    00382         return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_roughland);
    00383       }
    00384     }
    00385
    00386     case WATER_TILE_LOCK: {
    00387       static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
    00388         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
    00389         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
    00390         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
    00391       };
    00392
    00393       if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
    00394       if (_current_company == OWNER_WATER) return CMD_ERROR;
    00395       /* move to the middle tile.. */
    00396       return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
    00397     }
    00398
    00399     case WATER_TILE_DEPOT:
    00400       if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
    00401       return RemoveShipDepot(tile, flags);
    00402
    00403     default:
    00404       NOT_REACHED();
    00405   }
    00406 }
    00407
    00416 static bool IsWateredTile(TileIndex tile, Direction from)
    00417 {
    00418   switch (GetTileType(tile)) {
    00419     case MP_WATER:
    00420       switch (GetWaterTileType(tile)) {
    00421         default: NOT_REACHED();
    00422         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
    00423         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
    00424
    00425         case WATER_TILE_COAST:
    00426           switch (GetTileSlope(tile, NULL)) {
    00427             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00428             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00429             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00430             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00431             default: return false;
    00432           }
    00433       }
    00434
    00435     case MP_RAILWAY:
    00436       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00437         assert(IsPlainRailTile(tile));
    00438         switch (GetTileSlope(tile, NULL)) {
    00439           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
    00440           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
    00441           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
    00442           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
    00443           default: return false;
    00444         }
    00445       }
    00446       return false;
    00447
    00448     case MP_STATION:
    00449       if (IsOilRig(tile)) {
    00450         /* Do not draw waterborders inside of industries.
    00451          * Note: There is no easy way to detect the industry of an oilrig tile. */
    00452         TileIndex src_tile = tile + TileOffsByDir(from);
    00453         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00454             (IsTileType(src_tile, MP_INDUSTRY))) return true;
    00455
    00456         return GetWaterClass(tile) != WATER_CLASS_INVALID;
    00457       }
    00458       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
    00459
    00460     case MP_INDUSTRY: {
    00461       /* Do not draw waterborders inside of industries.
    00462        * Note: There is no easy way to detect the industry of an oilrig tile. */
    00463       TileIndex src_tile = tile + TileOffsByDir(from);
    00464       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
    00465           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
    00466
    00467       return IsIndustryTileOnWater(tile);
    00468     }
    00469
    00470     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
    00471
    00472     default:          return false;
    00473   }
    00474 }
    00475
    00476 static void DrawWaterEdges(SpriteID base, TileIndex tile)
    00477 {
    00478   uint wa;
    00479
    00480   /* determine the edges around with water. */
    00481   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
    00482   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
    00483   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
    00484   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
    00485
    00486   if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
    00487   if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
    00488   if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
    00489   if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
    00490
    00491   /* right corner */
    00492   switch (wa & 0x03) {
    00493     case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
    00494     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
    00495   }
    00496
    00497   /* bottom corner */
    00498   switch (wa & 0x06) {
    00499     case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
    00500     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
    00501   }
    00502
    00503   /* left corner */
    00504   switch (wa & 0x0C) {
    00505     case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
    00506     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
    00507   }
    00508
    00509   /* upper corner */
    00510   switch (wa & 0x09) {
    00511     case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
    00512     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
    00513   }
    00514 }
    00515
    00517 static void DrawSeaWater(TileIndex tile)
    00518 {
    00519   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00520 }
    00521
    00523 static void DrawCanalWater(TileIndex tile)
    00524 {
    00525   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
    00526
    00527   /* Test for custom graphics, else use the default */
    00528   SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
    00529   if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
    00530
    00531   DrawWaterEdges(dikes_base, tile);
    00532 }
    00533
    00534 struct LocksDrawTileStruct {
    00535   int8 delta_x, delta_y, delta_z;
    00536   byte width, height, depth;
    00537   SpriteID image;
    00538 };
    00539
    00540 #include "table/water_land.h"
    00541
    00542 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
    00543   SpriteID palette, uint base, bool draw_ground
    00544 )
    00545 {
    00546   SpriteID image;
    00547   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
    00548   SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
    00549
    00550   /* If no custom graphics, use defaults */
    00551   if (water_base == 0) water_base = SPR_CANALS_BASE;
    00552   if (locks_base == 0) {
    00553     locks_base = SPR_SHIPLIFT_BASE;
    00554   } else {
    00555     /* If using custom graphics, ignore the variation on height */
    00556     base = 0;
    00557   }
    00558
    00559   image = wdts++->image;
    00560   if (image < 4) image += water_base;
    00561   if (draw_ground) DrawGroundSprite(image, PAL_NONE);
    00562
    00563   /* End now if buildings are invisible */
    00564   if (IsInvisibilitySet(TO_BUILDINGS)) return;
    00565
    00566   for (; wdts->delta_x != 0x80; wdts++) {
    00567     AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
    00568       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
    00569       wdts->size_x, wdts->size_y,
    00570       wdts->size_z, ti->z + wdts->delta_z,
    00571       IsTransparencySet(TO_BUILDINGS));
    00572   }
    00573 }
    00574
    00575 static void DrawRiverWater(const TileInfo *ti)
    00576 {
    00577   SpriteID image = SPR_FLAT_WATER_TILE;
    00578   SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
    00579
    00580   if (ti->tileh != SLOPE_FLAT) {
    00581     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
    00582     if (image == 0) {
    00583       switch (ti->tileh) {
    00584         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
    00585         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
    00586         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
    00587         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
    00588         default:       image = SPR_FLAT_WATER_TILE;    break;
    00589       }
    00590     } else {
    00591       switch (ti->tileh) {
    00592         default: NOT_REACHED();
    00593         case SLOPE_SE:             edges_base += 12; break;
    00594         case SLOPE_NE: image += 1; edges_base += 24; break;
    00595         case SLOPE_SW: image += 2; edges_base += 36; break;
    00596         case SLOPE_NW: image += 3; edges_base += 48; break;
    00597       }
    00598     }
    00599   }
    00600
    00601   DrawGroundSprite(image, PAL_NONE);
    00602
    00603   /* Draw river edges if available. */
    00604   if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
    00605 }
    00606
    00607 void DrawShoreTile(Slope tileh)
    00608 {
    00609   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
    00610    * This allows to calculate the proper sprite to display for this Slope */
    00611   static const byte tileh_to_shoresprite[32] = {
    00612     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
    00613     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
    00614   };
    00615
    00616   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
    00617   assert(tileh != SLOPE_FLAT);     // Shore is never flat
    00618
    00619   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
    00620
    00621   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
    00622 }
    00623
    00624 void DrawWaterClassGround(const TileInfo *ti) {
    00625   switch (GetWaterClass(ti->tile)) {
    00626     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
    00627     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
    00628     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
    00629     default: NOT_REACHED();
    00630   }
    00631 }
    00632
    00633 static void DrawTile_Water(TileInfo *ti)
    00634 {
    00635   switch (GetWaterTileType(ti->tile)) {
    00636     case WATER_TILE_CLEAR:
    00637       DrawWaterClassGround(ti);
    00638       DrawBridgeMiddle(ti);
    00639       break;
    00640
    00641     case WATER_TILE_COAST: {
    00642       DrawShoreTile(ti->tileh);
    00643       DrawBridgeMiddle(ti);
    00644     } break;
    00645
    00646     case WATER_TILE_LOCK: {
    00647       const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
    00648       DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
    00649     } break;
    00650
    00651     case WATER_TILE_DEPOT:
    00652       DrawWaterClassGround(ti);
    00653       DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
    00654       break;
    00655   }
    00656 }
    00657
    00658 void DrawShipDepotSprite(int x, int y, int image)
    00659 {
    00660   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
    00661
    00662   DrawSprite(wdts++->image, PAL_NONE, x, y);
    00663
    00664   for (; wdts->delta_x != 0x80; wdts++) {
    00665     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
    00666     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
    00667   }
    00668 }
    00669
    00670
    00671 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
    00672 {
    00673   uint z;
    00674   Slope tileh = GetTileSlope(tile, &z);
    00675
    00676   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00677 }
    00678
    00679 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
    00680 {
    00681   return FOUNDATION_NONE;
    00682 }
    00683
    00684 static void GetAcceptedCargo_Water(TileIndex tile, AcceptedCargo ac)
    00685 {
    00686   /* not used */
    00687 }
    00688
    00689 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
    00690 {
    00691   switch (GetWaterTileType(tile)) {
    00692     case WATER_TILE_CLEAR:
    00693       switch (GetWaterClass(tile)) {
    00694         case WATER_CLASS_SEA:   td->str = STR_3804_WATER;     break;
    00695         case WATER_CLASS_CANAL: td->str = STR_LANDINFO_CANAL; break;
    00696         case WATER_CLASS_RIVER: td->str = STR_LANDINFO_RIVER; break;
    00697         default: assert(0); break;
    00698       }
    00699       break;
    00700     case WATER_TILE_COAST: td->str = STR_3805_COAST_OR_RIVERBANK; break;
    00701     case WATER_TILE_LOCK : td->str = STR_LANDINFO_LOCK;           break;
    00702     case WATER_TILE_DEPOT: td->str = STR_3806_SHIP_DEPOT;         break;
    00703     default: assert(0); break;
    00704   }
    00705
    00706   td->owner[0] = GetTileOwner(tile);
    00707 }
    00708
    00709 static void AnimateTile_Water(TileIndex tile)
    00710 {
    00711   /* not used */
    00712 }
    00713
    00714 static void FloodVehicle(Vehicle *v);
    00715
    00722 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
    00723 {
    00724   byte z = *(byte*)data;
    00725
    00726   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00727   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
    00728
    00729   FloodVehicle(v);
    00730   return NULL;
    00731 }
    00732
    00738 static void FloodVehicles(TileIndex tile)
    00739 {
    00740   byte z = 0;
    00741
    00742   if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
    00743     const Station *st = GetStationByTile(tile);
    00744     const AirportFTAClass *airport = st->Airport();
    00745     z = 1 + airport->delta_z;
    00746     for (uint x = 0; x < airport->size_x; x++) {
    00747       for (uint y = 0; y < airport->size_y; y++) {
    00748         tile = TILE_ADDXY(st->airport_tile, x, y);
    00749         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00750       }
    00751     }
    00752
    00753     /* No vehicle could be flooded on this airport anymore */
    00754     return;
    00755   }
    00756
    00757   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
    00758   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
    00759     const Station *st = GetStationByTile(tile);
    00760
    00761     BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
    00762       if (st->TileBelongsToRailStation(t)) {
    00763         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00764       }
    00765     END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
    00766
    00767     return;
    00768   }
    00769
    00770   if (!IsBridgeTile(tile)) {
    00771     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00772     return;
    00773   }
    00774
    00775   TileIndex end = GetOtherBridgeEnd(tile);
    00776   z = GetBridgeHeight(tile);
    00777
    00778   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
    00779   FindVehicleOnPos(end, &z, &FloodVehicleProc);
    00780 }
    00781
    00782 static void FloodVehicle(Vehicle *v)
    00783 {
    00784   if (!(v->vehstatus & VS_CRASHED)) {
    00785     uint16 pass = 0;
    00786
    00787     if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_AIRCRAFT) {
    00788       if (v->type == VEH_AIRCRAFT) {
    00789         /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
    00790          * because that's always the shadow. Except for the heliport, because
    00791          * that station has a big z_offset for the aircraft. */
    00792         if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
    00793         const Station *st = GetStationByTile(v->tile);
    00794         const AirportFTAClass *airport = st->Airport();
    00795
    00796         if (v->z_pos != airport->delta_z + 1) return;
    00797       }
    00798
    00799       if (v->type != VEH_AIRCRAFT) v = v->First();
    00800
    00801       /* crash all wagons, and count passengers */
    00802       for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00803         if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
    00804         u->vehstatus |= VS_CRASHED;
    00805         MarkSingleVehicleDirty(u);
    00806       }
    00807
    00808       switch (v->type) {
    00809         default: NOT_REACHED();
    00810         case VEH_TRAIN:
    00811           if (IsFrontEngine(v)) {
    00812             pass += 4; // driver
    00813             /* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
    00814              * In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
    00815             v->vehstatus &= ~VS_CRASHED;
    00816             FreeTrainTrackReservation(v);
    00817             v->vehstatus |= VS_CRASHED;
    00818           }
    00819           v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
    00820           InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
    00821           break;
    00822
    00823         case VEH_ROAD:
    00824           if (IsRoadVehFront(v)) pass += 1; // driver
    00825           v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
    00826           InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
    00827           break;
    00828
    00829         case VEH_AIRCRAFT:
    00830           pass += 2; // driver
    00831           v->u.air.crashed_counter = 9000; // max 10000, disappear pretty fast
    00832           InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
    00833           break;
    00834       }
    00835     } else {
    00836       return;
    00837     }
    00838
    00839     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    00840     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    00841
    00842     AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
    00843     SetDParam(0, pass);
    00844     AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
    00845       NS_ACCIDENT_VEHICLE,
    00846       v->index,
    00847       0);
    00848     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    00849     SndPlayVehicleFx(SND_12_EXPLOSION, v);
    00850   }
    00851 }
    00852
    00858 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
    00859 {
    00860   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
    00861    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
    00862    * FLOOD_PASSIVE: (not used)
    00863    * FLOOD_NONE:    canals, rivers, everything else
    00864    */
    00865   switch (GetTileType(tile)) {
    00866     case MP_WATER:
    00867       if (IsCoast(tile)) {
    00868         Slope tileh = GetTileSlope(tile, NULL);
    00869         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00870       } else {
    00871         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
    00872       }
    00873
    00874     case MP_RAILWAY:
    00875       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
    00876         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
    00877       }
    00878       return FLOOD_NONE;
    00879
    00880     case MP_TREES:
    00881       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
    00882
    00883     case MP_STATION:
    00884       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
    00885         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
    00886       }
    00887       return FLOOD_NONE;
    00888
    00889     case MP_INDUSTRY:
    00890       return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
    00891
    00892     default:
    00893       return FLOOD_NONE;
    00894   }
    00895 }
    00896
    00900 void DoFloodTile(TileIndex target)
    00901 {
    00902   assert(!IsTileType(target, MP_WATER));
    00903
    00904   bool flooded = false; // Will be set to true if something is changed.
    00905
    00906   _current_company = OWNER_WATER;
    00907
    00908   Slope tileh = GetTileSlope(target, NULL);
    00909   if (tileh != SLOPE_FLAT) {
    00910     /* make coast.. */
    00911     switch (GetTileType(target)) {
    00912       case MP_RAILWAY: {
    00913         if (!IsPlainRailTile(target)) break;
    00914         FloodVehicles(target);
    00915         flooded = FloodHalftile(target);
    00916         break;
    00917       }
    00918
    00919       case MP_TREES:
    00920         if (!IsSlopeWithOneCornerRaised(tileh)) {
    00921           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
    00922           MarkTileDirtyByTile(target);
    00923           flooded = true;
    00924           break;
    00925         }
    00926       /* FALL THROUGH */
    00927       case MP_CLEAR:
    00928         if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00929           MakeShore(target);
    00930           MarkTileDirtyByTile(target);
    00931           flooded = true;
    00932         }
    00933         break;
    00934
    00935       default:
    00936         break;
    00937     }
    00938   } else {
    00939     /* Flood vehicles */
    00940     FloodVehicles(target);
    00941
    00942     /* flood flat tile */
    00943     if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00944       MakeWater(target);
    00945       MarkTileDirtyByTile(target);
    00946       flooded = true;
    00947     }
    00948   }
    00949
    00950   if (flooded) {
    00951     /* Mark surrounding canal tiles dirty too to avoid glitches */
    00952     MarkCanalsAndRiversAroundDirty(target);
    00953
    00954     /* update signals if needed */
    00955     UpdateSignalsInBuffer();
    00956   }
    00957
    00958   _current_company = OWNER_NONE;
    00959 }
    00960
    00964 static void DoDryUp(TileIndex tile)
    00965 {
    00966   _current_company = OWNER_WATER;
    00967
    00968   switch (GetTileType(tile)) {
    00969     case MP_RAILWAY:
    00970       assert(IsPlainRailTile(tile));
    00971       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
    00972
    00973       RailGroundType new_ground;
    00974       switch (GetTrackBits(tile)) {
    00975         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
    00976         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
    00977         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
    00978         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
    00979         default: NOT_REACHED();
    00980       }
    00981       SetRailGroundType(tile, new_ground);
    00982       MarkTileDirtyByTile(tile);
    00983       break;
    00984
    00985     case MP_TREES:
    00986       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
    00987       MarkTileDirtyByTile(tile);
    00988       break;
    00989
    00990     case MP_WATER:
    00991       assert(IsCoast(tile));
    00992
    00993       if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
    00994         MakeClear(tile, CLEAR_GRASS, 3);
    00995         MarkTileDirtyByTile(tile);
    00996       }
    00997       break;
    00998
    00999     default: NOT_REACHED();
    01000   }
    01001
    01002   _current_company = OWNER_NONE;
    01003 }
    01004
    01011 void TileLoop_Water(TileIndex tile)
    01012 {
    01013   switch (GetFloodingBehaviour(tile)) {
    01014     case FLOOD_ACTIVE:
    01015       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
    01016         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
    01017         if (dest == INVALID_TILE) continue;
    01018         /* do not try to flood water tiles - increases performance a lot */
    01019         if (IsTileType(dest, MP_WATER)) continue;
    01020
    01021         uint z_dest;
    01022         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01023         if (z_dest > 0) continue;
    01024
    01025         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
    01026
    01027         DoFloodTile(dest);
    01028       }
    01029       break;
    01030
    01031     case FLOOD_DRYUP: {
    01032       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
    01033       uint check_dirs = _flood_from_dirs[slope_here];
    01034       uint dir;
    01035       FOR_EACH_SET_BIT(dir, check_dirs) {
    01036         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
    01037         if (dest == INVALID_TILE) continue;
    01038
    01039         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
    01040         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
    01041       }
    01042       DoDryUp(tile);
    01043       break;
    01044     }
    01045
    01046     default: return;
    01047   }
    01048 }
    01049
    01050 void ConvertGroundTilesIntoWaterTiles()
    01051 {
    01052   TileIndex tile;
    01053   uint z;
    01054   Slope slope;
    01055
    01056   for (tile = 0; tile < MapSize(); ++tile) {
    01057     slope = GetTileSlope(tile, &z);
    01058     if (IsTileType(tile, MP_CLEAR) && z == 0) {
    01059       /* Make both water for tiles at level 0
    01060        * and make shore, as that looks much better
    01061        * during the generation. */
    01062       switch (slope) {
    01063         case SLOPE_FLAT:
    01064           MakeWater(tile);
    01065           break;
    01066
    01067         case SLOPE_N:
    01068         case SLOPE_E:
    01069         case SLOPE_S:
    01070         case SLOPE_W:
    01071           MakeShore(tile);
    01072           break;
    01073
    01074         default:
    01075           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
    01076           uint dir;
    01077           FOR_EACH_SET_BIT(dir, check_dirs) {
    01078             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
    01079             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
    01080             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
    01081               MakeShore(tile);
    01082               break;
    01083             }
    01084           }
    01085           break;
    01086       }
    01087     }
    01088   }
    01089 }
    01090
    01091 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    01092 {
    01093   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
    01094
    01095   TrackBits ts;
    01096
    01097   if (mode != TRANSPORT_WATER) return 0;
    01098
    01099   switch (GetWaterTileType(tile)) {
    01100     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
    01101     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
    01102     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
    01103     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
    01104     default: return 0;
    01105   }
    01106   if (TileX(tile) == 0) {
    01107     /* NE border: remove tracks that connects NE tile edge */
    01108     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
    01109   }
    01110   if (TileY(tile) == 0) {
    01111     /* NW border: remove tracks that connects NW tile edge */
    01112     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
    01113   }
    01114   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
    01115 }
    01116
    01117 static bool ClickTile_Water(TileIndex tile)
    01118 {
    01119   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
    01120     TileIndex tile2 = GetOtherShipDepotTile(tile);
    01121
    01122     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
    01123     return true;
    01124   }
    01125   return false;
    01126 }
    01127
    01128 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
    01129 {
    01130   if (!IsTileOwner(tile, old_owner)) return;
    01131
    01132   if (new_owner != INVALID_OWNER) {
    01133     SetTileOwner(tile, new_owner);
    01134     return;
    01135   }
    01136
    01137   /* Remove depot */
    01138   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
    01139
    01140   /* Set owner of canals and locks ... and also canal under dock there was before.
    01141    * Check if the new owner after removing depot isn't OWNER_WATER. */
    01142   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
    01143 }
    01144
    01145 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
    01146 {
    01147   return VETSB_CONTINUE;
    01148 }
    01149
    01150 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
    01151 {
    01152   /* Canals can't be terraformed */
    01153   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_MUST_DEMOLISH_CANAL_FIRST);
    01154
    01155   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    01156 }
    01157
    01158
    01159 extern const TileTypeProcs _tile_type_water_procs = {
    01160   DrawTile_Water,           /* draw_tile_proc */
    01161   GetSlopeZ_Water,          /* get_slope_z_proc */
    01162   ClearTile_Water,          /* clear_tile_proc */
    01163   GetAcceptedCargo_Water,   /* get_accepted_cargo_proc */
    01164   GetTileDesc_Water,        /* get_tile_desc_proc */
    01165   GetTileTrackStatus_Water, /* get_tile_track_status_proc */
    01166   ClickTile_Water,          /* click_tile_proc */
    01167   AnimateTile_Water,        /* animate_tile_proc */
    01168   TileLoop_Water,           /* tile_loop_clear */
    01169   ChangeTileOwner_Water,    /* change_tile_owner_clear */
    01170   NULL,                     /* get_produced_cargo_proc */
    01171   VehicleEnter_Water,       /* vehicle_enter_tile_proc */
    01172   GetFoundation_Water,      /* get_foundation_proc */
    01173   TerraformTile_Water,      /* terraform_tile_proc */
    01174 };