00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "cmd_helper.h"
00008 #include "landscape.h"
00009 #include "viewport_func.h"
00010 #include "command_func.h"
00011 #include "town.h"
00012 #include "news_func.h"
00013 #include "depot_base.h"
00014 #include "depot_func.h"
00015 #include "vehicle_gui.h"
00016 #include "train.h"
00017 #include "roadveh.h"
00018 #include "water.h"
00019 #include "industry_map.h"
00020 #include "cargotype.h"
00021 #include "newgrf_canal.h"
00022 #include "transparency.h"
00023 #include "strings_func.h"
00024 #include "functions.h"
00025 #include "window_func.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 "newgrf_cargo.h"
00033 #include "effectvehicle_func.h"
00034 #include "tunnelbridge_map.h"
00035 #include "ai/ai.hpp"
00036
00037 #include "table/sprites.h"
00038 #include "table/strings.h"
00039
00043 enum FloodingBehaviour {
00044 FLOOD_NONE,
00045 FLOOD_ACTIVE,
00046 FLOOD_PASSIVE,
00047 FLOOD_DRYUP,
00048 };
00049
00053 static const uint8 _flood_from_dirs[] = {
00054 (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE),
00055 (1 << DIR_NE) | (1 << DIR_SE),
00056 (1 << DIR_NW) | (1 << DIR_NE),
00057 (1 << DIR_NE),
00058 (1 << DIR_NW) | (1 << DIR_SW),
00059 0,
00060 (1 << DIR_NW),
00061 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),
00062 (1 << DIR_SW) | (1 << DIR_SE),
00063 (1 << DIR_SE),
00064 0,
00065 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),
00066 (1 << DIR_SW),
00067 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),
00068 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),
00069 };
00070
00077 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00078 {
00079 if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00080 }
00081
00088 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00089 {
00090 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00091 MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00092 }
00093 }
00094
00095
00102 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00103 {
00104 TileIndex tile2;
00105
00106 CommandCost ret;
00107
00108 Axis axis = Extract<Axis, 0>(p1);
00109
00110 tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00111
00112 if (!IsWaterTile(tile) || !IsWaterTile(tile2)) {
00113 return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
00114 }
00115
00116 if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00117
00118 if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
00119
00120 return_cmd_error(STR_0239_SITE_UNSUITABLE);
00121 }
00122
00123 WaterClass wc1 = GetWaterClass(tile);
00124 WaterClass wc2 = GetWaterClass(tile2);
00125 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00126 if (CmdFailed(ret)) return CMD_ERROR;
00127 ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00128 if (CmdFailed(ret)) return CMD_ERROR;
00129
00130 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00131
00132 if (flags & DC_EXEC) {
00133 Depot *depot = new Depot(tile);
00134 depot->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00135
00136 MakeShipDepot(tile, _current_company, DEPOT_NORTH, axis, wc1);
00137 MakeShipDepot(tile2, _current_company, DEPOT_SOUTH, axis, wc2);
00138 MarkTileDirtyByTile(tile);
00139 MarkTileDirtyByTile(tile2);
00140 }
00141
00142 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot);
00143 }
00144
00145 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00146 {
00147 assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile) || IsOilRig(tile))) || IsTileType(tile, MP_INDUSTRY));
00148
00149 WaterClass wc = GetWaterClass(tile);
00150
00151
00152 uint z;
00153 if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID;
00154
00155 if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL;
00156
00157 switch (wc) {
00158 case WATER_CLASS_SEA: MakeWater(tile); break;
00159 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00160 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
00161 default: DoClearSquare(tile); break;
00162 }
00163 }
00164
00165 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
00166 {
00167 if (!IsShipDepot(tile)) return CMD_ERROR;
00168 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00169
00170 TileIndex tile2 = GetOtherShipDepotTile(tile);
00171
00172
00173 if (!(flags & DC_BANKRUPT)) {
00174 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
00175 }
00176
00177 if (flags & DC_EXEC) {
00178
00179 delete GetDepotByTile(tile2 < tile ? tile2 : tile);
00180
00181 MakeWaterKeepingClass(tile, GetTileOwner(tile));
00182 MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00183 MarkTileDirtyByTile(tile);
00184 MarkTileDirtyByTile(tile2);
00185 }
00186
00187 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_ship_depot);
00188 }
00189
00191 static CommandCost DoBuildShiplift(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
00192 {
00193 CommandCost ret;
00194 int delta;
00195
00196
00197 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00198 if (CmdFailed(ret)) return CMD_ERROR;
00199
00200 delta = TileOffsByDiagDir(dir);
00201
00202 WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00203
00204 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00205 if (CmdFailed(ret)) return CMD_ERROR;
00206 if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
00207 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00208 }
00209
00210
00211 WaterClass wc_upper = 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_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00217 }
00218
00219 if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00220 (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00221 (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00222 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00223 }
00224
00225 if (flags & DC_EXEC) {
00226 MakeLock(tile, _current_company, dir, wc_lower, wc_upper);
00227 MarkTileDirtyByTile(tile);
00228 MarkTileDirtyByTile(tile - delta);
00229 MarkTileDirtyByTile(tile + delta);
00230 MarkCanalsAndRiversAroundDirty(tile - delta);
00231 MarkCanalsAndRiversAroundDirty(tile + delta);
00232 }
00233
00234 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 22 >> 3);
00235 }
00236
00237 static CommandCost RemoveShiplift(TileIndex tile, DoCommandFlag flags)
00238 {
00239 TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
00240
00241 if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR;
00242
00243
00244 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta))
00245 return CMD_ERROR;
00246
00247 if (flags & DC_EXEC) {
00248 DoClearSquare(tile);
00249 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
00250 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
00251 MarkTileDirtyByTile(tile - delta);
00252 MarkTileDirtyByTile(tile + delta);
00253 MarkCanalsAndRiversAroundDirty(tile - delta);
00254 MarkCanalsAndRiversAroundDirty(tile + delta);
00255 }
00256
00257 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2);
00258 }
00259
00266 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00267 {
00268 DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
00269 if (dir == INVALID_DIAGDIR) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00270
00271
00272 if (IsWaterTile(tile)) return_cmd_error(STR_0239_SITE_UNSUITABLE);
00273
00274 return DoBuildShiplift(tile, dir, flags);
00275 }
00276
00283 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00284 {
00285 CommandCost cost(EXPENSES_CONSTRUCTION);
00286 int size_x, size_y;
00287 int x;
00288 int y;
00289 int sx, sy;
00290
00291 if (p1 >= MapSize()) return CMD_ERROR;
00292
00293
00294 if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;
00295
00296 x = TileX(tile);
00297 y = TileY(tile);
00298 sx = TileX(p1);
00299 sy = TileY(p1);
00300
00301 if (x < sx) Swap(x, sx);
00302 if (y < sy) Swap(y, sy);
00303 size_x = (x - sx) + 1;
00304 size_y = (y - sy) + 1;
00305
00306
00307 if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
00308
00309 BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
00310 CommandCost ret;
00311
00312 Slope slope = GetTileSlope(tile, NULL);
00313 if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
00314 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00315 }
00316
00317
00318 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;
00319
00320 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00321 if (CmdFailed(ret)) return ret;
00322 cost.AddCost(ret);
00323
00324 if (flags & DC_EXEC) {
00325 if (TileHeight(tile) == 0 && p2 == 1) {
00326 MakeWater(tile);
00327 } else if (p2 == 2) {
00328 MakeRiver(tile, Random());
00329 } else {
00330 MakeCanal(tile, _current_company, Random());
00331 }
00332 MarkTileDirtyByTile(tile);
00333 MarkCanalsAndRiversAroundDirty(tile);
00334 }
00335
00336 cost.AddCost(_price.clear_water);
00337 } END_TILE_LOOP(tile, size_x, size_y, 0);
00338
00339 if (cost.GetCost() == 0) {
00340 return_cmd_error(STR_1007_ALREADY_BUILT);
00341 } else {
00342 return cost;
00343 }
00344 }
00345
00346 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00347 {
00348 switch (GetWaterTileType(tile)) {
00349 case WATER_TILE_CLEAR:
00350 if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
00351
00352
00353 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00354 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00355 return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
00356 }
00357
00358
00359 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00360
00361 if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
00362
00363 if (flags & DC_EXEC) {
00364 DoClearSquare(tile);
00365 MarkCanalsAndRiversAroundDirty(tile);
00366 }
00367 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
00368
00369 case WATER_TILE_COAST: {
00370 Slope slope = GetTileSlope(tile, NULL);
00371
00372
00373 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00374
00375 if (flags & DC_EXEC) {
00376 DoClearSquare(tile);
00377 MarkCanalsAndRiversAroundDirty(tile);
00378 }
00379 if (IsSlopeWithOneCornerRaised(slope)) {
00380 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
00381 } else {
00382 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_roughland);
00383 }
00384 }
00385
00386 case WATER_TILE_LOCK: {
00387 static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
00388 { 0, 0}, {0, 0}, { 0, 0}, {0, 0},
00389 {-1, 0}, {0, 1}, { 1, 0}, {0, -1},
00390 { 1, 0}, {0, -1}, {-1, 0}, {0, 1},
00391 };
00392
00393 if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00394 if (_current_company == OWNER_WATER) return CMD_ERROR;
00395
00396 return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
00397 }
00398
00399 case WATER_TILE_DEPOT:
00400 if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00401 return RemoveShipDepot(tile, flags);
00402
00403 default:
00404 NOT_REACHED();
00405 }
00406 }
00407
00416 static bool IsWateredTile(TileIndex tile, Direction from)
00417 {
00418 switch (GetTileType(tile)) {
00419 case MP_WATER:
00420 switch (GetWaterTileType(tile)) {
00421 default: NOT_REACHED();
00422 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00423 case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00424
00425 case WATER_TILE_COAST:
00426 switch (GetTileSlope(tile, NULL)) {
00427 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00428 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00429 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00430 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00431 default: return false;
00432 }
00433 }
00434
00435 case MP_RAILWAY:
00436 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00437 assert(IsPlainRail(tile));
00438 switch (GetTileSlope(tile, NULL)) {
00439 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00440 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00441 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00442 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00443 default: return false;
00444 }
00445 }
00446 return false;
00447
00448 case MP_STATION:
00449 if (IsOilRig(tile)) {
00450
00451
00452 TileIndex src_tile = tile + TileOffsByDir(from);
00453 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00454 (IsTileType(src_tile, MP_INDUSTRY))) return true;
00455
00456 return GetWaterClass(tile) != WATER_CLASS_INVALID;
00457 }
00458 return (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
00459
00460 case MP_INDUSTRY: {
00461
00462
00463 TileIndex src_tile = tile + TileOffsByDir(from);
00464 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00465 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00466
00467 return IsIndustryTileOnWater(tile);
00468 }
00469
00470 case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00471
00472 default: return false;
00473 }
00474 }
00475
00476 static void DrawWaterEdges(SpriteID base, TileIndex tile)
00477 {
00478 uint wa;
00479
00480
00481 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00482 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00483 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00484 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00485
00486 if (!(wa & 1)) DrawGroundSprite(base, PAL_NONE);
00487 if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
00488 if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE);
00489 if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE);
00490
00491
00492 switch (wa & 0x03) {
00493 case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
00494 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
00495 }
00496
00497
00498 switch (wa & 0x06) {
00499 case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
00500 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
00501 }
00502
00503
00504 switch (wa & 0x0C) {
00505 case 0: DrawGroundSprite(base + 6, PAL_NONE); break;
00506 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
00507 }
00508
00509
00510 switch (wa & 0x09) {
00511 case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
00512 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
00513 }
00514 }
00515
00517 static void DrawSeaWater(TileIndex tile)
00518 {
00519 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00520 }
00521
00523 static void DrawCanalWater(TileIndex tile)
00524 {
00525 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00526
00527
00528 SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
00529 if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
00530
00531 DrawWaterEdges(dikes_base, tile);
00532 }
00533
00534 struct LocksDrawTileStruct {
00535 int8 delta_x, delta_y, delta_z;
00536 byte width, height, depth;
00537 SpriteID image;
00538 };
00539
00540 #include "table/water_land.h"
00541
00542 static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
00543 SpriteID palette, uint base, bool draw_ground
00544 )
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 switch (GetWaterClass(ti->tile)) {
00626 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00627 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00628 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00629 default: NOT_REACHED();
00630 }
00631 }
00632
00633 static void DrawTile_Water(TileInfo *ti)
00634 {
00635 switch (GetWaterTileType(ti->tile)) {
00636 case WATER_TILE_CLEAR:
00637 DrawWaterClassGround(ti);
00638 DrawBridgeMiddle(ti);
00639 break;
00640
00641 case WATER_TILE_COAST: {
00642 DrawShoreTile(ti->tileh);
00643 DrawBridgeMiddle(ti);
00644 } break;
00645
00646 case WATER_TILE_LOCK: {
00647 const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
00648 DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0, true);
00649 } break;
00650
00651 case WATER_TILE_DEPOT:
00652 DrawWaterClassGround(ti);
00653 DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), 0, false);
00654 break;
00655 }
00656 }
00657
00658 void DrawShipDepotSprite(int x, int y, int image)
00659 {
00660 const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
00661
00662 DrawSprite(wdts++->image, PAL_NONE, x, y);
00663
00664 for (; wdts->delta_x != 0x80; wdts++) {
00665 Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
00666 DrawSprite(wdts->image, COMPANY_SPRITE_COLOUR(_local_company), x + pt.x, y + pt.y);
00667 }
00668 }
00669
00670
00671 static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
00672 {
00673 uint z;
00674 Slope tileh = GetTileSlope(tile, &z);
00675
00676 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
00677 }
00678
00679 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00680 {
00681 return FOUNDATION_NONE;
00682 }
00683
00684 static void GetAcceptedCargo_Water(TileIndex tile, AcceptedCargo ac)
00685 {
00686
00687 }
00688
00689 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00690 {
00691 switch (GetWaterTileType(tile)) {
00692 case WATER_TILE_CLEAR:
00693 switch (GetWaterClass(tile)) {
00694 case WATER_CLASS_SEA: td->str = STR_3804_WATER; break;
00695 case WATER_CLASS_CANAL: td->str = STR_LANDINFO_CANAL; break;
00696 case WATER_CLASS_RIVER: td->str = STR_LANDINFO_RIVER; break;
00697 default: assert(0); break;
00698 }
00699 break;
00700 case WATER_TILE_COAST: td->str = STR_3805_COAST_OR_RIVERBANK; break;
00701 case WATER_TILE_LOCK : td->str = STR_LANDINFO_LOCK; break;
00702 case WATER_TILE_DEPOT: td->str = STR_3806_SHIP_DEPOT; break;
00703 default: assert(0); break;
00704 }
00705
00706 td->owner[0] = GetTileOwner(tile);
00707 }
00708
00709 static void FloodVehicle(Vehicle *v);
00710
00717 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00718 {
00719 byte z = *(byte*)data;
00720
00721 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00722 if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00723
00724 FloodVehicle(v);
00725 return NULL;
00726 }
00727
00733 static void FloodVehicles(TileIndex tile)
00734 {
00735 byte z = 0;
00736
00737 if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
00738 const Station *st = GetStationByTile(tile);
00739 const AirportFTAClass *airport = st->Airport();
00740 z = 1 + airport->delta_z;
00741 for (uint x = 0; x < airport->size_x; x++) {
00742 for (uint y = 0; y < airport->size_y; y++) {
00743 tile = TILE_ADDXY(st->airport_tile, x, y);
00744 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00745 }
00746 }
00747
00748
00749 return;
00750 }
00751
00752
00753 if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
00754 const Station *st = GetStationByTile(tile);
00755
00756 BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00757 if (st->TileBelongsToRailStation(t)) {
00758 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00759 }
00760 END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
00761
00762 return;
00763 }
00764
00765 if (!IsBridgeTile(tile)) {
00766 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00767 return;
00768 }
00769
00770 TileIndex end = GetOtherBridgeEnd(tile);
00771 z = GetBridgeHeight(tile);
00772
00773 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00774 FindVehicleOnPos(end, &z, &FloodVehicleProc);
00775 }
00776
00777 static void FloodVehicle(Vehicle *v)
00778 {
00779 if (!(v->vehstatus & VS_CRASHED)) {
00780 uint16 pass = 0;
00781
00782 if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_AIRCRAFT) {
00783 if (v->type == VEH_AIRCRAFT) {
00784
00785
00786
00787 if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
00788 const Station *st = GetStationByTile(v->tile);
00789 const AirportFTAClass *airport = st->Airport();
00790
00791 if (v->z_pos != airport->delta_z + 1) return;
00792 }
00793
00794 if (v->type != VEH_AIRCRAFT) v = v->First();
00795
00796
00797 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00798 if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
00799 u->vehstatus |= VS_CRASHED;
00800 MarkSingleVehicleDirty(u);
00801 }
00802
00803 switch (v->type) {
00804 default: NOT_REACHED();
00805 case VEH_TRAIN:
00806 if (IsFrontEngine(v)) {
00807 pass += 4;
00808
00809
00810 v->vehstatus &= ~VS_CRASHED;
00811 if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
00812 v->vehstatus |= VS_CRASHED;
00813 }
00814 v->u.rail.crash_anim_pos = 4000;
00815 InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
00816 break;
00817
00818 case VEH_ROAD:
00819 if (IsRoadVehFront(v)) pass += 1;
00820 v->u.road.crashed_ctr = 2000;
00821 InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
00822 break;
00823
00824 case VEH_AIRCRAFT:
00825 pass += 2;
00826 v->u.air.crashed_counter = 9000;
00827 InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
00828 break;
00829 }
00830 } else {
00831 return;
00832 }
00833
00834 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00835 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
00836
00837 AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
00838 SetDParam(0, pass);
00839 AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
00840 NS_ACCIDENT_VEHICLE,
00841 v->index,
00842 0);
00843 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00844 SndPlayVehicleFx(SND_12_EXPLOSION, v);
00845 }
00846 }
00847
00853 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
00854 {
00855
00856
00857
00858
00859
00860 switch (GetTileType(tile)) {
00861 case MP_WATER:
00862 if (IsCoast(tile)) {
00863 Slope tileh = GetTileSlope(tile, NULL);
00864 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00865 } else {
00866 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
00867 }
00868
00869 case MP_RAILWAY:
00870 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00871 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
00872 }
00873 return FLOOD_NONE;
00874
00875 case MP_TREES:
00876 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
00877
00878 case MP_STATION:
00879 if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
00880 return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
00881 }
00882 return FLOOD_NONE;
00883
00884 case MP_INDUSTRY:
00885 return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
00886
00887 default:
00888 return FLOOD_NONE;
00889 }
00890 }
00891
00895 void DoFloodTile(TileIndex target)
00896 {
00897 assert(!IsTileType(target, MP_WATER));
00898
00899 bool flooded = false;
00900
00901 _current_company = OWNER_WATER;
00902
00903 Slope tileh = GetTileSlope(target, NULL);
00904 if (tileh != SLOPE_FLAT) {
00905
00906 switch (GetTileType(target)) {
00907 case MP_RAILWAY: {
00908 if (!IsPlainRail(target)) break;
00909 FloodVehicles(target);
00910 flooded = FloodHalftile(target);
00911 break;
00912 }
00913
00914 case MP_TREES:
00915 if (!IsSlopeWithOneCornerRaised(tileh)) {
00916 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
00917 MarkTileDirtyByTile(target);
00918 flooded = true;
00919 break;
00920 }
00921
00922 case MP_CLEAR:
00923 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00924 MakeShore(target);
00925 MarkTileDirtyByTile(target);
00926 flooded = true;
00927 }
00928 break;
00929
00930 default:
00931 break;
00932 }
00933 } else {
00934
00935 FloodVehicles(target);
00936
00937
00938 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00939 MakeWater(target);
00940 MarkTileDirtyByTile(target);
00941 flooded = true;
00942 }
00943 }
00944
00945 if (flooded) {
00946
00947 MarkCanalsAndRiversAroundDirty(target);
00948
00949
00950 UpdateSignalsInBuffer();
00951 }
00952
00953 _current_company = OWNER_NONE;
00954 }
00955
00959 static void DoDryUp(TileIndex tile)
00960 {
00961 _current_company = OWNER_WATER;
00962
00963 switch (GetTileType(tile)) {
00964 case MP_RAILWAY:
00965 assert(IsPlainRail(tile));
00966 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
00967
00968 RailGroundType new_ground;
00969 switch (GetTrackBits(tile)) {
00970 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
00971 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
00972 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
00973 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
00974 default: NOT_REACHED();
00975 }
00976 SetRailGroundType(tile, new_ground);
00977 MarkTileDirtyByTile(tile);
00978 break;
00979
00980 case MP_TREES:
00981 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
00982 MarkTileDirtyByTile(tile);
00983 break;
00984
00985 case MP_WATER:
00986 assert(IsCoast(tile));
00987
00988 if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
00989 MakeClear(tile, CLEAR_GRASS, 3);
00990 MarkTileDirtyByTile(tile);
00991 }
00992 break;
00993
00994 default: NOT_REACHED();
00995 }
00996
00997 _current_company = OWNER_NONE;
00998 }
00999
01006 void TileLoop_Water(TileIndex tile)
01007 {
01008 switch (GetFloodingBehaviour(tile)) {
01009 case FLOOD_ACTIVE:
01010 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01011 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
01012 if (dest == INVALID_TILE) continue;
01013
01014 if (IsTileType(dest, MP_WATER)) continue;
01015
01016 uint z_dest;
01017 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01018 if (z_dest > 0) continue;
01019
01020 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01021
01022 DoFloodTile(dest);
01023 }
01024 break;
01025
01026 case FLOOD_DRYUP: {
01027 Slope slope_here = GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01028 uint check_dirs = _flood_from_dirs[slope_here];
01029 uint dir;
01030 FOR_EACH_SET_BIT(dir, check_dirs) {
01031 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
01032 if (dest == INVALID_TILE) continue;
01033
01034 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01035 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01036 }
01037 DoDryUp(tile);
01038 break;
01039 }
01040
01041 default: return;
01042 }
01043 }
01044
01045 void ConvertGroundTilesIntoWaterTiles()
01046 {
01047 TileIndex tile;
01048 uint z;
01049 Slope slope;
01050
01051 for (tile = 0; tile < MapSize(); ++tile) {
01052 slope = GetTileSlope(tile, &z);
01053 if (IsTileType(tile, MP_CLEAR) && z == 0) {
01054
01055
01056
01057 switch (slope) {
01058 case SLOPE_FLAT:
01059 MakeWater(tile);
01060 break;
01061
01062 case SLOPE_N:
01063 case SLOPE_E:
01064 case SLOPE_S:
01065 case SLOPE_W:
01066 MakeShore(tile);
01067 break;
01068
01069 default:
01070 uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
01071 uint dir;
01072 FOR_EACH_SET_BIT(dir, check_dirs) {
01073 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01074 Slope slope_dest = GetTileSlope(dest, NULL) & ~SLOPE_STEEP;
01075 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01076 MakeShore(tile);
01077 break;
01078 }
01079 }
01080 break;
01081 }
01082 }
01083 }
01084 }
01085
01086 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01087 {
01088 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01089
01090 TrackBits ts;
01091
01092 if (mode != TRANSPORT_WATER) return 0;
01093
01094 switch (GetWaterTileType(tile)) {
01095 case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01096 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
01097 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01098 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01099 default: return 0;
01100 }
01101 if (TileX(tile) == 0) {
01102
01103 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01104 }
01105 if (TileY(tile) == 0) {
01106
01107 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01108 }
01109 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01110 }
01111
01112 static bool ClickTile_Water(TileIndex tile)
01113 {
01114 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01115 TileIndex tile2 = GetOtherShipDepotTile(tile);
01116
01117 ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_SHIP);
01118 return true;
01119 }
01120 return false;
01121 }
01122
01123 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01124 {
01125 if (!IsTileOwner(tile, old_owner)) return;
01126
01127 if (new_owner != INVALID_OWNER) {
01128 SetTileOwner(tile, new_owner);
01129 return;
01130 }
01131
01132
01133 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01134
01135
01136
01137 if (IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
01138 }
01139
01140 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01141 {
01142 return VETSB_CONTINUE;
01143 }
01144
01145 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
01146 {
01147
01148 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_MUST_DEMOLISH_CANAL_FIRST);
01149
01150 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01151 }
01152
01153
01154 extern const TileTypeProcs _tile_type_water_procs = {
01155 DrawTile_Water,
01156 GetSlopeZ_Water,
01157 ClearTile_Water,
01158 GetAcceptedCargo_Water,
01159 GetTileDesc_Water,
01160 GetTileTrackStatus_Water,
01161 ClickTile_Water,
01162 NULL,
01163 TileLoop_Water,
01164 ChangeTileOwner_Water,
01165 NULL,
01166 VehicleEnter_Water,
01167 GetFoundation_Water,
01168 TerraformTile_Water,
01169 };