water_cmd.cpp

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

Generated on Tue Jan 5 21:03:00 2010 for OpenTTD by  doxygen 1.5.6