water_cmd.cpp

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

Generated on Wed Mar 3 23:32:30 2010 for OpenTTD by  doxygen 1.6.1