00001
00002
00003
00004
00005
00006
00007
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),
00062 (1 << DIR_NE) | (1 << DIR_SE),
00063 (1 << DIR_NW) | (1 << DIR_NE),
00064 (1 << DIR_NE),
00065 (1 << DIR_NW) | (1 << DIR_SW),
00066 0,
00067 (1 << DIR_NW),
00068 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),
00069 (1 << DIR_SW) | (1 << DIR_SE),
00070 (1 << DIR_SE),
00071 0,
00072 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),
00073 (1 << DIR_SW),
00074 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),
00075 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),
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
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
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
00182 if (!(flags & DC_BANKRUPT)) {
00183 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
00184 }
00185
00186 if (flags & DC_EXEC) {
00187
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
00206 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00207 if (CmdFailed(ret)) return CMD_ERROR;
00208
00209 delta = TileOffsByDiagDir(dir);
00210
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
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
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
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
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
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
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
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
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
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},
00402 {-1, 0}, {0, 1}, { 1, 0}, {0, -1},
00403 { 1, 0}, {0, -1}, {-1, 0}, {0, 1},
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
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
00464
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
00475
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
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
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
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
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
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
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
00563 if (water_base == 0) water_base = SPR_CANALS_BASE;
00564 if (locks_base == 0) {
00565 locks_base = SPR_SHIPLIFT_BASE;
00566 } else {
00567
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
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
00616 if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
00617 }
00618
00619 void DrawShoreTile(Slope tileh)
00620 {
00621
00622
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));
00629 assert(tileh != SLOPE_FLAT);
00630
00631 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
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
00757 return;
00758 }
00759
00760
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
00792
00793
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
00822
00823
00824
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;
00866
00867 _current_company = OWNER_WATER;
00868
00869 Slope tileh = GetTileSlope(target, NULL);
00870 if (tileh != SLOPE_FLAT) {
00871
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
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
00901 FloodVehicles(target);
00902
00903
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
00913 MarkCanalsAndRiversAroundDirty(target);
00914
00915
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
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
01021
01022
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
01069 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01070 }
01071 if (TileY(tile) == 0) {
01072
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
01099 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01100
01101
01102
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
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,
01122 GetSlopeZ_Water,
01123 ClearTile_Water,
01124 NULL,
01125 GetTileDesc_Water,
01126 GetTileTrackStatus_Water,
01127 ClickTile_Water,
01128 NULL,
01129 TileLoop_Water,
01130 ChangeTileOwner_Water,
01131 NULL,
01132 VehicleEnter_Water,
01133 GetFoundation_Water,
01134 TerraformTile_Water,
01135 };