water_cmd.cpp

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

Generated on Wed Apr 21 20:31:56 2010 for OpenTTD by  doxygen 1.6.1