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
00300 if (p1 >= MapSize()) return CMD_ERROR;
00301
00302
00303 if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
00304
00305 TileArea ta(tile, p1);
00306
00307
00308 if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
00309
00310 TILE_AREA_LOOP(tile, ta) {
00311 CommandCost ret;
00312
00313 Slope slope = GetTileSlope(tile, NULL);
00314 if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
00315 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00316 }
00317
00318
00319 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
00320
00321 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00322 if (CmdFailed(ret)) return ret;
00323 cost.AddCost(ret);
00324
00325 if (flags & DC_EXEC) {
00326 if (TileHeight(tile) == 0 && p2 == 1) {
00327 MakeSea(tile);
00328 } else if (p2 == 2) {
00329 MakeRiver(tile, Random());
00330 } else {
00331 MakeCanal(tile, _current_company, Random());
00332 }
00333 MarkTileDirtyByTile(tile);
00334 MarkCanalsAndRiversAroundDirty(tile);
00335 }
00336
00337 cost.AddCost(_price[PR_CLEAR_WATER]);
00338 }
00339
00340 if (cost.GetCost() == 0) {
00341 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00342 } else {
00343 return cost;
00344 }
00345 }
00346
00347 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00348 {
00349 switch (GetWaterTileType(tile)) {
00350 case WATER_TILE_CLEAR:
00351 if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00352
00353
00354 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00355 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00356 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00357 }
00358
00359
00360 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00361
00362 if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
00363
00364 if (flags & DC_EXEC) {
00365 DoClearSquare(tile);
00366 MarkCanalsAndRiversAroundDirty(tile);
00367 }
00368 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00369
00370 case WATER_TILE_COAST: {
00371 Slope slope = GetTileSlope(tile, NULL);
00372
00373
00374 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00375
00376 if (flags & DC_EXEC) {
00377 DoClearSquare(tile);
00378 MarkCanalsAndRiversAroundDirty(tile);
00379 }
00380 if (IsSlopeWithOneCornerRaised(slope)) {
00381 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00382 } else {
00383 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00384 }
00385 }
00386
00387 case WATER_TILE_LOCK: {
00388 static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
00389 { 0, 0}, {0, 0}, { 0, 0}, {0, 0},
00390 {-1, 0}, {0, 1}, { 1, 0}, {0, -1},
00391 { 1, 0}, {0, -1}, {-1, 0}, {0, 1},
00392 };
00393
00394 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00395 if (_current_company == OWNER_WATER) return CMD_ERROR;
00396
00397 return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
00398 }
00399
00400 case WATER_TILE_DEPOT:
00401 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00402 return RemoveShipDepot(tile, flags);
00403
00404 default:
00405 NOT_REACHED();
00406 }
00407 }
00408
00417 static bool IsWateredTile(TileIndex tile, Direction from)
00418 {
00419 switch (GetTileType(tile)) {
00420 case MP_WATER:
00421 switch (GetWaterTileType(tile)) {
00422 default: NOT_REACHED();
00423 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00424 case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00425
00426 case WATER_TILE_COAST:
00427 switch (GetTileSlope(tile, NULL)) {
00428 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00429 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00430 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00431 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00432 default: return false;
00433 }
00434 }
00435
00436 case MP_RAILWAY:
00437 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00438 assert(IsPlainRail(tile));
00439 switch (GetTileSlope(tile, NULL)) {
00440 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00441 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00442 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00443 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00444 default: return false;
00445 }
00446 }
00447 return false;
00448
00449 case MP_STATION:
00450 if (IsOilRig(tile)) {
00451
00452
00453 TileIndex src_tile = tile + TileOffsByDir(from);
00454 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00455 (IsTileType(src_tile, MP_INDUSTRY))) return true;
00456
00457 return GetWaterClass(tile) != WATER_CLASS_INVALID;
00458 }
00459 return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00460
00461 case MP_INDUSTRY: {
00462
00463
00464 TileIndex src_tile = tile + TileOffsByDir(from);
00465 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00466 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00467
00468 return IsIndustryTileOnWater(tile);
00469 }
00470
00471 case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00472
00473 default: return false;
00474 }
00475 }
00476
00477 static void DrawWaterEdges(SpriteID base, TileIndex tile)
00478 {
00479 uint wa;
00480
00481
00482 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00483 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00484 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00485 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00486
00487 if (!(wa & 1)) DrawGroundSprite(base, PAL_NONE);
00488 if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
00489 if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
00490 if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
00491
00492
00493 switch (wa & 0x03) {
00494 case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
00495 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
00496 }
00497
00498
00499 switch (wa & 0x06) {
00500 case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
00501 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
00502 }
00503
00504
00505 switch (wa & 0x0C) {
00506 case 0: DrawGroundSprite(base + 6, PAL_NONE); break;
00507 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
00508 }
00509
00510
00511 switch (wa & 0x09) {
00512 case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
00513 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
00514 }
00515 }
00516
00518 static void DrawSeaWater(TileIndex tile)
00519 {
00520 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00521 }
00522
00524 static void DrawCanalWater(TileIndex tile)
00525 {
00526 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00527
00528
00529 SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
00530 if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
00531
00532 DrawWaterEdges(dikes_base, tile);
00533 }
00534
00535 struct LocksDrawTileStruct {
00536 int8 delta_x, delta_y, delta_z;
00537 byte width, height, depth;
00538 SpriteID image;
00539 };
00540
00541 #include "table/water_land.h"
00542
00543 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
00544 SpriteID palette, uint base, bool draw_ground)
00545 {
00546 SpriteID image;
00547 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00548 SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
00549
00550
00551 if (water_base == 0) water_base = SPR_CANALS_BASE;
00552 if (locks_base == 0) {
00553 locks_base = SPR_SHIPLIFT_BASE;
00554 } else {
00555
00556 base = 0;
00557 }
00558
00559 image = wdts++->image;
00560 if (image < 4) image += water_base;
00561 if (draw_ground) DrawGroundSprite(image, PAL_NONE);
00562
00563
00564 if (IsInvisibilitySet(TO_BUILDINGS)) return;
00565
00566 for (; wdts->delta_x != 0x80; wdts++) {
00567 AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
00568 ti->x + wdts->delta_x, ti->y + wdts->delta_y,
00569 wdts->size_x, wdts->size_y,
00570 wdts->size_z, ti->z + wdts->delta_z,
00571 IsTransparencySet(TO_BUILDINGS));
00572 }
00573 }
00574
00575 static void DrawRiverWater(const TileInfo *ti)
00576 {
00577 SpriteID image = SPR_FLAT_WATER_TILE;
00578 SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
00579
00580 if (ti->tileh != SLOPE_FLAT) {
00581 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00582 if (image == 0) {
00583 switch (ti->tileh) {
00584 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00585 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
00586 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
00587 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00588 default: image = SPR_FLAT_WATER_TILE; break;
00589 }
00590 } else {
00591 switch (ti->tileh) {
00592 default: NOT_REACHED();
00593 case SLOPE_SE: edges_base += 12; break;
00594 case SLOPE_NE: image += 1; edges_base += 24; break;
00595 case SLOPE_SW: image += 2; edges_base += 36; break;
00596 case SLOPE_NW: image += 3; edges_base += 48; break;
00597 }
00598 }
00599 }
00600
00601 DrawGroundSprite(image, PAL_NONE);
00602
00603
00604 if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
00605 }
00606
00607 void DrawShoreTile(Slope tileh)
00608 {
00609
00610
00611 static const byte tileh_to_shoresprite[32] = {
00612 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
00614 };
00615
00616 assert(!IsHalftileSlope(tileh));
00617 assert(tileh != SLOPE_FLAT);
00618
00619 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
00620
00621 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00622 }
00623
00624 void DrawWaterClassGround(const TileInfo *ti)
00625 {
00626 switch (GetWaterClass(ti->tile)) {
00627 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00628 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00629 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00630 default: NOT_REACHED();
00631 }
00632 }
00633
00634 static void DrawTile_Water(TileInfo *ti)
00635 {
00636 switch (GetWaterTileType(ti->tile)) {
00637 case WATER_TILE_CLEAR:
00638 DrawWaterClassGround(ti);
00639 DrawBridgeMiddle(ti);
00640 break;
00641
00642 case WATER_TILE_COAST: {
00643 DrawShoreTile(ti->tileh);
00644 DrawBridgeMiddle(ti);
00645 } break;
00646
00647 case WATER_TILE_LOCK: {
00648 const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
00649 DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
00650 } break;
00651
00652 case WATER_TILE_DEPOT:
00653 DrawWaterClassGround(ti);
00654 DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
00655 break;
00656 }
00657 }
00658
00659 void DrawShipDepotSprite(int x, int y, int image)
00660 {
00661 const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00662
00663 DrawSprite(wdts++->image, PAL_NONE, x, y);
00664
00665 for (; wdts->delta_x != 0x80; wdts++) {
00666 Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00667 DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
00668 }
00669 }
00670
00671
00672 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00673 {
00674 uint z;
00675 Slope tileh = GetTileSlope(tile, &z);
00676
00677 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00678 }
00679
00680 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00681 {
00682 return FOUNDATION_NONE;
00683 }
00684
00685 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00686 {
00687 switch (GetWaterTileType(tile)) {
00688 case WATER_TILE_CLEAR:
00689 switch (GetWaterClass(tile)) {
00690 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00691 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00692 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00693 default: NOT_REACHED(); break;
00694 }
00695 break;
00696 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00697 case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
00698 case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT; break;
00699 default: NOT_REACHED(); break;
00700 }
00701
00702 td->owner[0] = GetTileOwner(tile);
00703 }
00704
00705 static void FloodVehicle(Vehicle *v);
00706
00713 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00714 {
00715 byte z = *(byte*)data;
00716
00717 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00718 if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00719
00720 FloodVehicle(v);
00721 return NULL;
00722 }
00723
00729 static void FloodVehicles(TileIndex tile)
00730 {
00731 byte z = 0;
00732
00733 if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
00734 const Station *st = Station::GetByTile(tile);
00735 const AirportFTAClass *airport = st->Airport();
00736 z = 1 + airport->delta_z;
00737 for (uint x = 0; x < airport->size_x; x++) {
00738 for (uint y = 0; y < airport->size_y; y++) {
00739 tile = TILE_ADDXY(st->airport_tile, x, y);
00740 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00741 }
00742 }
00743
00744
00745 return;
00746 }
00747
00748
00749 if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00750 const Station *st = Station::GetByTile(tile);
00751
00752 TILE_AREA_LOOP(t, st->train_station) {
00753 if (st->TileBelongsToRailStation(t)) {
00754 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00755 }
00756 }
00757
00758 return;
00759 }
00760
00761 if (!IsBridgeTile(tile)) {
00762 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00763 return;
00764 }
00765
00766 TileIndex end = GetOtherBridgeEnd(tile);
00767 z = GetBridgeHeight(tile);
00768
00769 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00770 FindVehicleOnPos(end, &z, &FloodVehicleProc);
00771 }
00772
00773 static void FloodVehicle(Vehicle *v)
00774 {
00775 if ((v->vehstatus & VS_CRASHED) != 0) return;
00776 if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_AIRCRAFT) return;
00777
00778 if (v->type == VEH_AIRCRAFT) {
00779
00780
00781
00782 if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00783 const Station *st = Station::GetByTile(v->tile);
00784 const AirportFTAClass *airport = st->Airport();
00785
00786 if (v->z_pos != airport->delta_z + 1) return;
00787 } else {
00788 v = v->First();
00789 }
00790
00791 uint pass = v->Crash(true);
00792
00793 AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00794 SetDParam(0, pass);
00795 AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
00796 NS_ACCIDENT,
00797 v->index);
00798 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00799 SndPlayVehicleFx(SND_12_EXPLOSION, v);
00800 }
00801
00807 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00808 {
00809
00810
00811
00812
00813
00814 switch (GetTileType(tile)) {
00815 case MP_WATER:
00816 if (IsCoast(tile)) {
00817 Slope tileh = GetTileSlope(tile, NULL);
00818 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00819 } else {
00820 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00821 }
00822
00823 case MP_RAILWAY:
00824 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00825 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00826 }
00827 return FLOOD_NONE;
00828
00829 case MP_TREES:
00830 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00831
00832 case MP_STATION:
00833 if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
00834 return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00835 }
00836 return FLOOD_NONE;
00837
00838 case MP_INDUSTRY:
00839 return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
00840
00841 default:
00842 return FLOOD_NONE;
00843 }
00844 }
00845
00849 void DoFloodTile(TileIndex target)
00850 {
00851 assert(!IsTileType(target, MP_WATER));
00852
00853 bool flooded = false;
00854
00855 _current_company = OWNER_WATER;
00856
00857 Slope tileh = GetTileSlope(target, NULL);
00858 if (tileh != SLOPE_FLAT) {
00859
00860 switch (GetTileType(target)) {
00861 case MP_RAILWAY: {
00862 if (!IsPlainRail(target)) break;
00863 FloodVehicles(target);
00864 flooded = FloodHalftile(target);
00865 break;
00866 }
00867
00868 case MP_TREES:
00869 if (!IsSlopeWithOneCornerRaised(tileh)) {
00870 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00871 MarkTileDirtyByTile(target);
00872 flooded = true;
00873 break;
00874 }
00875
00876 case MP_CLEAR:
00877 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00878 MakeShore(target);
00879 MarkTileDirtyByTile(target);
00880 flooded = true;
00881 }
00882 break;
00883
00884 default:
00885 break;
00886 }
00887 } else {
00888
00889 FloodVehicles(target);
00890
00891
00892 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00893 MakeSea(target);
00894 MarkTileDirtyByTile(target);
00895 flooded = true;
00896 }
00897 }
00898
00899 if (flooded) {
00900
00901 MarkCanalsAndRiversAroundDirty(target);
00902
00903
00904 UpdateSignalsInBuffer();
00905 }
00906
00907 _current_company = OWNER_NONE;
00908 }
00909
00913 static void DoDryUp(TileIndex tile)
00914 {
00915 _current_company = OWNER_WATER;
00916
00917 switch (GetTileType(tile)) {
00918 case MP_RAILWAY:
00919 assert(IsPlainRail(tile));
00920 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00921
00922 RailGroundType new_ground;
00923 switch (GetTrackBits(tile)) {
00924 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00925 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00926 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
00927 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
00928 default: NOT_REACHED();
00929 }
00930 SetRailGroundType(tile, new_ground);
00931 MarkTileDirtyByTile(tile);
00932 break;
00933
00934 case MP_TREES:
00935 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
00936 MarkTileDirtyByTile(tile);
00937 break;
00938
00939 case MP_WATER:
00940 assert(IsCoast(tile));
00941
00942 if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00943 MakeClear(tile, CLEAR_GRASS, 3);
00944 MarkTileDirtyByTile(tile);
00945 }
00946 break;
00947
00948 default: NOT_REACHED();
00949 }
00950
00951 _current_company = OWNER_NONE;
00952 }
00953
00960 void TileLoop_Water(TileIndex tile)
00961 {
00962 switch (GetFloodingBehaviour(tile)) {
00963 case FLOOD_ACTIVE:
00964 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00965 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
00966 if (dest == INVALID_TILE) continue;
00967
00968 if (IsTileType(dest, MP_WATER)) continue;
00969
00970 uint z_dest;
00971 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00972 if (z_dest > 0) continue;
00973
00974 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
00975
00976 DoFloodTile(dest);
00977 }
00978 break;
00979
00980 case FLOOD_DRYUP: {
00981 Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00982 uint check_dirs = _flood_from_dirs[slope_here];
00983 uint dir;
00984 FOR_EACH_SET_BIT(dir, check_dirs) {
00985 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
00986 if (dest == INVALID_TILE) continue;
00987
00988 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
00989 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
00990 }
00991 DoDryUp(tile);
00992 break;
00993 }
00994
00995 default: return;
00996 }
00997 }
00998
00999 void ConvertGroundTilesIntoWaterTiles()
01000 {
01001 TileIndex tile;
01002 uint z;
01003 Slope slope;
01004
01005 for (tile = 0; tile < MapSize(); ++tile) {
01006 slope = GetTileSlope(tile, &z);
01007 if (IsTileType(tile, MP_CLEAR) && z == 0) {
01008
01009
01010
01011 switch (slope) {
01012 case SLOPE_FLAT:
01013 MakeSea(tile);
01014 break;
01015
01016 case SLOPE_N:
01017 case SLOPE_E:
01018 case SLOPE_S:
01019 case SLOPE_W:
01020 MakeShore(tile);
01021 break;
01022
01023 default:
01024 uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01025 uint dir;
01026 FOR_EACH_SET_BIT(dir, check_dirs) {
01027 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01028 Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01029 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01030 MakeShore(tile);
01031 break;
01032 }
01033 }
01034 break;
01035 }
01036 }
01037 }
01038 }
01039
01040 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01041 {
01042 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01043
01044 TrackBits ts;
01045
01046 if (mode != TRANSPORT_WATER) return 0;
01047
01048 switch (GetWaterTileType(tile)) {
01049 case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01050 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01051 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01052 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01053 default: return 0;
01054 }
01055 if (TileX(tile) == 0) {
01056
01057 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01058 }
01059 if (TileY(tile) == 0) {
01060
01061 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01062 }
01063 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01064 }
01065
01066 static bool ClickTile_Water(TileIndex tile)
01067 {
01068 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01069 TileIndex tile2 = GetOtherShipDepotTile(tile);
01070
01071 ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01072 return true;
01073 }
01074 return false;
01075 }
01076
01077 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01078 {
01079 if (!IsTileOwner(tile, old_owner)) return;
01080
01081 if (new_owner != INVALID_OWNER) {
01082 SetTileOwner(tile, new_owner);
01083 return;
01084 }
01085
01086
01087 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01088
01089
01090
01091 if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01092 }
01093
01094 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01095 {
01096 return VETSB_CONTINUE;
01097 }
01098
01099 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01100 {
01101
01102 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01103
01104 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01105 }
01106
01107
01108 extern const TileTypeProcs _tile_type_water_procs = {
01109 DrawTile_Water,
01110 GetSlopeZ_Water,
01111 ClearTile_Water,
01112 NULL,
01113 GetTileDesc_Water,
01114 GetTileTrackStatus_Water,
01115 ClickTile_Water,
01116 NULL,
01117 TileLoop_Water,
01118 ChangeTileOwner_Water,
01119 NULL,
01120 VehicleEnter_Water,
01121 GetFoundation_Water,
01122 TerraformTile_Water,
01123 };