water_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: water_cmd.cpp 17346 2009-09-01 13:16:53Z rubidium $ */
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(IsPlainRail(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 FloodVehicle(Vehicle *v);
00710 
00717 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00718 {
00719   byte z = *(byte*)data;
00720 
00721   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00722   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00723 
00724   FloodVehicle(v);
00725   return NULL;
00726 }
00727 
00733 static void FloodVehicles(TileIndex tile)
00734 {
00735   byte z = 0;
00736 
00737   if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
00738     const Station *st = GetStationByTile(tile);
00739     const AirportFTAClass *airport = st->Airport();
00740     z = 1 + airport->delta_z;
00741     for (uint x = 0; x < airport->size_x; x++) {
00742       for (uint y = 0; y < airport->size_y; y++) {
00743         tile = TILE_ADDXY(st->airport_tile, x, y);
00744         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00745       }
00746     }
00747 
00748     /* No vehicle could be flooded on this airport anymore */
00749     return;
00750   }
00751 
00752   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
00753   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00754     const Station *st = GetStationByTile(tile);
00755 
00756     BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00757       if (st->TileBelongsToRailStation(t)) {
00758         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00759       }
00760     END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00761 
00762     return;
00763   }
00764 
00765   if (!IsBridgeTile(tile)) {
00766     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00767     return;
00768   }
00769 
00770   TileIndex end = GetOtherBridgeEnd(tile);
00771   z = GetBridgeHeight(tile);
00772 
00773   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00774   FindVehicleOnPos(end, &z, &FloodVehicleProc);
00775 }
00776 
00777 static void FloodVehicle(Vehicle *v)
00778 {
00779   if (!(v->vehstatus & VS_CRASHED)) {
00780     uint16 pass = 0;
00781 
00782     if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_AIRCRAFT) {
00783       if (v->type == VEH_AIRCRAFT) {
00784         /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
00785          * because that's always the shadow. Except for the heliport, because
00786          * that station has a big z_offset for the aircraft. */
00787         if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00788         const Station *st = GetStationByTile(v->tile);
00789         const AirportFTAClass *airport = st->Airport();
00790 
00791         if (v->z_pos != airport->delta_z + 1) return;
00792       }
00793 
00794       if (v->type != VEH_AIRCRAFT) v = v->First();
00795 
00796       /* crash all wagons, and count passengers */
00797       for (Vehicle *u = v; u != NULL; u = u->Next()) {
00798         if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
00799         u->vehstatus |= VS_CRASHED;
00800         MarkSingleVehicleDirty(u);
00801       }
00802 
00803       switch (v->type) {
00804         default: NOT_REACHED();
00805         case VEH_TRAIN:
00806           if (IsFrontEngine(v)) {
00807             pass += 4; // driver
00808             /* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
00809              * In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
00810             v->vehstatus &= ~VS_CRASHED;
00811             if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
00812             v->vehstatus |= VS_CRASHED;
00813           }
00814           v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
00815           InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
00816           break;
00817 
00818         case VEH_ROAD:
00819           if (IsRoadVehFront(v)) pass += 1; // driver
00820           v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
00821           InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
00822           break;
00823 
00824         case VEH_AIRCRAFT:
00825           pass += 2; // driver
00826           v->u.air.crashed_counter = 9000; // max 10000, disappear pretty fast
00827           InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
00828           break;
00829       }
00830     } else {
00831       return;
00832     }
00833 
00834     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00835     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
00836 
00837     AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00838     SetDParam(0, pass);
00839     AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
00840       NS_ACCIDENT_VEHICLE,
00841       v->index,
00842       0);
00843     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00844     SndPlayVehicleFx(SND_12_EXPLOSION, v);
00845   }
00846 }
00847 
00853 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00854 {
00855   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
00856    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
00857    * FLOOD_PASSIVE: (not used)
00858    * FLOOD_NONE:    canals, rivers, everything else
00859    */
00860   switch (GetTileType(tile)) {
00861     case MP_WATER:
00862       if (IsCoast(tile)) {
00863         Slope tileh = GetTileSlope(tile, NULL);
00864         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00865       } else {
00866         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00867       }
00868 
00869     case MP_RAILWAY:
00870       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00871         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00872       }
00873       return FLOOD_NONE;
00874 
00875     case MP_TREES:
00876       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00877 
00878     case MP_STATION:
00879       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
00880         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00881       }
00882       return FLOOD_NONE;
00883 
00884     case MP_INDUSTRY:
00885       return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
00886 
00887     default:
00888       return FLOOD_NONE;
00889   }
00890 }
00891 
00895 void DoFloodTile(TileIndex target)
00896 {
00897   assert(!IsTileType(target, MP_WATER));
00898 
00899   bool flooded = false; // Will be set to true if something is changed.
00900 
00901   _current_company = OWNER_WATER;
00902 
00903   Slope tileh = GetTileSlope(target, NULL);
00904   if (tileh != SLOPE_FLAT) {
00905     /* make coast.. */
00906     switch (GetTileType(target)) {
00907       case MP_RAILWAY: {
00908         if (!IsPlainRail(target)) break;
00909         FloodVehicles(target);
00910         flooded = FloodHalftile(target);
00911         break;
00912       }
00913 
00914       case MP_TREES:
00915         if (!IsSlopeWithOneCornerRaised(tileh)) {
00916           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00917           MarkTileDirtyByTile(target);
00918           flooded = true;
00919           break;
00920         }
00921       /* FALL THROUGH */
00922       case MP_CLEAR:
00923         if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00924           MakeShore(target);
00925           MarkTileDirtyByTile(target);
00926           flooded = true;
00927         }
00928         break;
00929 
00930       default:
00931         break;
00932     }
00933   } else {
00934     /* Flood vehicles */
00935     FloodVehicles(target);
00936 
00937     /* flood flat tile */
00938     if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00939       MakeWater(target);
00940       MarkTileDirtyByTile(target);
00941       flooded = true;
00942     }
00943   }
00944 
00945   if (flooded) {
00946     /* Mark surrounding canal tiles dirty too to avoid glitches */
00947     MarkCanalsAndRiversAroundDirty(target);
00948 
00949     /* update signals if needed */
00950     UpdateSignalsInBuffer();
00951   }
00952 
00953   _current_company = OWNER_NONE;
00954 }
00955 
00959 static void DoDryUp(TileIndex tile)
00960 {
00961   _current_company = OWNER_WATER;
00962 
00963   switch (GetTileType(tile)) {
00964     case MP_RAILWAY:
00965       assert(IsPlainRail(tile));
00966       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00967 
00968       RailGroundType new_ground;
00969       switch (GetTrackBits(tile)) {
00970         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00971         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00972         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
00973         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
00974         default: NOT_REACHED();
00975       }
00976       SetRailGroundType(tile, new_ground);
00977       MarkTileDirtyByTile(tile);
00978       break;
00979 
00980     case MP_TREES:
00981       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
00982       MarkTileDirtyByTile(tile);
00983       break;
00984 
00985     case MP_WATER:
00986       assert(IsCoast(tile));
00987 
00988       if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00989         MakeClear(tile, CLEAR_GRASS, 3);
00990         MarkTileDirtyByTile(tile);
00991       }
00992       break;
00993 
00994     default: NOT_REACHED();
00995   }
00996 
00997   _current_company = OWNER_NONE;
00998 }
00999 
01006 void TileLoop_Water(TileIndex tile)
01007 {
01008   switch (GetFloodingBehaviour(tile)) {
01009     case FLOOD_ACTIVE:
01010       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01011         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
01012         if (dest == INVALID_TILE) continue;
01013         /* do not try to flood water tiles - increases performance a lot */
01014         if (IsTileType(dest, MP_WATER)) continue;
01015 
01016         uint z_dest;
01017         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01018         if (z_dest > 0) continue;
01019 
01020         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01021 
01022         DoFloodTile(dest);
01023       }
01024       break;
01025 
01026     case FLOOD_DRYUP: {
01027       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01028       uint check_dirs = _flood_from_dirs[slope_here];
01029       uint dir;
01030       FOR_EACH_SET_BIT(dir, check_dirs) {
01031         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
01032         if (dest == INVALID_TILE) continue;
01033 
01034         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01035         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01036       }
01037       DoDryUp(tile);
01038       break;
01039     }
01040 
01041     default: return;
01042   }
01043 }
01044 
01045 void ConvertGroundTilesIntoWaterTiles()
01046 {
01047   TileIndex tile;
01048   uint z;
01049   Slope slope;
01050 
01051   for (tile = 0; tile < MapSize(); ++tile) {
01052     slope = GetTileSlope(tile, &z);
01053     if (IsTileType(tile, MP_CLEAR) && z == 0) {
01054       /* Make both water for tiles at level 0
01055        * and make shore, as that looks much better
01056        * during the generation. */
01057       switch (slope) {
01058         case SLOPE_FLAT:
01059           MakeWater(tile);
01060           break;
01061 
01062         case SLOPE_N:
01063         case SLOPE_E:
01064         case SLOPE_S:
01065         case SLOPE_W:
01066           MakeShore(tile);
01067           break;
01068 
01069         default:
01070           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01071           uint dir;
01072           FOR_EACH_SET_BIT(dir, check_dirs) {
01073             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01074             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01075             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01076               MakeShore(tile);
01077               break;
01078             }
01079           }
01080           break;
01081       }
01082     }
01083   }
01084 }
01085 
01086 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01087 {
01088   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01089 
01090   TrackBits ts;
01091 
01092   if (mode != TRANSPORT_WATER) return 0;
01093 
01094   switch (GetWaterTileType(tile)) {
01095     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01096     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01097     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01098     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01099     default: return 0;
01100   }
01101   if (TileX(tile) == 0) {
01102     /* NE border: remove tracks that connects NE tile edge */
01103     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01104   }
01105   if (TileY(tile) == 0) {
01106     /* NW border: remove tracks that connects NW tile edge */
01107     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01108   }
01109   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01110 }
01111 
01112 static bool ClickTile_Water(TileIndex tile)
01113 {
01114   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01115     TileIndex tile2 = GetOtherShipDepotTile(tile);
01116 
01117     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01118     return true;
01119   }
01120   return false;
01121 }
01122 
01123 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01124 {
01125   if (!IsTileOwner(tile, old_owner)) return;
01126 
01127   if (new_owner != INVALID_OWNER) {
01128     SetTileOwner(tile, new_owner);
01129     return;
01130   }
01131 
01132   /* Remove depot */
01133   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01134 
01135   /* Set owner of canals and locks ... and also canal under dock there was before.
01136    * Check if the new owner after removing depot isn't OWNER_WATER. */
01137   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01138 }
01139 
01140 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01141 {
01142   return VETSB_CONTINUE;
01143 }
01144 
01145 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01146 {
01147   /* Canals can't be terraformed */
01148   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_MUST_DEMOLISH_CANAL_FIRST);
01149 
01150   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01151 }
01152 
01153 
01154 extern const TileTypeProcs _tile_type_water_procs = {
01155   DrawTile_Water,           // draw_tile_proc
01156   GetSlopeZ_Water,          // get_slope_z_proc
01157   ClearTile_Water,          // clear_tile_proc
01158   GetAcceptedCargo_Water,   // get_accepted_cargo_proc
01159   GetTileDesc_Water,        // get_tile_desc_proc
01160   GetTileTrackStatus_Water, // get_tile_track_status_proc
01161   ClickTile_Water,          // click_tile_proc
01162   NULL,                     // animate_tile_proc
01163   TileLoop_Water,           // tile_loop_clear
01164   ChangeTileOwner_Water,    // change_tile_owner_clear
01165   NULL,                     // get_produced_cargo_proc
01166   VehicleEnter_Water,       // vehicle_enter_tile_proc
01167   GetFoundation_Water,      // get_foundation_proc
01168   TerraformTile_Water,      // terraform_tile_proc
01169 };

Generated on Mon Dec 14 21:00:05 2009 for OpenTTD by  doxygen 1.5.6