water_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: water_cmd.cpp 14259 2008-09-07 11:54:00Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "bridge.h"
00009 #include "cmd_helper.h"
00010 #include "station_map.h"
00011 #include "tile_cmd.h"
00012 #include "landscape.h"
00013 #include "viewport_func.h"
00014 #include "command_func.h"
00015 #include "town.h"
00016 #include "news.h"
00017 #include "depot.h"
00018 #include "vehicle_gui.h"
00019 #include "train.h"
00020 #include "roadveh.h"
00021 #include "water.h"
00022 #include "water_map.h"
00023 #include "industry_map.h"
00024 #include "newgrf.h"
00025 #include "newgrf_canal.h"
00026 #include "transparency.h"
00027 #include "strings_func.h"
00028 #include "functions.h"
00029 #include "window_func.h"
00030 #include "vehicle_func.h"
00031 #include "sound_func.h"
00032 #include "variables.h"
00033 #include "player_func.h"
00034 #include "settings_type.h"
00035 #include "clear_map.h"
00036 #include "tree_map.h"
00037 #include "aircraft.h"
00038 
00039 #include "table/sprites.h"
00040 #include "table/strings.h"
00041 
00045 enum FloodingBehaviour {
00046   FLOOD_NONE,    
00047   FLOOD_ACTIVE,  
00048   FLOOD_PASSIVE, 
00049   FLOOD_DRYUP,   
00050 };
00051 
00055 static const uint8 _flood_from_dirs[] = {
00056   (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
00057   (1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
00058   (1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
00059   (1 << DIR_NE),                                                 // SLOPE_SW
00060   (1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
00061   0,                                                             // SLOPE_EW
00062   (1 << DIR_NW),                                                 // SLOPE_SE
00063   (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
00064   (1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
00065   (1 << DIR_SE),                                                 // SLOPE_NW
00066   0,                                                             // SLOPE_NS
00067   (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
00068   (1 << DIR_SW),                                                 // SLOPE_NE
00069   (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
00070   (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
00071 };
00072 
00079 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00080 {
00081   if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00082 }
00083 
00090 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00091 {
00092   for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00093     MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00094   }
00095 }
00096 
00107 void SetWaterClassDependingOnSurroundings(TileIndex t)
00108 {
00109   assert(GetTileSlope(t, NULL) == SLOPE_FLAT);
00110 
00111   /* Mark tile dirty in all cases */
00112   MarkTileDirtyByTile(t);
00113 
00114   if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) {
00115     /* tiles at map borders are always WATER_CLASS_SEA */
00116     SetWaterClass(t, WATER_CLASS_SEA);
00117     return;
00118   }
00119 
00120   bool has_water = false;
00121   bool has_canal = false;
00122   bool has_river = false;
00123 
00124   for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
00125     TileIndex neighbour = TileAddByDiagDir(t, dir);
00126     switch (GetTileType(neighbour)) {
00127       case MP_WATER:
00128         /* clear water and shipdepots have already a WaterClass associated */
00129         if (IsCoast(neighbour)) {
00130           has_water = true;
00131         } else if (!IsLock(neighbour)) {
00132           switch (GetWaterClass(neighbour)) {
00133             case WATER_CLASS_SEA:   has_water = true; break;
00134             case WATER_CLASS_CANAL: has_canal = true; break;
00135             case WATER_CLASS_RIVER: has_river = true; break;
00136             default: NOT_REACHED();
00137           }
00138         }
00139         break;
00140 
00141       case MP_RAILWAY:
00142         /* Shore or flooded halftile */
00143         has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER);
00144         break;
00145 
00146       case MP_TREES:
00147         /* trees on shore */
00148         has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE);
00149         break;
00150 
00151       default: break;
00152     }
00153   }
00154 
00155   if (has_river && !has_canal) {
00156     SetWaterClass(t, WATER_CLASS_RIVER);
00157   } else if (has_canal || !has_water) {
00158     SetWaterClass(t, WATER_CLASS_CANAL);
00159   } else {
00160     SetWaterClass(t, WATER_CLASS_SEA);
00161   }
00162 }
00163 
00164 
00171 CommandCost CmdBuildShipDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00172 {
00173   TileIndex tile2;
00174 
00175   CommandCost ret;
00176 
00177   Axis axis = Extract<Axis, 0>(p1);
00178 
00179   tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00180 
00181   if (!IsWaterTile(tile) || !IsWaterTile(tile2)) {
00182     return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
00183   }
00184 
00185   if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00186 
00187   if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
00188     /* Prevent depots on rapids */
00189     return_cmd_error(STR_0239_SITE_UNSUITABLE);
00190   }
00191 
00192   WaterClass wc1 = GetWaterClass(tile);
00193   WaterClass wc2 = GetWaterClass(tile2);
00194   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00195   if (CmdFailed(ret)) return CMD_ERROR;
00196   ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00197   if (CmdFailed(ret)) return CMD_ERROR;
00198 
00199   if (!Depot::CanAllocateItem()) return CMD_ERROR;
00200 
00201   if (flags & DC_EXEC) {
00202     Depot *depot = new Depot(tile);
00203     depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
00204 
00205     MakeShipDepot(tile,  _current_player, DEPOT_NORTH, axis, wc1);
00206     MakeShipDepot(tile2, _current_player, DEPOT_SOUTH, axis, wc2);
00207     MarkTileDirtyByTile(tile);
00208     MarkTileDirtyByTile(tile2);
00209   }
00210 
00211   return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot);
00212 }
00213 
00214 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00215 {
00216   assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile))));
00217 
00218   switch (GetWaterClass(tile)) {
00219     case WATER_CLASS_SEA:   MakeWater(tile);              break;
00220     case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00221     case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
00222   }
00223 }
00224 
00225 static CommandCost RemoveShipDepot(TileIndex tile, uint32 flags)
00226 {
00227   if (!IsShipDepot(tile)) return CMD_ERROR;
00228   if (!CheckTileOwnership(tile)) return CMD_ERROR;
00229 
00230   TileIndex tile2 = GetOtherShipDepotTile(tile);
00231 
00232   /* do not check for ship on tile when company goes bankrupt */
00233   if (!(flags & DC_BANKRUPT)) {
00234     if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
00235   }
00236 
00237   if (flags & DC_EXEC) {
00238     /* Kill the depot, which is registered at the northernmost tile. Use that one */
00239     delete GetDepotByTile(tile2 < tile ? tile2 : tile);
00240 
00241     MakeWaterKeepingClass(tile,  GetTileOwner(tile));
00242     MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00243     MarkTileDirtyByTile(tile);
00244     MarkTileDirtyByTile(tile2);
00245   }
00246 
00247   return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_ship_depot);
00248 }
00249 
00251 static CommandCost DoBuildShiplift(TileIndex tile, DiagDirection dir, uint32 flags)
00252 {
00253   CommandCost ret;
00254   int delta;
00255 
00256   /* middle tile */
00257   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00258   if (CmdFailed(ret)) return CMD_ERROR;
00259 
00260   delta = TileOffsByDiagDir(dir);
00261   /* lower tile */
00262   WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00263 
00264   ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00265   if (CmdFailed(ret)) return CMD_ERROR;
00266   if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
00267     return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00268   }
00269 
00270   /* upper tile */
00271   WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
00272 
00273   ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00274   if (CmdFailed(ret)) return CMD_ERROR;
00275   if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
00276     return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00277   }
00278 
00279   if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00280       (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00281       (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00282     return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00283   }
00284 
00285   if (flags & DC_EXEC) {
00286     MakeLock(tile, _current_player, dir, wc_lower, wc_upper);
00287     MarkTileDirtyByTile(tile);
00288     MarkTileDirtyByTile(tile - delta);
00289     MarkTileDirtyByTile(tile + delta);
00290     MarkCanalsAndRiversAroundDirty(tile - delta);
00291     MarkCanalsAndRiversAroundDirty(tile + delta);
00292   }
00293 
00294   return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 22 >> 3);
00295 }
00296 
00297 static CommandCost RemoveShiplift(TileIndex tile, uint32 flags)
00298 {
00299   TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
00300 
00301   if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR;
00302 
00303   /* make sure no vehicle is on the tile. */
00304   if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta))
00305     return CMD_ERROR;
00306 
00307   if (flags & DC_EXEC) {
00308     DoClearSquare(tile);
00309     MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
00310     MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
00311     MarkTileDirtyByTile(tile - delta);
00312     MarkTileDirtyByTile(tile + delta);
00313     MarkCanalsAndRiversAroundDirty(tile - delta);
00314     MarkCanalsAndRiversAroundDirty(tile + delta);
00315   }
00316 
00317   return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2);
00318 }
00319 
00326 CommandCost CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00327 {
00328   DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
00329   if (dir == INVALID_DIAGDIR) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00330 
00331   /* Disallow building of locks on river rapids */
00332   if (IsWaterTile(tile)) return_cmd_error(STR_0239_SITE_UNSUITABLE);
00333 
00334   return DoBuildShiplift(tile, dir, flags);
00335 }
00336 
00343 CommandCost CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00344 {
00345   CommandCost cost(EXPENSES_CONSTRUCTION);
00346   int size_x, size_y;
00347   int x;
00348   int y;
00349   int sx, sy;
00350 
00351   if (p1 >= MapSize()) return CMD_ERROR;
00352 
00353   /* Outside of the editor you can only build canals, not oceans */
00354   if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
00355 
00356   x = TileX(tile);
00357   y = TileY(tile);
00358   sx = TileX(p1);
00359   sy = TileY(p1);
00360 
00361   if (x < sx) Swap(x, sx);
00362   if (y < sy) Swap(y, sy);
00363   size_x = (x - sx) + 1;
00364   size_y = (y - sy) + 1;
00365 
00366   /* Outside the editor you can only drag canals, and not areas */
00367   if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
00368 
00369   BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
00370     CommandCost ret;
00371 
00372     Slope slope = GetTileSlope(tile, NULL);
00373     if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
00374       return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00375     }
00376 
00377     /* can't make water of water! */
00378     if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
00379 
00380     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00381     if (CmdFailed(ret)) return ret;
00382     cost.AddCost(ret);
00383 
00384     if (flags & DC_EXEC) {
00385       if (TileHeight(tile) == 0 && p2 == 1) {
00386         MakeWater(tile);
00387       } else if (p2 == 2) {
00388         MakeRiver(tile, Random());
00389       } else {
00390         MakeCanal(tile, _current_player, Random());
00391       }
00392       MarkTileDirtyByTile(tile);
00393       MarkCanalsAndRiversAroundDirty(tile);
00394     }
00395 
00396     cost.AddCost(_price.clear_water);
00397   } END_TILE_LOOP(tile, size_x, size_y, 0);
00398 
00399   if (cost.GetCost() == 0) {
00400     return_cmd_error(STR_1007_ALREADY_BUILT);
00401   } else {
00402     return cost;
00403   }
00404 }
00405 
00406 static CommandCost ClearTile_Water(TileIndex tile, byte flags)
00407 {
00408   switch (GetWaterTileType(tile)) {
00409     case WATER_TILE_CLEAR:
00410       if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
00411 
00412       /* Make sure it's not an edge tile. */
00413       if (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00414           !IsInsideMM(TileY(tile), 1, MapMaxY() - 1)) {
00415         return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
00416       }
00417 
00418       /* Make sure no vehicle is on the tile */
00419       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00420 
00421       if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
00422 
00423       if (flags & DC_EXEC) {
00424         DoClearSquare(tile);
00425         MarkCanalsAndRiversAroundDirty(tile);
00426       }
00427       return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
00428 
00429     case WATER_TILE_COAST: {
00430       Slope slope = GetTileSlope(tile, NULL);
00431 
00432       /* Make sure no vehicle is on the tile */
00433       if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00434 
00435       if (flags & DC_EXEC) {
00436         DoClearSquare(tile);
00437         MarkCanalsAndRiversAroundDirty(tile);
00438       }
00439       if (IsSlopeWithOneCornerRaised(slope)) {
00440         return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
00441       } else {
00442         return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_roughland);
00443       }
00444     }
00445 
00446     case WATER_TILE_LOCK: {
00447       static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
00448         { 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
00449         {-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
00450         { 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
00451       };
00452 
00453       if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00454       if (_current_player == OWNER_WATER) return CMD_ERROR;
00455       /* move to the middle tile.. */
00456       return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
00457     }
00458 
00459     case WATER_TILE_DEPOT:
00460       if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00461       return RemoveShipDepot(tile, flags);
00462 
00463     default:
00464       NOT_REACHED();
00465   }
00466 }
00467 
00476 static bool IsWateredTile(TileIndex tile, Direction from)
00477 {
00478   switch (GetTileType(tile)) {
00479     case MP_WATER:
00480       if (!IsCoast(tile)) return true;
00481       switch (GetTileSlope(tile, NULL)) {
00482         case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00483         case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00484         case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00485         case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00486         default: return false;
00487       }
00488 
00489     case MP_RAILWAY:
00490       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00491         assert(IsPlainRailTile(tile));
00492         switch (GetTileSlope(tile, NULL)) {
00493           case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00494           case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00495           case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00496           case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00497           default: return false;
00498         }
00499       }
00500       return false;
00501 
00502     case MP_STATION:  return IsOilRig(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00503     case MP_INDUSTRY: return (GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0;
00504     default:          return false;
00505   }
00506 }
00507 
00508 static void DrawWaterEdges(SpriteID base, TileIndex tile)
00509 {
00510   uint wa;
00511 
00512   /* determine the edges around with water. */
00513   wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
00514   wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
00515   wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
00516   wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
00517 
00518   if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
00519   if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
00520   if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
00521   if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
00522 
00523   /* right corner */
00524   switch (wa & 0x03) {
00525     case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
00526     case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
00527   }
00528 
00529   /* bottom corner */
00530   switch (wa & 0x06) {
00531     case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
00532     case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
00533   }
00534 
00535   /* left corner */
00536   switch (wa & 0x0C) {
00537     case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
00538     case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
00539   }
00540 
00541   /* upper corner */
00542   switch (wa & 0x09) {
00543     case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
00544     case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
00545   }
00546 }
00547 
00549 static void DrawSeaWater(TileIndex tile)
00550 {
00551   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00552 }
00553 
00555 static void DrawCanalWater(TileIndex tile)
00556 {
00557   DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00558 
00559   /* Test for custom graphics, else use the default */
00560   SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
00561   if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
00562 
00563   DrawWaterEdges(dikes_base, tile);
00564 }
00565 
00566 struct LocksDrawTileStruct {
00567   int8 delta_x, delta_y, delta_z;
00568   byte width, height, depth;
00569   SpriteID image;
00570 };
00571 
00572 #include "table/water_land.h"
00573 
00574 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
00575   SpriteID palette, uint base, bool draw_ground
00576 )
00577 {
00578   SpriteID image;
00579   SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00580   SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
00581 
00582   /* If no custom graphics, use defaults */
00583   if (water_base == 0) water_base = SPR_CANALS_BASE;
00584   if (locks_base == 0) {
00585     locks_base = SPR_SHIPLIFT_BASE;
00586   } else {
00587     /* If using custom graphics, ignore the variation on height */
00588     base = 0;
00589   }
00590 
00591   image = wdts++->image;
00592   if (image < 4) image += water_base;
00593   if (draw_ground) DrawGroundSprite(image, PAL_NONE);
00594 
00595   for (; wdts->delta_x != 0x80; wdts++) {
00596     AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
00597       ti->x + wdts->delta_x, ti->y + wdts->delta_y,
00598       wdts->width, wdts->height,
00599       wdts->unk, ti->z + wdts->delta_z,
00600       IsTransparencySet(TO_BUILDINGS));
00601   }
00602 }
00603 
00604 static void DrawRiverWater(const TileInfo *ti)
00605 {
00606   SpriteID image = SPR_FLAT_WATER_TILE;
00607   SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
00608 
00609   if (ti->tileh != SLOPE_FLAT) {
00610     image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00611     if (image == 0) {
00612       switch (ti->tileh) {
00613         case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00614         case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
00615         case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
00616         case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00617         default:       image = SPR_FLAT_WATER_TILE;    break;
00618       }
00619     } else {
00620       switch (ti->tileh) {
00621         default: NOT_REACHED();
00622         case SLOPE_SE:             edges_base += 12; break;
00623         case SLOPE_NE: image += 1; edges_base += 24; break;
00624         case SLOPE_SW: image += 2; edges_base += 36; break;
00625         case SLOPE_NW: image += 3; edges_base += 48; break;
00626       }
00627     }
00628   }
00629 
00630   DrawGroundSprite(image, PAL_NONE);
00631 
00632   /* Draw river edges if available. */
00633   if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
00634 }
00635 
00636 void DrawShoreTile(Slope tileh)
00637 {
00638   /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
00639    * This allows to calculate the proper sprite to display for this Slope */
00640   static const byte tileh_to_shoresprite[32] = {
00641     0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00642     0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
00643   };
00644 
00645   assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
00646   assert(tileh != SLOPE_FLAT);     // Shore is never flat
00647 
00648   assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
00649 
00650   DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00651 }
00652 
00653 void DrawWaterClassGround(const TileInfo *ti) {
00654   switch (GetWaterClass(ti->tile)) {
00655     case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
00656     case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00657     case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00658   }
00659 }
00660 
00661 static void DrawTile_Water(TileInfo *ti)
00662 {
00663   switch (GetWaterTileType(ti->tile)) {
00664     case WATER_TILE_CLEAR:
00665       DrawWaterClassGround(ti);
00666       DrawBridgeMiddle(ti);
00667       break;
00668 
00669     case WATER_TILE_COAST: {
00670       DrawShoreTile(ti->tileh);
00671       DrawBridgeMiddle(ti);
00672     } break;
00673 
00674     case WATER_TILE_LOCK: {
00675       const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
00676       DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
00677     } break;
00678 
00679     case WATER_TILE_DEPOT:
00680       DrawWaterClassGround(ti);
00681       DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)), 0, false);
00682       break;
00683   }
00684 }
00685 
00686 void DrawShipDepotSprite(int x, int y, int image)
00687 {
00688   const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00689 
00690   DrawSprite(wdts++->image, PAL_NONE, x, y);
00691 
00692   for (; wdts->delta_x != 0x80; wdts++) {
00693     Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00694     DrawSprite(wdts->image, PLAYER_SPRITE_COLOR(_local_player), x + pt.x, y + pt.y);
00695   }
00696 }
00697 
00698 
00699 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00700 {
00701   uint z;
00702   Slope tileh = GetTileSlope(tile, &z);
00703 
00704   return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00705 }
00706 
00707 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00708 {
00709   return FOUNDATION_NONE;
00710 }
00711 
00712 static void GetAcceptedCargo_Water(TileIndex tile, AcceptedCargo ac)
00713 {
00714   /* not used */
00715 }
00716 
00717 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00718 {
00719   switch (GetWaterTileType(tile)) {
00720     case WATER_TILE_CLEAR:
00721       if (!IsCanal(tile)) {
00722         td->str = STR_3804_WATER;
00723       } else {
00724         td->str = STR_LANDINFO_CANAL;
00725       }
00726       break;
00727     case WATER_TILE_COAST: td->str = STR_3805_COAST_OR_RIVERBANK; break;
00728     case WATER_TILE_LOCK : td->str = STR_LANDINFO_LOCK; break;
00729     case WATER_TILE_DEPOT: td->str = STR_3806_SHIP_DEPOT; break;
00730     default: assert(0); break;
00731   }
00732 
00733   td->owner = GetTileOwner(tile);
00734 }
00735 
00736 static void AnimateTile_Water(TileIndex tile)
00737 {
00738   /* not used */
00739 }
00740 
00741 static void FloodVehicle(Vehicle *v);
00742 
00749 static void *FloodVehicleProc(Vehicle *v, void *data)
00750 {
00751   byte z = *(byte*)data;
00752 
00753   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00754   if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00755 
00756   FloodVehicle(v);
00757   return NULL;
00758 }
00759 
00765 static void FloodVehicles(TileIndex tile)
00766 {
00767   byte z = 0;
00768 
00769   if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
00770     const Station *st = GetStationByTile(tile);
00771     const AirportFTAClass *airport = st->Airport();
00772     z = 1 + airport->delta_z;
00773     for (uint x = 0; x < airport->size_x; x++) {
00774       for (uint y = 0; y < airport->size_y; y++) {
00775         tile = TILE_ADDXY(st->airport_tile, x, y);
00776         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00777       }
00778     }
00779 
00780     /* No vehicle could be flooded on this airport anymore */
00781     return;
00782   }
00783 
00784   /* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
00785   if (!_patches.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00786     const Station *st = GetStationByTile(tile);
00787 
00788     BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00789       if (st->TileBelongsToRailStation(t)) {
00790         FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00791       }
00792     END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00793 
00794     return;
00795   }
00796 
00797   if (!IsBridgeTile(tile)) {
00798     FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00799     return;
00800   }
00801 
00802   TileIndex end = GetOtherBridgeEnd(tile);
00803   z = GetBridgeHeight(tile);
00804 
00805   FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00806   FindVehicleOnPos(end, &z, &FloodVehicleProc);
00807 }
00808 
00809 static void FloodVehicle(Vehicle *v)
00810 {
00811   if (!(v->vehstatus & VS_CRASHED)) {
00812     uint16 pass = 0;
00813 
00814     if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_AIRCRAFT) {
00815       if (v->type == VEH_AIRCRAFT) {
00816         /* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
00817          * because that's always the shadow. Except for the heliport, because
00818          * that station has a big z_offset for the aircraft. */
00819         if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00820         const Station *st = GetStationByTile(v->tile);
00821         const AirportFTAClass *airport = st->Airport();
00822 
00823         if (v->z_pos != airport->delta_z + 1) return;
00824       }
00825       Vehicle *u;
00826 
00827       if (v->type != VEH_AIRCRAFT) v = v->First();
00828       u = v;
00829 
00830       /* crash all wagons, and count passengers */
00831       BEGIN_ENUM_WAGONS(v)
00832         if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
00833         v->vehstatus |= VS_CRASHED;
00834         MarkSingleVehicleDirty(v);
00835       END_ENUM_WAGONS(v)
00836 
00837       v = u;
00838 
00839       switch (v->type) {
00840         default: NOT_REACHED();
00841         case VEH_TRAIN:
00842           if (IsFrontEngine(v)) pass += 4; // driver
00843           v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
00844           break;
00845 
00846         case VEH_ROAD:
00847           if (IsRoadVehFront(v)) pass += 1; // driver
00848           v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
00849           break;
00850 
00851         case VEH_AIRCRAFT:
00852           pass += 2; // driver
00853           v->u.air.crashed_counter = 9000; // max 10000, disappear pretty fast
00854           break;
00855       }
00856 
00857       RebuildVehicleLists();
00858     } else {
00859       return;
00860     }
00861 
00862     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00863     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
00864 
00865     SetDParam(0, pass);
00866     AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
00867       NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
00868       v->index,
00869       0);
00870     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00871     SndPlayVehicleFx(SND_12_EXPLOSION, v);
00872   }
00873 }
00874 
00880 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00881 {
00882   /* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile
00883    * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
00884    * FLOOD_PASSIVE: oilrig, water-industries
00885    * FLOOD_NONE:    canals, rivers, everything else
00886    */
00887   switch (GetTileType(tile)) {
00888     case MP_WATER:
00889       if (IsCoast(tile)) {
00890         Slope tileh = GetTileSlope(tile, NULL);
00891         return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00892       } else {
00893         return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00894       }
00895 
00896     case MP_RAILWAY:
00897       if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00898         return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00899       }
00900       return FLOOD_NONE;
00901 
00902     case MP_TREES:
00903       return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00904 
00905     case MP_STATION:
00906       if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT)) {
00907         return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00908       }
00909       return (IsOilRig(tile) ? FLOOD_PASSIVE : FLOOD_NONE);
00910 
00911     case MP_INDUSTRY:
00912       return ((GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0 ? FLOOD_PASSIVE : FLOOD_NONE);
00913 
00914     default:
00915       return FLOOD_NONE;
00916   }
00917 }
00918 
00922 static void DoFloodTile(TileIndex target)
00923 {
00924   assert(!IsTileType(target, MP_WATER));
00925 
00926   bool flooded = false; // Will be set to true if something is changed.
00927 
00928   _current_player = OWNER_WATER;
00929 
00930   Slope tileh = GetTileSlope(target, NULL);
00931   if (tileh != SLOPE_FLAT) {
00932     /* make coast.. */
00933     switch (GetTileType(target)) {
00934       case MP_RAILWAY: {
00935         if (!IsPlainRailTile(target)) break;
00936         FloodVehicles(target);
00937         flooded = FloodHalftile(target);
00938         break;
00939       }
00940 
00941       case MP_TREES:
00942         if (!IsSlopeWithOneCornerRaised(tileh)) {
00943           SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00944           MarkTileDirtyByTile(target);
00945           flooded = true;
00946           break;
00947         }
00948       /* FALL THROUGH */
00949       case MP_CLEAR:
00950         if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00951           MakeShore(target);
00952           MarkTileDirtyByTile(target);
00953           flooded = true;
00954         }
00955         break;
00956 
00957       default:
00958         break;
00959     }
00960   } else {
00961     /* Flood vehicles */
00962     FloodVehicles(target);
00963 
00964     /* flood flat tile */
00965     if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00966       MakeWater(target);
00967       MarkTileDirtyByTile(target);
00968       flooded = true;
00969     }
00970   }
00971 
00972   if (flooded) {
00973     /* Mark surrounding canal tiles dirty too to avoid glitches */
00974     MarkCanalsAndRiversAroundDirty(target);
00975 
00976     /* update signals if needed */
00977     UpdateSignalsInBuffer();
00978   }
00979 
00980   _current_player = OWNER_NONE;
00981 }
00982 
00986 static void DoDryUp(TileIndex tile)
00987 {
00988   _current_player = OWNER_WATER;
00989 
00990   switch (GetTileType(tile)) {
00991     case MP_RAILWAY:
00992       assert(IsPlainRailTile(tile));
00993       assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00994 
00995       RailGroundType new_ground;
00996       switch (GetTrackBits(tile)) {
00997         case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00998         case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00999         case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
01000         case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
01001         default: NOT_REACHED();
01002       }
01003       SetRailGroundType(tile, new_ground);
01004       MarkTileDirtyByTile(tile);
01005       break;
01006 
01007     case MP_TREES:
01008       SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
01009       MarkTileDirtyByTile(tile);
01010       break;
01011 
01012     case MP_WATER:
01013       assert(IsCoast(tile));
01014 
01015       if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
01016         MakeClear(tile, CLEAR_GRASS, 3);
01017         MarkTileDirtyByTile(tile);
01018       }
01019       break;
01020 
01021     default: NOT_REACHED();
01022   }
01023 
01024   _current_player = OWNER_NONE;
01025 }
01026 
01033 void TileLoop_Water(TileIndex tile)
01034 {
01035   switch (GetFloodingBehaviour(tile)) {
01036     case FLOOD_ACTIVE:
01037       for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01038         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
01039         if (dest == INVALID_TILE) continue;
01040         /* do not try to flood water tiles - increases performance a lot */
01041         if (IsTileType(dest, MP_WATER)) continue;
01042 
01043         uint z_dest;
01044         Slope slope_dest = (Slope)(GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP);
01045         if (z_dest > 0) continue;
01046 
01047         if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01048 
01049         DoFloodTile(dest);
01050       }
01051       break;
01052 
01053     case FLOOD_DRYUP: {
01054       Slope slope_here = (Slope)(GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP);
01055       uint check_dirs = _flood_from_dirs[slope_here];
01056       uint dir;
01057       FOR_EACH_SET_BIT(dir, check_dirs) {
01058         TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
01059         if (dest == INVALID_TILE) continue;
01060 
01061         FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01062         if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01063       }
01064       DoDryUp(tile);
01065       break;
01066     }
01067 
01068     default: return;
01069   }
01070 }
01071 
01072 void ConvertGroundTilesIntoWaterTiles()
01073 {
01074   TileIndex tile;
01075   uint z;
01076   Slope slope;
01077 
01078   for (tile = 0; tile < MapSize(); ++tile) {
01079     slope = GetTileSlope(tile, &z);
01080     if (IsTileType(tile, MP_CLEAR) && z == 0) {
01081       /* Make both water for tiles at level 0
01082        * and make shore, as that looks much better
01083        * during the generation. */
01084       switch (slope) {
01085         case SLOPE_FLAT:
01086           MakeWater(tile);
01087           break;
01088 
01089         case SLOPE_N:
01090         case SLOPE_E:
01091         case SLOPE_S:
01092         case SLOPE_W:
01093           MakeShore(tile);
01094           break;
01095 
01096         default:
01097           uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01098           uint dir;
01099           FOR_EACH_SET_BIT(dir, check_dirs) {
01100             TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01101             Slope slope_dest = (Slope)(GetTileSlope(dest, NULL) & ~SLOPE_STEEP);
01102             if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01103               MakeShore(tile);
01104               break;
01105             }
01106           }
01107           break;
01108       }
01109     }
01110   }
01111 }
01112 
01113 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01114 {
01115   static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01116 
01117   TrackBits ts;
01118 
01119   if (mode != TRANSPORT_WATER) return 0;
01120 
01121   switch (GetWaterTileType(tile)) {
01122     case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01123     case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01124     case WATER_TILE_LOCK:  ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
01125     case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01126     default: return 0;
01127   }
01128   if (TileX(tile) == 0) {
01129     /* NE border: remove tracks that connects NE tile edge */
01130     ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01131   }
01132   if (TileY(tile) == 0) {
01133     /* NW border: remove tracks that connects NW tile edge */
01134     ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01135   }
01136   return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01137 }
01138 
01139 static void ClickTile_Water(TileIndex tile)
01140 {
01141   if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01142     TileIndex tile2 = GetOtherShipDepotTile(tile);
01143 
01144     ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01145   }
01146 }
01147 
01148 static void ChangeTileOwner_Water(TileIndex tile, PlayerID old_player, PlayerID new_player)
01149 {
01150   if (!IsTileOwner(tile, old_player)) return;
01151 
01152   if (new_player != PLAYER_SPECTATOR) {
01153     SetTileOwner(tile, new_player);
01154     return;
01155   }
01156 
01157   /* Remove depot */
01158   if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01159 
01160   /* Set owner of canals and locks ... and also canal under dock there was before.
01161    * Check if the new owner after removing depot isn't OWNER_WATER. */
01162   if (IsTileOwner(tile, old_player)) SetTileOwner(tile, OWNER_NONE);
01163 }
01164 
01165 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01166 {
01167   return VETSB_CONTINUE;
01168 }
01169 
01170 static CommandCost TerraformTile_Water(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
01171 {
01172   /* Canals can't be terraformed */
01173   if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_MUST_DEMOLISH_CANAL_FIRST);
01174 
01175   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01176 }
01177 
01178 
01179 extern const TileTypeProcs _tile_type_water_procs = {
01180   DrawTile_Water,           /* draw_tile_proc */
01181   GetSlopeZ_Water,          /* get_slope_z_proc */
01182   ClearTile_Water,          /* clear_tile_proc */
01183   GetAcceptedCargo_Water,   /* get_accepted_cargo_proc */
01184   GetTileDesc_Water,        /* get_tile_desc_proc */
01185   GetTileTrackStatus_Water, /* get_tile_track_status_proc */
01186   ClickTile_Water,          /* click_tile_proc */
01187   AnimateTile_Water,        /* animate_tile_proc */
01188   TileLoop_Water,           /* tile_loop_clear */
01189   ChangeTileOwner_Water,    /* change_tile_owner_clear */
01190   NULL,                     /* get_produced_cargo_proc */
01191   VehicleEnter_Water,       /* vehicle_enter_tile_proc */
01192   GetFoundation_Water,      /* get_foundation_proc */
01193   TerraformTile_Water,      /* terraform_tile_proc */
01194 };

Generated on Mon Sep 22 20:34:20 2008 for openttd by  doxygen 1.5.6