00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "landscape.h"
00015 #include "viewport_func.h"
00016 #include "command_func.h"
00017 #include "town.h"
00018 #include "news_func.h"
00019 #include "depot_base.h"
00020 #include "depot_func.h"
00021 #include "water.h"
00022 #include "industry_map.h"
00023 #include "newgrf_canal.h"
00024 #include "strings_func.h"
00025 #include "functions.h"
00026 #include "vehicle_func.h"
00027 #include "sound_func.h"
00028 #include "company_func.h"
00029 #include "clear_map.h"
00030 #include "tree_map.h"
00031 #include "aircraft.h"
00032 #include "effectvehicle_func.h"
00033 #include "tunnelbridge_map.h"
00034 #include "station_base.h"
00035 #include "ai/ai.hpp"
00036 #include "core/random_func.hpp"
00037
00038 #include "table/sprites.h"
00039 #include "table/strings.h"
00040
00044 static const uint8 _flood_from_dirs[] = {
00045 (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE),
00046 (1 << DIR_NE) | (1 << DIR_SE),
00047 (1 << DIR_NW) | (1 << DIR_NE),
00048 (1 << DIR_NE),
00049 (1 << DIR_NW) | (1 << DIR_SW),
00050 0,
00051 (1 << DIR_NW),
00052 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),
00053 (1 << DIR_SW) | (1 << DIR_SE),
00054 (1 << DIR_SE),
00055 0,
00056 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),
00057 (1 << DIR_SW),
00058 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),
00059 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),
00060 };
00061
00068 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00069 {
00070 if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00071 }
00072
00079 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00080 {
00081 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00082 MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00083 }
00084 }
00085
00086
00095 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00096 {
00097 Axis axis = Extract<Axis, 0, 1>(p1);
00098
00099 TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00100
00101 if (!IsWaterTile(tile) || !IsWaterTile(tile2)) {
00102 return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
00103 }
00104
00105 if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00106
00107 if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
00108
00109 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00110 }
00111
00112 WaterClass wc1 = GetWaterClass(tile);
00113 WaterClass wc2 = GetWaterClass(tile2);
00114 CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00115 if (ret.Failed()) return CMD_ERROR;
00116 ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00117 if (ret.Failed()) return CMD_ERROR;
00118
00119 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00120
00121 if (flags & DC_EXEC) {
00122 Depot *depot = new Depot(tile);
00123 depot->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00124
00125 MakeShipDepot(tile, _current_company, depot->index, DEPOT_NORTH, axis, wc1);
00126 MakeShipDepot(tile2, _current_company, depot->index, DEPOT_SOUTH, axis, wc2);
00127 MarkTileDirtyByTile(tile);
00128 MarkTileDirtyByTile(tile2);
00129 }
00130
00131 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
00132 }
00133
00134 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00135 {
00136 assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile) || IsOilRig(tile))) || IsTileType(tile, MP_INDUSTRY));
00137
00138 WaterClass wc = GetWaterClass(tile);
00139
00140
00141 uint z;
00142 if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
00143
00144 if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
00145
00146 switch (wc) {
00147 case WATER_CLASS_SEA: MakeSea(tile); break;
00148 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00149 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
00150 default: DoClearSquare(tile); break;
00151 }
00152 }
00153
00154 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
00155 {
00156 if (!IsShipDepot(tile)) return CMD_ERROR;
00157 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00158
00159 TileIndex tile2 = GetOtherShipDepotTile(tile);
00160
00161
00162 if (!(flags & DC_BANKRUPT)) {
00163 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
00164 }
00165
00166 if (flags & DC_EXEC) {
00167
00168 delete Depot::GetByTile(tile);
00169
00170 MakeWaterKeepingClass(tile, GetTileOwner(tile));
00171 MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00172 MarkTileDirtyByTile(tile);
00173 MarkTileDirtyByTile(tile2);
00174 }
00175
00176 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
00177 }
00178
00180 static CommandCost DoBuildShiplift(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
00181 {
00182 CommandCost ret;
00183 int delta;
00184
00185
00186 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00187 if (ret.Failed()) return CMD_ERROR;
00188
00189 delta = TileOffsByDiagDir(dir);
00190
00191 WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00192
00193 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00194 if (ret.Failed()) return CMD_ERROR;
00195 if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
00196 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00197 }
00198
00199
00200 WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
00201
00202 ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00203 if (ret.Failed()) return CMD_ERROR;
00204 if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
00205 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00206 }
00207
00208 if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00209 (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00210 (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00211 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00212 }
00213
00214 if (flags & DC_EXEC) {
00215 MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
00216 MarkTileDirtyByTile(tile);
00217 MarkTileDirtyByTile(tile - delta);
00218 MarkTileDirtyByTile(tile + delta);
00219 MarkCanalsAndRiversAroundDirty(tile - delta);
00220 MarkCanalsAndRiversAroundDirty(tile + delta);
00221 }
00222
00223 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER] * 22 >> 3);
00224 }
00225
00226 static CommandCost RemoveShiplift(TileIndex tile, DoCommandFlag flags)
00227 {
00228 TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
00229
00230 if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR;
00231
00232
00233 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta))
00234 return CMD_ERROR;
00235
00236 if (flags & DC_EXEC) {
00237 DoClearSquare(tile);
00238 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
00239 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
00240 MarkTileDirtyByTile(tile - delta);
00241 MarkTileDirtyByTile(tile + delta);
00242 MarkCanalsAndRiversAroundDirty(tile - delta);
00243 MarkCanalsAndRiversAroundDirty(tile + delta);
00244 }
00245
00246 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER] * 2);
00247 }
00248
00257 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00258 {
00259 DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
00260 if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00261
00262
00263 if (IsWaterTile(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00264
00265 return DoBuildShiplift(tile, dir, flags);
00266 }
00267
00276 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00277 {
00278 CommandCost cost(EXPENSES_CONSTRUCTION);
00279
00280 if (p1 >= MapSize() || p2 > 2) return CMD_ERROR;
00281
00282
00283 if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
00284
00285 TileArea ta(tile, p1);
00286
00287
00288 if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
00289
00290 TILE_AREA_LOOP(tile, ta) {
00291 CommandCost ret;
00292
00293 Slope slope = GetTileSlope(tile, NULL);
00294 if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
00295 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00296 }
00297
00298
00299 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
00300
00301 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00302 if (ret.Failed()) return ret;
00303 cost.AddCost(ret);
00304
00305 if (flags & DC_EXEC) {
00306 if (TileHeight(tile) == 0 && p2 == 1) {
00307 MakeSea(tile);
00308 } else if (p2 == 2) {
00309 MakeRiver(tile, Random());
00310 } else {
00311 MakeCanal(tile, _current_company, Random());
00312 }
00313 MarkTileDirtyByTile(tile);
00314 MarkCanalsAndRiversAroundDirty(tile);
00315 }
00316
00317 cost.AddCost(_price[PR_CLEAR_WATER]);
00318 }
00319
00320 if (cost.GetCost() == 0) {
00321 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00322 } else {
00323 return cost;
00324 }
00325 }
00326
00327 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00328 {
00329 switch (GetWaterTileType(tile)) {
00330 case WATER_TILE_CLEAR:
00331 if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00332
00333
00334 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00335 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00336 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00337 }
00338
00339
00340 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00341
00342 if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
00343
00344 if (flags & DC_EXEC) {
00345 DoClearSquare(tile);
00346 MarkCanalsAndRiversAroundDirty(tile);
00347 }
00348 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00349
00350 case WATER_TILE_COAST: {
00351 Slope slope = GetTileSlope(tile, NULL);
00352
00353
00354 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00355
00356 if (flags & DC_EXEC) {
00357 DoClearSquare(tile);
00358 MarkCanalsAndRiversAroundDirty(tile);
00359 }
00360 if (IsSlopeWithOneCornerRaised(slope)) {
00361 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00362 } else {
00363 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00364 }
00365 }
00366
00367 case WATER_TILE_LOCK: {
00368 static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
00369 { 0, 0}, {0, 0}, { 0, 0}, {0, 0},
00370 {-1, 0}, {0, 1}, { 1, 0}, {0, -1},
00371 { 1, 0}, {0, -1}, {-1, 0}, {0, 1},
00372 };
00373
00374 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00375 if (_current_company == OWNER_WATER) return CMD_ERROR;
00376
00377 return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
00378 }
00379
00380 case WATER_TILE_DEPOT:
00381 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00382 return RemoveShipDepot(tile, flags);
00383
00384 default:
00385 NOT_REACHED();
00386 }
00387 }
00388
00397 static bool IsWateredTile(TileIndex tile, Direction from)
00398 {
00399 switch (GetTileType(tile)) {
00400 case MP_WATER:
00401 switch (GetWaterTileType(tile)) {
00402 default: NOT_REACHED();
00403 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00404 case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00405
00406 case WATER_TILE_COAST:
00407 switch (GetTileSlope(tile, NULL)) {
00408 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00409 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00410 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00411 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00412 default: return false;
00413 }
00414 }
00415
00416 case MP_RAILWAY:
00417 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00418 assert(IsPlainRail(tile));
00419 switch (GetTileSlope(tile, NULL)) {
00420 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00421 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00422 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00423 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00424 default: return false;
00425 }
00426 }
00427 return false;
00428
00429 case MP_STATION:
00430 if (IsOilRig(tile)) {
00431
00432
00433 TileIndex src_tile = tile + TileOffsByDir(from);
00434 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00435 (IsTileType(src_tile, MP_INDUSTRY))) return true;
00436
00437 return GetWaterClass(tile) != WATER_CLASS_INVALID;
00438 }
00439 return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00440
00441 case MP_INDUSTRY: {
00442
00443
00444 TileIndex src_tile = tile + TileOffsByDir(from);
00445 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00446 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00447
00448 return IsIndustryTileOnWater(tile);
00449 }
00450
00451 case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00452
00453 default: return false;
00454 }
00455 }
00456
00457 static void DrawWaterEdges(SpriteID base, TileIndex tile)
00458 {
00459 uint wa;
00460
00461
00462 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00463 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00464 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00465 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00466
00467 if (!(wa & 1)) DrawGroundSprite(base, PAL_NONE);
00468 if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
00469 if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
00470 if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
00471
00472
00473 switch (wa & 0x03) {
00474 case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
00475 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
00476 }
00477
00478
00479 switch (wa & 0x06) {
00480 case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
00481 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
00482 }
00483
00484
00485 switch (wa & 0x0C) {
00486 case 0: DrawGroundSprite(base + 6, PAL_NONE); break;
00487 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
00488 }
00489
00490
00491 switch (wa & 0x09) {
00492 case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
00493 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
00494 }
00495 }
00496
00498 static void DrawSeaWater(TileIndex tile)
00499 {
00500 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00501 }
00502
00504 static void DrawCanalWater(TileIndex tile)
00505 {
00506 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00507
00508
00509 SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
00510 if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
00511
00512 DrawWaterEdges(dikes_base, tile);
00513 }
00514
00515 struct LocksDrawTileStruct {
00516 int8 delta_x, delta_y, delta_z;
00517 byte width, height, depth;
00518 SpriteID image;
00519 };
00520
00521 #include "table/water_land.h"
00522
00523 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
00524 PaletteID palette, uint base, bool draw_ground)
00525 {
00526 SpriteID image;
00527 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00528 SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile);
00529
00530
00531 if (water_base == 0) water_base = SPR_CANALS_BASE;
00532 if (locks_base == 0) {
00533 locks_base = SPR_SHIPLIFT_BASE;
00534 } else {
00535
00536 base = 0;
00537 }
00538
00539 image = wdts++->image;
00540 if (image < 4) image += water_base;
00541 if (draw_ground) DrawGroundSprite(image, PAL_NONE);
00542
00543
00544 if (IsInvisibilitySet(TO_BUILDINGS)) return;
00545
00546 for (; wdts->delta_x != 0x80; wdts++) {
00547 AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette,
00548 ti->x + wdts->delta_x, ti->y + wdts->delta_y,
00549 wdts->size_x, wdts->size_y,
00550 wdts->size_z, ti->z + wdts->delta_z,
00551 IsTransparencySet(TO_BUILDINGS));
00552 }
00553 }
00554
00555 static void DrawRiverWater(const TileInfo *ti)
00556 {
00557 SpriteID image = SPR_FLAT_WATER_TILE;
00558 SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
00559
00560 if (ti->tileh != SLOPE_FLAT) {
00561 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00562 if (image == 0) {
00563 switch (ti->tileh) {
00564 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00565 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
00566 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
00567 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00568 default: image = SPR_FLAT_WATER_TILE; break;
00569 }
00570 } else {
00571 switch (ti->tileh) {
00572 default: NOT_REACHED();
00573 case SLOPE_SE: edges_base += 12; break;
00574 case SLOPE_NE: image += 1; edges_base += 24; break;
00575 case SLOPE_SW: image += 2; edges_base += 36; break;
00576 case SLOPE_NW: image += 3; edges_base += 48; break;
00577 }
00578 }
00579 }
00580
00581 DrawGroundSprite(image, PAL_NONE);
00582
00583
00584 if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
00585 }
00586
00587 void DrawShoreTile(Slope tileh)
00588 {
00589
00590
00591 static const byte tileh_to_shoresprite[32] = {
00592 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
00594 };
00595
00596 assert(!IsHalftileSlope(tileh));
00597 assert(tileh != SLOPE_FLAT);
00598
00599 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
00600
00601 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00602 }
00603
00604 void DrawWaterClassGround(const TileInfo *ti)
00605 {
00606 switch (GetWaterClass(ti->tile)) {
00607 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00608 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00609 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00610 default: NOT_REACHED();
00611 }
00612 }
00613
00614 static void DrawTile_Water(TileInfo *ti)
00615 {
00616 switch (GetWaterTileType(ti->tile)) {
00617 case WATER_TILE_CLEAR:
00618 DrawWaterClassGround(ti);
00619 DrawBridgeMiddle(ti);
00620 break;
00621
00622 case WATER_TILE_COAST: {
00623 DrawShoreTile(ti->tileh);
00624 DrawBridgeMiddle(ti);
00625 } break;
00626
00627 case WATER_TILE_LOCK: {
00628 const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
00629 DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
00630 } break;
00631
00632 case WATER_TILE_DEPOT:
00633 DrawWaterClassGround(ti);
00634 DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
00635 break;
00636 }
00637 }
00638
00639 void DrawShipDepotSprite(int x, int y, int image)
00640 {
00641 const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00642
00643 DrawSprite(wdts++->image, PAL_NONE, x, y);
00644
00645 for (; wdts->delta_x != 0x80; wdts++) {
00646 Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00647 DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
00648 }
00649 }
00650
00651
00652 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00653 {
00654 uint z;
00655 Slope tileh = GetTileSlope(tile, &z);
00656
00657 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00658 }
00659
00660 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00661 {
00662 return FOUNDATION_NONE;
00663 }
00664
00665 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00666 {
00667 switch (GetWaterTileType(tile)) {
00668 case WATER_TILE_CLEAR:
00669 switch (GetWaterClass(tile)) {
00670 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00671 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00672 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00673 default: NOT_REACHED(); break;
00674 }
00675 break;
00676 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00677 case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
00678 case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT; break;
00679 default: NOT_REACHED(); break;
00680 }
00681
00682 td->owner[0] = GetTileOwner(tile);
00683 }
00684
00685 static void FloodVehicle(Vehicle *v);
00686
00693 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00694 {
00695 byte z = *(byte*)data;
00696
00697 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00698 if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00699
00700 FloodVehicle(v);
00701 return NULL;
00702 }
00703
00709 static void FloodVehicles(TileIndex tile)
00710 {
00711 byte z = 0;
00712
00713 if (IsAirportTile(tile)) {
00714 const Station *st = Station::GetByTile(tile);
00715 const AirportSpec *as = st->GetAirportSpec();
00716 z = 1 + st->Airport()->delta_z;
00717 for (uint x = 0; x < as->size_x; x++) {
00718 for (uint y = 0; y < as->size_y; y++) {
00719 tile = TILE_ADDXY(st->airport_tile, x, y);
00720 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00721 }
00722 }
00723
00724
00725 return;
00726 }
00727
00728
00729 if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00730 const Station *st = Station::GetByTile(tile);
00731
00732 TILE_AREA_LOOP(t, st->train_station) {
00733 if (st->TileBelongsToRailStation(t)) {
00734 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00735 }
00736 }
00737
00738 return;
00739 }
00740
00741 if (!IsBridgeTile(tile)) {
00742 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00743 return;
00744 }
00745
00746 TileIndex end = GetOtherBridgeEnd(tile);
00747 z = GetBridgeHeight(tile);
00748
00749 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00750 FindVehicleOnPos(end, &z, &FloodVehicleProc);
00751 }
00752
00753 static void FloodVehicle(Vehicle *v)
00754 {
00755 if ((v->vehstatus & VS_CRASHED) != 0) return;
00756 if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_AIRCRAFT) return;
00757
00758 if (v->type == VEH_AIRCRAFT) {
00759
00760
00761
00762 if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00763 const Station *st = Station::GetByTile(v->tile);
00764 const AirportFTAClass *airport = st->Airport();
00765
00766 if (v->z_pos != airport->delta_z + 1) return;
00767 } else {
00768 v = v->First();
00769 }
00770
00771 uint pass = v->Crash(true);
00772
00773 AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00774 SetDParam(0, pass);
00775 AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
00776 NS_ACCIDENT,
00777 v->index);
00778 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00779 SndPlayVehicleFx(SND_12_EXPLOSION, v);
00780 }
00781
00787 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00788 {
00789
00790
00791
00792
00793
00794 switch (GetTileType(tile)) {
00795 case MP_WATER:
00796 if (IsCoast(tile)) {
00797 Slope tileh = GetTileSlope(tile, NULL);
00798 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00799 } else {
00800 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00801 }
00802
00803 case MP_RAILWAY:
00804 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00805 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00806 }
00807 return FLOOD_NONE;
00808
00809 case MP_TREES:
00810 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00811
00812 case MP_STATION:
00813 if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
00814 return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00815 }
00816 return FLOOD_NONE;
00817
00818 case MP_INDUSTRY:
00819 return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
00820
00821 default:
00822 return FLOOD_NONE;
00823 }
00824 }
00825
00829 void DoFloodTile(TileIndex target)
00830 {
00831 assert(!IsTileType(target, MP_WATER));
00832
00833 bool flooded = false;
00834
00835 _current_company = OWNER_WATER;
00836
00837 Slope tileh = GetTileSlope(target, NULL);
00838 if (tileh != SLOPE_FLAT) {
00839
00840 switch (GetTileType(target)) {
00841 case MP_RAILWAY: {
00842 if (!IsPlainRail(target)) break;
00843 FloodVehicles(target);
00844 flooded = FloodHalftile(target);
00845 break;
00846 }
00847
00848 case MP_TREES:
00849 if (!IsSlopeWithOneCornerRaised(tileh)) {
00850 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00851 MarkTileDirtyByTile(target);
00852 flooded = true;
00853 break;
00854 }
00855
00856 case MP_CLEAR:
00857 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
00858 MakeShore(target);
00859 MarkTileDirtyByTile(target);
00860 flooded = true;
00861 }
00862 break;
00863
00864 default:
00865 break;
00866 }
00867 } else {
00868
00869 FloodVehicles(target);
00870
00871
00872 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
00873 MakeSea(target);
00874 MarkTileDirtyByTile(target);
00875 flooded = true;
00876 }
00877 }
00878
00879 if (flooded) {
00880
00881 MarkCanalsAndRiversAroundDirty(target);
00882
00883
00884 UpdateSignalsInBuffer();
00885 }
00886
00887 _current_company = OWNER_NONE;
00888 }
00889
00893 static void DoDryUp(TileIndex tile)
00894 {
00895 _current_company = OWNER_WATER;
00896
00897 switch (GetTileType(tile)) {
00898 case MP_RAILWAY:
00899 assert(IsPlainRail(tile));
00900 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00901
00902 RailGroundType new_ground;
00903 switch (GetTrackBits(tile)) {
00904 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00905 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00906 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
00907 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
00908 default: NOT_REACHED();
00909 }
00910 SetRailGroundType(tile, new_ground);
00911 MarkTileDirtyByTile(tile);
00912 break;
00913
00914 case MP_TREES:
00915 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
00916 MarkTileDirtyByTile(tile);
00917 break;
00918
00919 case MP_WATER:
00920 assert(IsCoast(tile));
00921
00922 if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
00923 MakeClear(tile, CLEAR_GRASS, 3);
00924 MarkTileDirtyByTile(tile);
00925 }
00926 break;
00927
00928 default: NOT_REACHED();
00929 }
00930
00931 _current_company = OWNER_NONE;
00932 }
00933
00940 void TileLoop_Water(TileIndex tile)
00941 {
00942 switch (GetFloodingBehaviour(tile)) {
00943 case FLOOD_ACTIVE:
00944 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00945 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
00946 if (dest == INVALID_TILE) continue;
00947
00948 if (IsTileType(dest, MP_WATER)) continue;
00949
00950 uint z_dest;
00951 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00952 if (z_dest > 0) continue;
00953
00954 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
00955
00956 DoFloodTile(dest);
00957 }
00958 break;
00959
00960 case FLOOD_DRYUP: {
00961 Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
00962 uint check_dirs = _flood_from_dirs[slope_here];
00963 uint dir;
00964 FOR_EACH_SET_BIT(dir, check_dirs) {
00965 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
00966 if (dest == INVALID_TILE) continue;
00967
00968 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
00969 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
00970 }
00971 DoDryUp(tile);
00972 break;
00973 }
00974
00975 default: return;
00976 }
00977 }
00978
00979 void ConvertGroundTilesIntoWaterTiles()
00980 {
00981 TileIndex tile;
00982 uint z;
00983 Slope slope;
00984
00985 for (tile = 0; tile < MapSize(); ++tile) {
00986 slope = GetTileSlope(tile, &z);
00987 if (IsTileType(tile, MP_CLEAR) && z == 0) {
00988
00989
00990
00991 switch (slope) {
00992 case SLOPE_FLAT:
00993 MakeSea(tile);
00994 break;
00995
00996 case SLOPE_N:
00997 case SLOPE_E:
00998 case SLOPE_S:
00999 case SLOPE_W:
01000 MakeShore(tile);
01001 break;
01002
01003 default:
01004 uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01005 uint dir;
01006 FOR_EACH_SET_BIT(dir, check_dirs) {
01007 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01008 Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01009 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01010 MakeShore(tile);
01011 break;
01012 }
01013 }
01014 break;
01015 }
01016 }
01017 }
01018 }
01019
01020 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01021 {
01022 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01023
01024 TrackBits ts;
01025
01026 if (mode != TRANSPORT_WATER) return 0;
01027
01028 switch (GetWaterTileType(tile)) {
01029 case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01030 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01031 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01032 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01033 default: return 0;
01034 }
01035 if (TileX(tile) == 0) {
01036
01037 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01038 }
01039 if (TileY(tile) == 0) {
01040
01041 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01042 }
01043 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01044 }
01045
01046 static bool ClickTile_Water(TileIndex tile)
01047 {
01048 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01049 TileIndex tile2 = GetOtherShipDepotTile(tile);
01050
01051 ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01052 return true;
01053 }
01054 return false;
01055 }
01056
01057 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01058 {
01059 if (!IsTileOwner(tile, old_owner)) return;
01060
01061 if (new_owner != INVALID_OWNER) {
01062 SetTileOwner(tile, new_owner);
01063 return;
01064 }
01065
01066
01067 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01068
01069
01070
01071 if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01072 }
01073
01074 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01075 {
01076 return VETSB_CONTINUE;
01077 }
01078
01079 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01080 {
01081
01082 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01083
01084 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01085 }
01086
01087
01088 extern const TileTypeProcs _tile_type_water_procs = {
01089 DrawTile_Water,
01090 GetSlopeZ_Water,
01091 ClearTile_Water,
01092 NULL,
01093 GetTileDesc_Water,
01094 GetTileTrackStatus_Water,
01095 ClickTile_Water,
01096 NULL,
01097 TileLoop_Water,
01098 ChangeTileOwner_Water,
01099 NULL,
01100 VehicleEnter_Water,
01101 GetFoundation_Water,
01102 TerraformTile_Water,
01103 };