water_cmd.cpp

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

Generated on Tue Sep 14 17:06:57 2010 for OpenTTD by  doxygen 1.6.1