water_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: water_cmd.cpp 15718 2009-03-15 00:32:18Z 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(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 };

Generated on Mon May 11 15:48:09 2009 for OpenTTD by  doxygen 1.5.6