# water_cmd.cpp

Go to the documentation of this file.

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