water_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: water_cmd.cpp 21290 2010-11-21 18:38:45Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "landscape.h"
00015 #include "viewport_func.h"
00016 #include "command_func.h"
00017 #include "town.h"
00018 #include "news_func.h"
00019 #include "depot_base.h"
00020 #include "depot_func.h"
00021 #include "water.h"
00022 #include "industry_map.h"
00023 #include "newgrf_canal.h"
00024 #include "strings_func.h"
00025 #include "functions.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 "effectvehicle_func.h"
00033 #include "tunnelbridge_map.h"
00034 #include "station_base.h"
00035 #include "ai/ai.hpp"
00036 #include "core/random_func.hpp"
00037 #include "core/backup_type.hpp"
00038 #include "date_func.h"
00039 
00040 #include "table/strings.h"
00041 
00045 static const uint8 _flood_from_dirs[] = {
00046   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
00047   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
00048   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
00049   (1 << DIR_NE),                                                 // SLOPE_SW
00050   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
00051   0,                                                             // SLOPE_EW
00052   (1 << DIR_NW),                                                 // SLOPE_SE
00053   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
00054   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
00055   (1 << DIR_SE),                                                 // SLOPE_NW
00056   0,                                                             // SLOPE_NS
00057   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
00058   (1 << DIR_SW),                                                 // SLOPE_NE
00059   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
00060   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
00061 };
00062 
00069 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00070 {
00071   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00072 }
00073 
00080 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00081 {
00082   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00083     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00084   }
00085 }
00086 
00087 
00097 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00098 {
00099   Axis axis = Extract<Axis, 0, 1>(p1);
00100 
00101   TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00102 
00103   if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
00104     return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
00105   }
00106 
00107   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00108     (MayHaveBridgeAbove(tile2) && IsBridgeAbove(tile2))) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00109 
00110   if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
00111     /* Prevent depots on rapids */
00112     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00113   }
00114 
00115   if (!Depot::CanAllocateItem()) return CMD_ERROR;
00116 
00117   WaterClass wc1 = GetWaterClass(tile);
00118   WaterClass wc2 = GetWaterClass(tile2);
00119   CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
00120 
00121   bool add_cost = !IsWaterTile(tile);
00122   CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00123   if (ret.Failed()) return ret;
00124   if (add_cost) {
00125     cost.AddCost(ret);
00126   }
00127   add_cost = !IsWaterTile(tile2);
00128   ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00129   if (ret.Failed()) return ret;
00130   if (add_cost) {
00131     cost.AddCost(ret);
00132   }
00133 
00134   if (flags & DC_EXEC) {
00135     Depot *depot = new Depot(tile);
00136     depot->build_date = _date;
00137 
00138     MakeShipDepot(tile,  _current_company, depot->index, DEPOT_NORTH, axis, wc1);
00139     MakeShipDepot(tile2, _current_company, depot->index, DEPOT_SOUTH, axis, wc2);
00140     MarkTileDirtyByTile(tile);
00141     MarkTileDirtyByTile(tile2);
00142     MakeDefaultName(depot);
00143   }
00144 
00145   return cost;
00146 }
00147 
00148 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00149 {
00150   WaterClass wc = GetWaterClass(tile);
00151 
00152   /* Autoslope might turn an originally canal or river tile into land */
00153   uint z;
00154   if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
00155 
00156   if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
00157 
00158   /* Zero map array and terminate animation */
00159   DoClearSquare(tile);
00160 
00161   /* Maybe change to water */
00162   switch (wc) {
00163     case WATER_CLASS_SEA:   MakeSea(tile);                break;
00164     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00165     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
00166     default: break;
00167   }
00168 
00169   MarkTileDirtyByTile(tile);
00170 }
00171 
00172 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
00173 {
00174   if (!IsShipDepot(tile)) return CMD_ERROR;
00175 
00176   CommandCost ret = CheckTileOwnership(tile);
00177   if (ret.Failed()) return ret;
00178 
00179   TileIndex tile2 = GetOtherShipDepotTile(tile);
00180 
00181   /* do not check for ship on tile when company goes bankrupt */
00182   if (!(flags & DC_BANKRUPT)) {
00183     CommandCost ret = EnsureNoVehicleOnGround(tile);
00184     if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
00185     if (ret.Failed()) return ret;
00186   }
00187 
00188   if (flags & DC_EXEC) {
00189     delete Depot::GetByTile(tile);
00190 
00191     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
00192     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00193   }
00194 
00195   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
00196 }
00197 
00205 static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
00206 {
00207   CommandCost cost(EXPENSES_CONSTRUCTION);
00208 
00209   /* middle tile */
00210   CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00211   if (ret.Failed()) return ret;
00212   cost.AddCost(ret);
00213 
00214   int delta = TileOffsByDiagDir(dir);
00215   /* lower tile */
00216   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00217 
00218   if (!IsWaterTile(tile - delta)) {
00219     ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00220     if (ret.Failed()) return ret;
00221     cost.AddCost(ret);
00222     cost.AddCost(_price[PR_CLEAR_WATER]);
00223   }
00224   if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
00225     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00226   }
00227 
00228   /* upper tile */
00229   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
00230 
00231   if (!IsWaterTile(tile + delta)) {
00232     ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00233     if (ret.Failed()) return ret;
00234     cost.AddCost(ret);
00235     cost.AddCost(_price[PR_CLEAR_WATER]);
00236   }
00237   if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
00238     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00239   }
00240 
00241   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00242       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00243       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00244     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00245   }
00246 
00247   if (flags & DC_EXEC) {
00248     MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
00249     MarkTileDirtyByTile(tile);
00250     MarkTileDirtyByTile(tile - delta);
00251     MarkTileDirtyByTile(tile + delta);
00252     MarkCanalsAndRiversAroundDirty(tile - delta);
00253     MarkCanalsAndRiversAroundDirty(tile + delta);
00254   }
00255   cost.AddCost(_price[PR_BUILD_LOCK]);
00256 
00257   return cost;
00258 }
00259 
00266 static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags)
00267 {
00268   if (GetTileOwner(tile) != OWNER_NONE) {
00269     CommandCost ret = CheckTileOwnership(tile);
00270     if (ret.Failed()) return ret;
00271   }
00272 
00273   TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
00274 
00275   /* make sure no vehicle is on the tile. */
00276   CommandCost ret = EnsureNoVehicleOnGround(tile);
00277   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
00278   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
00279   if (ret.Failed()) return ret;
00280 
00281   if (flags & DC_EXEC) {
00282     DoClearSquare(tile);
00283     MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
00284     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
00285     MarkCanalsAndRiversAroundDirty(tile - delta);
00286     MarkCanalsAndRiversAroundDirty(tile + delta);
00287   }
00288 
00289   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
00290 }
00291 
00301 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00302 {
00303   DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
00304   if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00305 
00306   /* Disallow building of locks on river rapids */
00307   if (IsWaterTile(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00308 
00309   return DoBuildLock(tile, dir, flags);
00310 }
00311 
00321 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00322 {
00323   WaterClass wc = Extract<WaterClass, 0, 2>(p2);
00324   if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
00325 
00326   /* Outside of the editor you can only build canals, not oceans */
00327   if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
00328 
00329   TileArea ta(tile, p1);
00330 
00331   /* Outside the editor you can only drag canals, and not areas */
00332   if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
00333 
00334   CommandCost cost(EXPENSES_CONSTRUCTION);
00335   TILE_AREA_LOOP(tile, ta) {
00336     CommandCost ret;
00337 
00338     Slope slope = GetTileSlope(tile, NULL);
00339     if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
00340       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00341     }
00342 
00343     /* can't make water of water! */
00344     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
00345 
00346     ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
00347     if (ret.Failed()) return ret;
00348     cost.AddCost(ret);
00349 
00350     if (flags & DC_EXEC) {
00351       switch (wc) {
00352         case WATER_CLASS_RIVER:
00353           MakeRiver(tile, Random());
00354           break;
00355 
00356         case WATER_CLASS_SEA:
00357           if (TileHeight(tile) == 0) {
00358             MakeSea(tile);
00359             break;
00360           }
00361           /* FALL THROUGH */
00362 
00363         default:
00364           MakeCanal(tile, _current_company, Random());
00365           break;
00366       }
00367       MarkTileDirtyByTile(tile);
00368       MarkCanalsAndRiversAroundDirty(tile);
00369     }
00370 
00371     cost.AddCost(_price[PR_BUILD_CANAL]);
00372   }
00373 
00374   if (cost.GetCost() == 0) {
00375     return_cmd_error(STR_ERROR_ALREADY_BUILT);
00376   } else {
00377     return cost;
00378   }
00379 }
00380 
00381 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00382 {
00383   switch (GetWaterTileType(tile)) {
00384     case WATER_TILE_CLEAR: {
00385       if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00386 
00387       Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
00388       /* Make sure freeform edges are allowed or it's not an edge tile. */
00389       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00390           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00391         return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00392       }
00393 
00394       /* Make sure no vehicle is on the tile */
00395       CommandCost ret = EnsureNoVehicleOnGround(tile);
00396       if (ret.Failed()) return ret;
00397 
00398       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE) {
00399         CommandCost ret = CheckTileOwnership(tile);
00400         if (ret.Failed()) return ret;
00401       }
00402 
00403       if (flags & DC_EXEC) {
00404         DoClearSquare(tile);
00405         MarkCanalsAndRiversAroundDirty(tile);
00406       }
00407 
00408       return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
00409     }
00410 
00411     case WATER_TILE_COAST: {
00412       Slope slope = GetTileSlope(tile, NULL);
00413 
00414       /* Make sure no vehicle is on the tile */
00415       CommandCost ret = EnsureNoVehicleOnGround(tile);
00416       if (ret.Failed()) return ret;
00417 
00418       if (flags & DC_EXEC) {
00419         DoClearSquare(tile);
00420         MarkCanalsAndRiversAroundDirty(tile);
00421       }
00422       if (IsSlopeWithOneCornerRaised(slope)) {
00423         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00424       } else {
00425         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00426       }
00427     }
00428 
00429     case WATER_TILE_LOCK: {
00430       static const TileIndexDiffC _lock_tomiddle_offs[] = {
00431         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
00432         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
00433         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
00434       };
00435 
00436       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00437       if (_current_company == OWNER_WATER) return CMD_ERROR;
00438       /* move to the middle tile.. */
00439       return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetSection(tile)]), flags);
00440     }
00441 
00442     case WATER_TILE_DEPOT:
00443       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00444       return RemoveShipDepot(tile, flags);
00445 
00446     default:
00447       NOT_REACHED();
00448   }
00449 }
00450 
00459 static bool IsWateredTile(TileIndex tile, Direction from)
00460 {
00461   switch (GetTileType(tile)) {
00462     case MP_WATER:
00463       switch (GetWaterTileType(tile)) {
00464         default: NOT_REACHED();
00465         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00466         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00467 
00468         case WATER_TILE_COAST:
00469           switch (GetTileSlope(tile, NULL)) {
00470             case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00471             case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00472             case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00473             case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00474             default: return false;
00475           }
00476       }
00477 
00478     case MP_RAILWAY:
00479       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00480         assert(IsPlainRail(tile));
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       return false;
00490 
00491     case MP_STATION:
00492       if (IsOilRig(tile)) {
00493         /* Do not draw waterborders inside of industries.
00494          * Note: There is no easy way to detect the industry of an oilrig tile. */
00495         TileIndex src_tile = tile + TileOffsByDir(from);
00496         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00497             (IsTileType(src_tile, MP_INDUSTRY))) return true;
00498 
00499         return IsTileOnWater(tile);
00500       }
00501       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00502 
00503     case MP_INDUSTRY: {
00504       /* Do not draw waterborders inside of industries.
00505        * Note: There is no easy way to detect the industry of an oilrig tile. */
00506       TileIndex src_tile = tile + TileOffsByDir(from);
00507       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00508           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00509 
00510       return IsTileOnWater(tile);
00511     }
00512 
00513     case MP_OBJECT: return IsTileOnWater(tile);
00514 
00515     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00516 
00517     default:          return false;
00518   }
00519 }
00520 
00528 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
00529 {
00530   if (base != SPR_FLAT_WATER_TILE) {
00531     /* Only call offset callback if the sprite is NewGRF-provided. */
00532     offset = GetCanalSpriteOffset(feature, tile, offset);
00533   }
00534   DrawGroundSprite(base + offset, PAL_NONE);
00535 }
00536 
00543 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
00544 {
00545   CanalFeature feature;
00546   SpriteID base = 0;
00547   if (canal) {
00548     feature = CF_DIKES;
00549     base = GetCanalSprite(CF_DIKES, tile);
00550     if (base == 0) base = SPR_CANAL_DIKES_BASE;
00551   } else {
00552     feature = CF_RIVER_EDGE;
00553     base = GetCanalSprite(CF_RIVER_EDGE, tile);
00554     if (base == 0) return; // Don't draw if no sprites provided.
00555   }
00556 
00557   uint wa;
00558 
00559   /* determine the edges around with water. */
00560   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
00561   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
00562   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
00563   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
00564 
00565   if (!(wa & 1)) DrawWaterSprite(base, offset,     feature, tile);
00566   if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
00567   if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
00568   if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
00569 
00570   /* right corner */
00571   switch (wa & 0x03) {
00572     case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
00573     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
00574   }
00575 
00576   /* bottom corner */
00577   switch (wa & 0x06) {
00578     case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
00579     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
00580   }
00581 
00582   /* left corner */
00583   switch (wa & 0x0C) {
00584     case  0: DrawWaterSprite(base, offset + 6, feature, tile); break;
00585     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
00586   }
00587 
00588   /* upper corner */
00589   switch (wa & 0x09) {
00590     case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
00591     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
00592   }
00593 }
00594 
00596 static void DrawSeaWater(TileIndex tile)
00597 {
00598   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00599 }
00600 
00602 static void DrawCanalWater(TileIndex tile)
00603 {
00604   SpriteID image = SPR_FLAT_WATER_TILE;
00605   if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00606     /* First water slope sprite is flat water. */
00607     image = GetCanalSprite(CF_WATERSLOPE, tile);
00608     if (image == 0) image = SPR_FLAT_WATER_TILE;
00609   }
00610   DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
00611 
00612   DrawWaterEdges(true, 0, tile);
00613 }
00614 
00615 struct LocksDrawTileStruct {
00616   int8 delta_x, delta_y, delta_z;
00617   byte width, height, depth;
00618   SpriteID image;
00619 };
00620 
00621 #include "table/water_land.h"
00622 
00632 static void DrawWaterTileStruct(const TileInfo *ti, const WaterDrawTileStruct *wdts, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
00633 {
00634   /* Don't draw if buildings are invisible. */
00635   if (IsInvisibilitySet(TO_BUILDINGS)) return;
00636 
00637   for (; wdts->delta_x != 0x80; wdts++) {
00638     uint tile_offs = offset + wdts->image;
00639     if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
00640     AddSortableSpriteToDraw(base + tile_offs, palette,
00641       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
00642       wdts->size_x, wdts->size_y,
00643       wdts->size_z, ti->z + wdts->delta_z,
00644       IsTransparencySet(TO_BUILDINGS));
00645   }
00646 }
00647 
00649 static void DrawWaterLock(const TileInfo *ti)
00650 {
00651   const WaterDrawTileStruct *wdts = _lock_display_seq[GetSection(ti->tile)];
00652 
00653   /* Draw ground sprite. */
00654   SpriteID image = wdts++->image;
00655 
00656   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00657   if (water_base == 0) {
00658     /* Use default sprites. */
00659     water_base = SPR_CANALS_BASE;
00660   } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00661     /* NewGRF supplies a flat sprite as first sprite. */
00662     if (image == SPR_FLAT_WATER_TILE) {
00663       image = water_base;
00664     } else {
00665       image++;
00666     }
00667   }
00668 
00669   if (image < 5) image += water_base;
00670   DrawGroundSprite(image, PAL_NONE);
00671 
00672   /* Draw structures. */
00673   uint     zoffs = 0;
00674   SpriteID base  = GetCanalSprite(CF_LOCKS, ti->tile);
00675 
00676   if (base == 0) {
00677     /* If no custom graphics, use defaults. */
00678     base = SPR_LOCK_BASE;
00679     zoffs = ti->z > wdts[3].delta_y ? 24 : 0;
00680   }
00681 
00682   DrawWaterTileStruct(ti, wdts, base, zoffs, PAL_NONE, CF_LOCKS);
00683 }
00684 
00686 static void DrawWaterDepot(const TileInfo *ti)
00687 {
00688   DrawWaterClassGround(ti);
00689   /* Skip first entry in _shipdepot_display_seq as this is the ground sprite. */
00690   DrawWaterTileStruct(ti, _shipdepot_display_seq[GetSection(ti->tile)] + 1, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
00691 }
00692 
00693 static void DrawRiverWater(const TileInfo *ti)
00694 {
00695   SpriteID image = SPR_FLAT_WATER_TILE;
00696   uint     offset = 0;
00697   uint     edges_offset = 0;
00698 
00699   if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00700     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00701     if (image == 0) {
00702       switch (ti->tileh) {
00703         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00704         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
00705         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
00706         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00707         default:       image = SPR_FLAT_WATER_TILE;    break;
00708       }
00709     } else {
00710       /* Flag bit 0 indicates that the first sprite is flat water. */
00711       offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
00712 
00713       switch (ti->tileh) {
00714         case SLOPE_SE:              edges_offset += 12; break;
00715         case SLOPE_NE: offset += 1; edges_offset += 24; break;
00716         case SLOPE_SW: offset += 2; edges_offset += 36; break;
00717         case SLOPE_NW: offset += 3; edges_offset += 48; break;
00718         default:       offset  = 0; break;
00719       }
00720 
00721       offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
00722     }
00723   }
00724 
00725   DrawGroundSprite(image + offset, PAL_NONE);
00726 
00727   /* Draw river edges if available. */
00728   DrawWaterEdges(false, edges_offset, ti->tile);
00729 }
00730 
00731 void DrawShoreTile(Slope tileh)
00732 {
00733   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
00734    * This allows to calculate the proper sprite to display for this Slope */
00735   static const byte tileh_to_shoresprite[32] = {
00736     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00737     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
00738   };
00739 
00740   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
00741   assert(tileh != SLOPE_FLAT);     // Shore is never flat
00742 
00743   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
00744 
00745   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00746 }
00747 
00748 void DrawWaterClassGround(const TileInfo *ti)
00749 {
00750   switch (GetWaterClass(ti->tile)) {
00751     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
00752     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00753     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00754     default: NOT_REACHED();
00755   }
00756 }
00757 
00758 static void DrawTile_Water(TileInfo *ti)
00759 {
00760   switch (GetWaterTileType(ti->tile)) {
00761     case WATER_TILE_CLEAR:
00762       DrawWaterClassGround(ti);
00763       DrawBridgeMiddle(ti);
00764       break;
00765 
00766     case WATER_TILE_COAST: {
00767       DrawShoreTile(ti->tileh);
00768       DrawBridgeMiddle(ti);
00769       break;
00770     }
00771 
00772     case WATER_TILE_LOCK:
00773       DrawWaterLock(ti);
00774       break;
00775 
00776     case WATER_TILE_DEPOT:
00777       DrawWaterDepot(ti);
00778       break;
00779   }
00780 }
00781 
00782 void DrawShipDepotSprite(int x, int y, int image)
00783 {
00784   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00785 
00786   DrawSprite(wdts++->image, PAL_NONE, x, y);
00787 
00788   for (; wdts->delta_x != 0x80; wdts++) {
00789     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00790     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
00791   }
00792 }
00793 
00794 
00795 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00796 {
00797   uint z;
00798   Slope tileh = GetTileSlope(tile, &z);
00799 
00800   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00801 }
00802 
00803 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00804 {
00805   return FOUNDATION_NONE;
00806 }
00807 
00808 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00809 {
00810   switch (GetWaterTileType(tile)) {
00811     case WATER_TILE_CLEAR:
00812       switch (GetWaterClass(tile)) {
00813         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00814         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00815         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00816         default: NOT_REACHED(); break;
00817       }
00818       break;
00819     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00820     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
00821     case WATER_TILE_DEPOT:
00822       td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
00823       td->build_date = Depot::GetByTile(tile)->build_date;
00824       break;
00825     default: NOT_REACHED(); break;
00826   }
00827 
00828   td->owner[0] = GetTileOwner(tile);
00829 }
00830 
00836 static void FloodVehicle(Vehicle *v)
00837 {
00838   uint pass = v->Crash(true);
00839 
00840   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00841   SetDParam(0, pass);
00842   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NS_ACCIDENT, v->index);
00843   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00844   SndPlayVehicleFx(SND_12_EXPLOSION, v);
00845 }
00846 
00853 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00854 {
00855   if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
00856 
00857   switch (v->type) {
00858     default: break;
00859 
00860     case VEH_AIRCRAFT: {
00861       if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
00862       if (v->subtype == AIR_SHADOW) break;
00863 
00864       /* We compare v->z_pos against delta_z + 1 because the shadow
00865        * is at delta_z and the actual aircraft at delta_z + 1. */
00866       const Station *st = Station::GetByTile(v->tile);
00867       const AirportFTAClass *airport = st->airport.GetFTA();
00868       if (v->z_pos != airport->delta_z + 1) break;
00869 
00870       FloodVehicle(v);
00871       break;
00872     }
00873 
00874     case VEH_TRAIN:
00875     case VEH_ROAD: {
00876       byte z = *(byte*)data;
00877       if (v->z_pos > z) break;
00878       FloodVehicle(v->First());
00879       break;
00880     }
00881   }
00882 
00883   return NULL;
00884 }
00885 
00891 static void FloodVehicles(TileIndex tile)
00892 {
00893   byte z = 0;
00894 
00895   if (IsAirportTile(tile)) {
00896     const Station *st = Station::GetByTile(tile);
00897     TILE_AREA_LOOP(tile, st->airport) {
00898       if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00899     }
00900 
00901     /* No vehicle could be flooded on this airport anymore */
00902     return;
00903   }
00904 
00905   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
00906   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00907     const Station *st = Station::GetByTile(tile);
00908 
00909     TILE_AREA_LOOP(t, st->train_station) {
00910       if (st->TileBelongsToRailStation(t)) {
00911         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00912       }
00913     }
00914 
00915     return;
00916   }
00917 
00918   if (!IsBridgeTile(tile)) {
00919     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00920     return;
00921   }
00922 
00923   TileIndex end = GetOtherBridgeEnd(tile);
00924   z = GetBridgeHeight(tile);
00925 
00926   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00927   FindVehicleOnPos(end, &z, &FloodVehicleProc);
00928 }
00929 
00935 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00936 {
00937   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
00938    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
00939    * FLOOD_PASSIVE: (not used)
00940    * FLOOD_NONE:    canals, rivers, everything else
00941    */
00942   switch (GetTileType(tile)) {
00943     case MP_WATER:
00944       if (IsCoast(tile)) {
00945         Slope tileh = GetTileSlope(tile, NULL);
00946         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00947       }
00948       /* FALL THROUGH */
00949     case MP_STATION:
00950     case MP_INDUSTRY:
00951     case MP_OBJECT:
00952       return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00953 
00954     case MP_RAILWAY:
00955       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00956         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00957       }
00958       return FLOOD_NONE;
00959 
00960     case MP_TREES:
00961       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00962 
00963     default:
00964       return FLOOD_NONE;
00965   }
00966 }
00967 
00971 void DoFloodTile(TileIndex target)
00972 {
00973   assert(!IsTileType(target, MP_WATER));
00974 
00975   bool flooded = false; // Will be set to true if something is changed.
00976 
00977   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
00978 
00979   Slope tileh = GetTileSlope(target, NULL);
00980   if (tileh != SLOPE_FLAT) {
00981     /* make coast.. */
00982     switch (GetTileType(target)) {
00983       case MP_RAILWAY: {
00984         if (!IsPlainRail(target)) break;
00985         FloodVehicles(target);
00986         flooded = FloodHalftile(target);
00987         break;
00988       }
00989 
00990       case MP_TREES:
00991         if (!IsSlopeWithOneCornerRaised(tileh)) {
00992           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00993           MarkTileDirtyByTile(target);
00994           flooded = true;
00995           break;
00996         }
00997         /* FALL THROUGH */
00998 
00999       case MP_CLEAR:
01000         if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01001           MakeShore(target);
01002           MarkTileDirtyByTile(target);
01003           flooded = true;
01004         }
01005         break;
01006 
01007       default:
01008         break;
01009     }
01010   } else {
01011     /* Flood vehicles */
01012     FloodVehicles(target);
01013 
01014     /* flood flat tile */
01015     if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01016       MakeSea(target);
01017       MarkTileDirtyByTile(target);
01018       flooded = true;
01019     }
01020   }
01021 
01022   if (flooded) {
01023     /* Mark surrounding canal tiles dirty too to avoid glitches */
01024     MarkCanalsAndRiversAroundDirty(target);
01025 
01026     /* update signals if needed */
01027     UpdateSignalsInBuffer();
01028   }
01029 
01030   cur_company.Restore();
01031 }
01032 
01036 static void DoDryUp(TileIndex tile)
01037 {
01038   Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01039 
01040   switch (GetTileType(tile)) {
01041     case MP_RAILWAY:
01042       assert(IsPlainRail(tile));
01043       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
01044 
01045       RailGroundType new_ground;
01046       switch (GetTrackBits(tile)) {
01047         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
01048         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
01049         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
01050         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
01051         default: NOT_REACHED();
01052       }
01053       SetRailGroundType(tile, new_ground);
01054       MarkTileDirtyByTile(tile);
01055       break;
01056 
01057     case MP_TREES:
01058       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
01059       MarkTileDirtyByTile(tile);
01060       break;
01061 
01062     case MP_WATER:
01063       assert(IsCoast(tile));
01064 
01065       if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01066         MakeClear(tile, CLEAR_GRASS, 3);
01067         MarkTileDirtyByTile(tile);
01068       }
01069       break;
01070 
01071     default: NOT_REACHED();
01072   }
01073 
01074   cur_company.Restore();
01075 }
01076 
01083 void TileLoop_Water(TileIndex tile)
01084 {
01085   switch (GetFloodingBehaviour(tile)) {
01086     case FLOOD_ACTIVE:
01087       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01088         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
01089         if (dest == INVALID_TILE) continue;
01090         /* do not try to flood water tiles - increases performance a lot */
01091         if (IsTileType(dest, MP_WATER)) continue;
01092 
01093         uint z_dest;
01094         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01095         if (z_dest > 0) continue;
01096 
01097         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01098 
01099         DoFloodTile(dest);
01100       }
01101       break;
01102 
01103     case FLOOD_DRYUP: {
01104       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01105       uint dir;
01106       FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
01107         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
01108         if (dest == INVALID_TILE) continue;
01109 
01110         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01111         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01112       }
01113       DoDryUp(tile);
01114       break;
01115     }
01116 
01117     default: return;
01118   }
01119 }
01120 
01121 void ConvertGroundTilesIntoWaterTiles()
01122 {
01123   uint z;
01124 
01125   for (TileIndex tile = 0; tile < MapSize(); ++tile) {
01126     Slope slope = GetTileSlope(tile, &z);
01127     if (IsTileType(tile, MP_CLEAR) && z == 0) {
01128       /* Make both water for tiles at level 0
01129        * and make shore, as that looks much better
01130        * during the generation. */
01131       switch (slope) {
01132         case SLOPE_FLAT:
01133           MakeSea(tile);
01134           break;
01135 
01136         case SLOPE_N:
01137         case SLOPE_E:
01138         case SLOPE_S:
01139         case SLOPE_W:
01140           MakeShore(tile);
01141           break;
01142 
01143         default:
01144           uint dir;
01145           FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
01146             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01147             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01148             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01149               MakeShore(tile);
01150               break;
01151             }
01152           }
01153           break;
01154       }
01155     }
01156   }
01157 }
01158 
01159 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01160 {
01161   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01162 
01163   TrackBits ts;
01164 
01165   if (mode != TRANSPORT_WATER) return 0;
01166 
01167   switch (GetWaterTileType(tile)) {
01168     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01169     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01170     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01171     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01172     default: return 0;
01173   }
01174   if (TileX(tile) == 0) {
01175     /* NE border: remove tracks that connects NE tile edge */
01176     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01177   }
01178   if (TileY(tile) == 0) {
01179     /* NW border: remove tracks that connects NW tile edge */
01180     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01181   }
01182   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01183 }
01184 
01185 static bool ClickTile_Water(TileIndex tile)
01186 {
01187   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01188     ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
01189     return true;
01190   }
01191   return false;
01192 }
01193 
01194 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01195 {
01196   if (!IsTileOwner(tile, old_owner)) return;
01197 
01198   if (new_owner != INVALID_OWNER) {
01199     SetTileOwner(tile, new_owner);
01200     return;
01201   }
01202 
01203   /* Remove depot */
01204   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01205 
01206   /* Set owner of canals and locks ... and also canal under dock there was before.
01207    * Check if the new owner after removing depot isn't OWNER_WATER. */
01208   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01209 }
01210 
01211 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01212 {
01213   return VETSB_CONTINUE;
01214 }
01215 
01216 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01217 {
01218   /* Canals can't be terraformed */
01219   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01220 
01221   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01222 }
01223 
01224 
01225 extern const TileTypeProcs _tile_type_water_procs = {
01226   DrawTile_Water,           // draw_tile_proc
01227   GetSlopeZ_Water,          // get_slope_z_proc
01228   ClearTile_Water,          // clear_tile_proc
01229   NULL,                     // add_accepted_cargo_proc
01230   GetTileDesc_Water,        // get_tile_desc_proc
01231   GetTileTrackStatus_Water, // get_tile_track_status_proc
01232   ClickTile_Water,          // click_tile_proc
01233   NULL,                     // animate_tile_proc
01234   TileLoop_Water,           // tile_loop_clear
01235   ChangeTileOwner_Water,    // change_tile_owner_clear
01236   NULL,                     // add_produced_cargo_proc
01237   VehicleEnter_Water,       // vehicle_enter_tile_proc
01238   GetFoundation_Water,      // get_foundation_proc
01239   TerraformTile_Water,      // terraform_tile_proc
01240 };

Generated on Fri Dec 31 17:15:42 2010 for OpenTTD by  doxygen 1.6.1