water_cmd.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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   int size_x, size_y;
00300   int x;
00301   int y;
00302   int sx, sy;
00303 
00304   if (p1 >= MapSize()) return CMD_ERROR;
00305 
00306   /* Outside of the editor you can only build canals, not oceans */
00307   if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
00308 
00309   x = TileX(tile);
00310   y = TileY(tile);
00311   sx = TileX(p1);
00312   sy = TileY(p1);
00313 
00314   if (x < sx) Swap(x, sx);
00315   if (y < sy) Swap(y, sy);
00316   size_x = (x - sx) + 1;
00317   size_y = (y - sy) + 1;
00318 
00319   /* Outside the editor you can only drag canals, and not areas */
00320   if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
00321 
00322   TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
00323     CommandCost ret;
00324 
00325     Slope slope = GetTileSlope(tile, NULL);
00326     if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
00327       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00328     }
00329 
00330     /* can't make water of water! */
00331     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
00332 
00333     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00334     if (CmdFailed(ret)) return ret;
00335     cost.AddCost(ret);
00336 
00337     if (flags & DC_EXEC) {
00338       if (TileHeight(tile) == 0 && p2 == 1) {
00339         MakeSea(tile);
00340       } else if (p2 == 2) {
00341         MakeRiver(tile, Random());
00342       } else {
00343         MakeCanal(tile, _current_company, Random());
00344       }
00345       MarkTileDirtyByTile(tile);
00346       MarkCanalsAndRiversAroundDirty(tile);
00347     }
00348 
00349     cost.AddCost(_price[PR_CLEAR_WATER]);
00350   }
00351 
00352   if (cost.GetCost() == 0) {
00353     return_cmd_error(STR_ERROR_ALREADY_BUILT);
00354   } else {
00355     return cost;
00356   }
00357 }
00358 
00359 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00360 {
00361   switch (GetWaterTileType(tile)) {
00362     case WATER_TILE_CLEAR:
00363       if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00364 
00365       /* Make sure freeform edges are allowed or it's not an edge tile. */
00366       if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00367           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00368         return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00369       }
00370 
00371       /* Make sure no vehicle is on the tile */
00372       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00373 
00374       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
00375 
00376       if (flags & DC_EXEC) {
00377         DoClearSquare(tile);
00378         MarkCanalsAndRiversAroundDirty(tile);
00379       }
00380       return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00381 
00382     case WATER_TILE_COAST: {
00383       Slope slope = GetTileSlope(tile, NULL);
00384 
00385       /* Make sure no vehicle is on the tile */
00386       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00387 
00388       if (flags & DC_EXEC) {
00389         DoClearSquare(tile);
00390         MarkCanalsAndRiversAroundDirty(tile);
00391       }
00392       if (IsSlopeWithOneCornerRaised(slope)) {
00393         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00394       } else {
00395         return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00396       }
00397     }
00398 
00399     case WATER_TILE_LOCK: {
00400       static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
00401         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
00402         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
00403         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
00404       };
00405 
00406       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00407       if (_current_company == OWNER_WATER) return CMD_ERROR;
00408       /* move to the middle tile.. */
00409       return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
00410     }
00411 
00412     case WATER_TILE_DEPOT:
00413       if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00414       return RemoveShipDepot(tile, flags);
00415 
00416     default:
00417       NOT_REACHED();
00418   }
00419 }
00420 
00429 static bool IsWateredTile(TileIndex tile, Direction from)
00430 {
00431   switch (GetTileType(tile)) {
00432     case MP_WATER:
00433       switch (GetWaterTileType(tile)) {
00434         default: NOT_REACHED();
00435         case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00436         case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00437 
00438         case WATER_TILE_COAST:
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 
00448     case MP_RAILWAY:
00449       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00450         assert(IsPlainRail(tile));
00451         switch (GetTileSlope(tile, NULL)) {
00452           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00453           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00454           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00455           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00456           default: return false;
00457         }
00458       }
00459       return false;
00460 
00461     case MP_STATION:
00462       if (IsOilRig(tile)) {
00463         /* Do not draw waterborders inside of industries.
00464          * Note: There is no easy way to detect the industry of an oilrig tile. */
00465         TileIndex src_tile = tile + TileOffsByDir(from);
00466         if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00467             (IsTileType(src_tile, MP_INDUSTRY))) return true;
00468 
00469         return GetWaterClass(tile) != WATER_CLASS_INVALID;
00470       }
00471       return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00472 
00473     case MP_INDUSTRY: {
00474       /* Do not draw waterborders inside of industries.
00475        * Note: There is no easy way to detect the industry of an oilrig tile. */
00476       TileIndex src_tile = tile + TileOffsByDir(from);
00477       if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00478           (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00479 
00480       return IsIndustryTileOnWater(tile);
00481     }
00482 
00483     case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00484 
00485     default:          return false;
00486   }
00487 }
00488 
00489 static void DrawWaterEdges(SpriteID base, TileIndex tile)
00490 {
00491   uint wa;
00492 
00493   /* determine the edges around with water. */
00494   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
00495   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
00496   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
00497   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
00498 
00499   if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
00500   if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
00501   if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
00502   if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
00503 
00504   /* right corner */
00505   switch (wa & 0x03) {
00506     case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
00507     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
00508   }
00509 
00510   /* bottom corner */
00511   switch (wa & 0x06) {
00512     case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
00513     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
00514   }
00515 
00516   /* left corner */
00517   switch (wa & 0x0C) {
00518     case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
00519     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
00520   }
00521 
00522   /* upper corner */
00523   switch (wa & 0x09) {
00524     case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
00525     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
00526   }
00527 }
00528 
00530 static void DrawSeaWater(TileIndex tile)
00531 {
00532   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00533 }
00534 
00536 static void DrawCanalWater(TileIndex tile)
00537 {
00538   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00539 
00540   /* Test for custom graphics, else use the default */
00541   SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
00542   if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
00543 
00544   DrawWaterEdges(dikes_base, tile);
00545 }
00546 
00547 struct LocksDrawTileStruct {
00548   int8 delta_x, delta_y, delta_z;
00549   byte width, height, depth;
00550   SpriteID image;
00551 };
00552 
00553 #include "table/water_land.h"
00554 
00555 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
00556   SpriteID palette, uint base, bool draw_ground)
00557 {
00558   SpriteID image;
00559   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00560   SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
00561 
00562   /* If no custom graphics, use defaults */
00563   if (water_base == 0) water_base = SPR_CANALS_BASE;
00564   if (locks_base == 0) {
00565     locks_base = SPR_SHIPLIFT_BASE;
00566   } else {
00567     /* If using custom graphics, ignore the variation on height */
00568     base = 0;
00569   }
00570 
00571   image = wdts++->image;
00572   if (image < 4) image += water_base;
00573   if (draw_ground) DrawGroundSprite(image, PAL_NONE);
00574 
00575   /* End now if buildings are invisible */
00576   if (IsInvisibilitySet(TO_BUILDINGS)) return;
00577 
00578   for (; wdts->delta_x != 0x80; wdts++) {
00579     AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
00580       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
00581       wdts->size_x, wdts->size_y,
00582       wdts->size_z, ti->z + wdts->delta_z,
00583       IsTransparencySet(TO_BUILDINGS));
00584   }
00585 }
00586 
00587 static void DrawRiverWater(const TileInfo *ti)
00588 {
00589   SpriteID image = SPR_FLAT_WATER_TILE;
00590   SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
00591 
00592   if (ti->tileh != SLOPE_FLAT) {
00593     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00594     if (image == 0) {
00595       switch (ti->tileh) {
00596         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00597         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
00598         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
00599         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00600         default:       image = SPR_FLAT_WATER_TILE;    break;
00601       }
00602     } else {
00603       switch (ti->tileh) {
00604         default: NOT_REACHED();
00605         case SLOPE_SE:             edges_base += 12; break;
00606         case SLOPE_NE: image += 1; edges_base += 24; break;
00607         case SLOPE_SW: image += 2; edges_base += 36; break;
00608         case SLOPE_NW: image += 3; edges_base += 48; break;
00609       }
00610     }
00611   }
00612 
00613   DrawGroundSprite(image, PAL_NONE);
00614 
00615   /* Draw river edges if available. */
00616   if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
00617 }
00618 
00619 void DrawShoreTile(Slope tileh)
00620 {
00621   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
00622    * This allows to calculate the proper sprite to display for this Slope */
00623   static const byte tileh_to_shoresprite[32] = {
00624     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00625     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
00626   };
00627 
00628   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
00629   assert(tileh != SLOPE_FLAT);     // Shore is never flat
00630 
00631   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
00632 
00633   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00634 }
00635 
00636 void DrawWaterClassGround(const TileInfo *ti)
00637 {
00638   switch (GetWaterClass(ti->tile)) {
00639     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
00640     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00641     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00642     default: NOT_REACHED();
00643   }
00644 }
00645 
00646 static void DrawTile_Water(TileInfo *ti)
00647 {
00648   switch (GetWaterTileType(ti->tile)) {
00649     case WATER_TILE_CLEAR:
00650       DrawWaterClassGround(ti);
00651       DrawBridgeMiddle(ti);
00652       break;
00653 
00654     case WATER_TILE_COAST: {
00655       DrawShoreTile(ti->tileh);
00656       DrawBridgeMiddle(ti);
00657     } break;
00658 
00659     case WATER_TILE_LOCK: {
00660       const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
00661       DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
00662     } break;
00663 
00664     case WATER_TILE_DEPOT:
00665       DrawWaterClassGround(ti);
00666       DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
00667       break;
00668   }
00669 }
00670 
00671 void DrawShipDepotSprite(int x, int y, int image)
00672 {
00673   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00674 
00675   DrawSprite(wdts++->image, PAL_NONE, x, y);
00676 
00677   for (; wdts->delta_x != 0x80; wdts++) {
00678     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00679     DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
00680   }
00681 }
00682 
00683 
00684 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00685 {
00686   uint z;
00687   Slope tileh = GetTileSlope(tile, &z);
00688 
00689   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00690 }
00691 
00692 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00693 {
00694   return FOUNDATION_NONE;
00695 }
00696 
00697 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00698 {
00699   switch (GetWaterTileType(tile)) {
00700     case WATER_TILE_CLEAR:
00701       switch (GetWaterClass(tile)) {
00702         case WATER_CLASS_SEA:   td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00703         case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00704         case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00705         default: NOT_REACHED(); break;
00706       }
00707       break;
00708     case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00709     case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK;               break;
00710     case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;         break;
00711     default: NOT_REACHED(); break;
00712   }
00713 
00714   td->owner[0] = GetTileOwner(tile);
00715 }
00716 
00717 static void FloodVehicle(Vehicle *v);
00718 
00725 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00726 {
00727   byte z = *(byte*)data;
00728 
00729   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00730   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00731 
00732   FloodVehicle(v);
00733   return NULL;
00734 }
00735 
00741 static void FloodVehicles(TileIndex tile)
00742 {
00743   byte z = 0;
00744 
00745   if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
00746     const Station *st = Station::GetByTile(tile);
00747     const AirportFTAClass *airport = st->Airport();
00748     z = 1 + airport->delta_z;
00749     for (uint x = 0; x < airport->size_x; x++) {
00750       for (uint y = 0; y < airport->size_y; y++) {
00751         tile = TILE_ADDXY(st->airport_tile, x, y);
00752         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00753       }
00754     }
00755 
00756     /* No vehicle could be flooded on this airport anymore */
00757     return;
00758   }
00759 
00760   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
00761   if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00762     const Station *st = Station::GetByTile(tile);
00763 
00764     TILE_LOOP(t, st->train_station.w, st->train_station.h, st->train_station.tile) {
00765       if (st->TileBelongsToRailStation(t)) {
00766         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00767       }
00768     }
00769 
00770     return;
00771   }
00772 
00773   if (!IsBridgeTile(tile)) {
00774     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00775     return;
00776   }
00777 
00778   TileIndex end = GetOtherBridgeEnd(tile);
00779   z = GetBridgeHeight(tile);
00780 
00781   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00782   FindVehicleOnPos(end, &z, &FloodVehicleProc);
00783 }
00784 
00785 static void FloodVehicle(Vehicle *v)
00786 {
00787   if ((v->vehstatus & VS_CRASHED) != 0) return;
00788   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_AIRCRAFT) return;
00789 
00790   if (v->type == VEH_AIRCRAFT) {
00791     /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
00792      * because that's always the shadow. Except for the heliport, because
00793      * that station has a big z_offset for the aircraft. */
00794     if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00795     const Station *st = Station::GetByTile(v->tile);
00796     const AirportFTAClass *airport = st->Airport();
00797 
00798     if (v->z_pos != airport->delta_z + 1) return;
00799   } else {
00800     v = v->First();
00801   }
00802 
00803   uint pass = v->Crash(true);
00804 
00805   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00806   SetDParam(0, pass);
00807   AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
00808     NS_ACCIDENT,
00809     v->index);
00810   CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00811   SndPlayVehicleFx(SND_12_EXPLOSION, v);
00812 }
00813 
00819 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00820 {
00821   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
00822    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
00823    * FLOOD_PASSIVE: (not used)
00824    * FLOOD_NONE:    canals, rivers, everything else
00825    */
00826   switch (GetTileType(tile)) {
00827     case MP_WATER:
00828       if (IsCoast(tile)) {
00829         Slope tileh = GetTileSlope(tile, NULL);
00830         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00831       } else {
00832         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00833       }
00834 
00835     case MP_RAILWAY:
00836       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00837         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00838       }
00839       return FLOOD_NONE;
00840 
00841     case MP_TREES:
00842       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00843 
00844     case MP_STATION:
00845       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
00846         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00847       }
00848       return FLOOD_NONE;
00849 
00850     case MP_INDUSTRY:
00851       return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
00852 
00853     default:
00854       return FLOOD_NONE;
00855   }
00856 }
00857 
00861 void DoFloodTile(TileIndex target)
00862 {
00863   assert(!IsTileType(target, MP_WATER));
00864 
00865   bool flooded = false; // Will be set to true if something is changed.
00866 
00867   _current_company = OWNER_WATER;
00868 
00869   Slope tileh = GetTileSlope(target, NULL);
00870   if (tileh != SLOPE_FLAT) {
00871     /* make coast.. */
00872     switch (GetTileType(target)) {
00873       case MP_RAILWAY: {
00874         if (!IsPlainRail(target)) break;
00875         FloodVehicles(target);
00876         flooded = FloodHalftile(target);
00877         break;
00878       }
00879 
00880       case MP_TREES:
00881         if (!IsSlopeWithOneCornerRaised(tileh)) {
00882           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00883           MarkTileDirtyByTile(target);
00884           flooded = true;
00885           break;
00886         }
00887       /* FALL THROUGH */
00888       case MP_CLEAR:
00889         if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00890           MakeShore(target);
00891           MarkTileDirtyByTile(target);
00892           flooded = true;
00893         }
00894         break;
00895 
00896       default:
00897         break;
00898     }
00899   } else {
00900     /* Flood vehicles */
00901     FloodVehicles(target);
00902 
00903     /* flood flat tile */
00904     if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00905       MakeSea(target);
00906       MarkTileDirtyByTile(target);
00907       flooded = true;
00908     }
00909   }
00910 
00911   if (flooded) {
00912     /* Mark surrounding canal tiles dirty too to avoid glitches */
00913     MarkCanalsAndRiversAroundDirty(target);
00914 
00915     /* update signals if needed */
00916     UpdateSignalsInBuffer();
00917   }
00918 
00919   _current_company = OWNER_NONE;
00920 }
00921 
00925 static void DoDryUp(TileIndex tile)
00926 {
00927   _current_company = OWNER_WATER;
00928 
00929   switch (GetTileType(tile)) {
00930     case MP_RAILWAY:
00931       assert(IsPlainRail(tile));
00932       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00933 
00934       RailGroundType new_ground;
00935       switch (GetTrackBits(tile)) {
00936         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00937         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00938         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
00939         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
00940         default: NOT_REACHED();
00941       }
00942       SetRailGroundType(tile, new_ground);
00943       MarkTileDirtyByTile(tile);
00944       break;
00945 
00946     case MP_TREES:
00947       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
00948       MarkTileDirtyByTile(tile);
00949       break;
00950 
00951     case MP_WATER:
00952       assert(IsCoast(tile));
00953 
00954       if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00955         MakeClear(tile, CLEAR_GRASS, 3);
00956         MarkTileDirtyByTile(tile);
00957       }
00958       break;
00959 
00960     default: NOT_REACHED();
00961   }
00962 
00963   _current_company = OWNER_NONE;
00964 }
00965 
00972 void TileLoop_Water(TileIndex tile)
00973 {
00974   switch (GetFloodingBehaviour(tile)) {
00975     case FLOOD_ACTIVE:
00976       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00977         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
00978         if (dest == INVALID_TILE) continue;
00979         /* do not try to flood water tiles - increases performance a lot */
00980         if (IsTileType(dest, MP_WATER)) continue;
00981 
00982         uint z_dest;
00983         Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00984         if (z_dest > 0) continue;
00985 
00986         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
00987 
00988         DoFloodTile(dest);
00989       }
00990       break;
00991 
00992     case FLOOD_DRYUP: {
00993       Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00994       uint check_dirs = _flood_from_dirs[slope_here];
00995       uint dir;
00996       FOR_EACH_SET_BIT(dir, check_dirs) {
00997         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
00998         if (dest == INVALID_TILE) continue;
00999 
01000         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01001         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01002       }
01003       DoDryUp(tile);
01004       break;
01005     }
01006 
01007     default: return;
01008   }
01009 }
01010 
01011 void ConvertGroundTilesIntoWaterTiles()
01012 {
01013   TileIndex tile;
01014   uint z;
01015   Slope slope;
01016 
01017   for (tile = 0; tile < MapSize(); ++tile) {
01018     slope = GetTileSlope(tile, &z);
01019     if (IsTileType(tile, MP_CLEAR) && z == 0) {
01020       /* Make both water for tiles at level 0
01021        * and make shore, as that looks much better
01022        * during the generation. */
01023       switch (slope) {
01024         case SLOPE_FLAT:
01025           MakeSea(tile);
01026           break;
01027 
01028         case SLOPE_N:
01029         case SLOPE_E:
01030         case SLOPE_S:
01031         case SLOPE_W:
01032           MakeShore(tile);
01033           break;
01034 
01035         default:
01036           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01037           uint dir;
01038           FOR_EACH_SET_BIT(dir, check_dirs) {
01039             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01040             Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01041             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01042               MakeShore(tile);
01043               break;
01044             }
01045           }
01046           break;
01047       }
01048     }
01049   }
01050 }
01051 
01052 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01053 {
01054   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01055 
01056   TrackBits ts;
01057 
01058   if (mode != TRANSPORT_WATER) return 0;
01059 
01060   switch (GetWaterTileType(tile)) {
01061     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01062     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01063     case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01064     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01065     default: return 0;
01066   }
01067   if (TileX(tile) == 0) {
01068     /* NE border: remove tracks that connects NE tile edge */
01069     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01070   }
01071   if (TileY(tile) == 0) {
01072     /* NW border: remove tracks that connects NW tile edge */
01073     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01074   }
01075   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01076 }
01077 
01078 static bool ClickTile_Water(TileIndex tile)
01079 {
01080   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01081     TileIndex tile2 = GetOtherShipDepotTile(tile);
01082 
01083     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01084     return true;
01085   }
01086   return false;
01087 }
01088 
01089 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01090 {
01091   if (!IsTileOwner(tile, old_owner)) return;
01092 
01093   if (new_owner != INVALID_OWNER) {
01094     SetTileOwner(tile, new_owner);
01095     return;
01096   }
01097 
01098   /* Remove depot */
01099   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01100 
01101   /* Set owner of canals and locks ... and also canal under dock there was before.
01102    * Check if the new owner after removing depot isn't OWNER_WATER. */
01103   if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01104 }
01105 
01106 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01107 {
01108   return VETSB_CONTINUE;
01109 }
01110 
01111 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01112 {
01113   /* Canals can't be terraformed */
01114   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01115 
01116   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01117 }
01118 
01119 
01120 extern const TileTypeProcs _tile_type_water_procs = {
01121   DrawTile_Water,           // draw_tile_proc
01122   GetSlopeZ_Water,          // get_slope_z_proc
01123   ClearTile_Water,          // clear_tile_proc
01124   NULL,                     // add_accepted_cargo_proc
01125   GetTileDesc_Water,        // get_tile_desc_proc
01126   GetTileTrackStatus_Water, // get_tile_track_status_proc
01127   ClickTile_Water,          // click_tile_proc
01128   NULL,                     // animate_tile_proc
01129   TileLoop_Water,           // tile_loop_clear
01130   ChangeTileOwner_Water,    // change_tile_owner_clear
01131   NULL,                     // add_produced_cargo_proc
01132   VehicleEnter_Water,       // vehicle_enter_tile_proc
01133   GetFoundation_Water,      // get_foundation_proc
01134   TerraformTile_Water,      // terraform_tile_proc
01135 };

Generated on Sat Dec 26 20:06:07 2009 for OpenTTD by  doxygen 1.5.6