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 "vehicle_func.h"
00026 #include "sound_func.h"
00027 #include "company_func.h"
00028 #include "clear_map.h"
00029 #include "tree_map.h"
00030 #include "aircraft.h"
00031 #include "effectvehicle_func.h"
00032 #include "tunnelbridge_map.h"
00033 #include "station_base.h"
00034 #include "ai/ai.hpp"
00035 #include "game/game.hpp"
00036 #include "core/random_func.hpp"
00037 #include "core/backup_type.hpp"
00038 #include "date_func.h"
00039 #include "company_base.h"
00040 #include "company_gui.h"
00041 #include "newgrf_generic.h"
00042
00043 #include "table/strings.h"
00044
00048 static const uint8 _flood_from_dirs[] = {
00049 (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE),
00050 (1 << DIR_NE) | (1 << DIR_SE),
00051 (1 << DIR_NW) | (1 << DIR_NE),
00052 (1 << DIR_NE),
00053 (1 << DIR_NW) | (1 << DIR_SW),
00054 0,
00055 (1 << DIR_NW),
00056 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),
00057 (1 << DIR_SW) | (1 << DIR_SE),
00058 (1 << DIR_SE),
00059 0,
00060 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),
00061 (1 << DIR_SW),
00062 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),
00063 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),
00064 };
00065
00072 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
00073 {
00074 if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
00075 }
00076
00083 static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
00084 {
00085 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
00086 MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
00087 }
00088 }
00089
00090
00100 CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00101 {
00102 Axis axis = Extract<Axis, 0, 1>(p1);
00103
00104 TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00105
00106 if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
00107 return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
00108 }
00109
00110 if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00111 (MayHaveBridgeAbove(tile2) && IsBridgeAbove(tile2))) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00112
00113 if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
00114
00115 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
00116 }
00117
00118 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00119
00120 WaterClass wc1 = GetWaterClass(tile);
00121 WaterClass wc2 = GetWaterClass(tile2);
00122 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
00123
00124 bool add_cost = !IsWaterTile(tile);
00125 CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00126 if (ret.Failed()) return ret;
00127 if (add_cost) {
00128 cost.AddCost(ret);
00129 }
00130 add_cost = !IsWaterTile(tile2);
00131 ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
00132 if (ret.Failed()) return ret;
00133 if (add_cost) {
00134 cost.AddCost(ret);
00135 }
00136
00137 if (flags & DC_EXEC) {
00138 Depot *depot = new Depot(tile);
00139 depot->build_date = _date;
00140
00141 if (wc1 == WATER_CLASS_CANAL || wc2 == WATER_CLASS_CANAL) {
00142
00143 Company::Get(_current_company)->infrastructure.water += wc1 == WATER_CLASS_CANAL && wc2 == WATER_CLASS_CANAL ? 2 : 1;
00144 }
00145 Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR;
00146 DirtyCompanyInfrastructureWindows(_current_company);
00147
00148 MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
00149 MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
00150 MarkTileDirtyByTile(tile);
00151 MarkTileDirtyByTile(tile2);
00152 MakeDefaultName(depot);
00153 }
00154
00155 return cost;
00156 }
00157
00158 void MakeWaterKeepingClass(TileIndex tile, Owner o)
00159 {
00160 WaterClass wc = GetWaterClass(tile);
00161
00162
00163 int z;
00164 Slope slope = GetTileSlope(tile, &z);
00165
00166 if (slope != SLOPE_FLAT) {
00167 if (wc == WATER_CLASS_CANAL) {
00168
00169 Company *c = Company::GetIfValid(o);
00170 if (c != NULL) {
00171 c->infrastructure.water--;
00172 DirtyCompanyInfrastructureWindows(c->index);
00173 }
00174
00175 wc = WATER_CLASS_INVALID;
00176 }
00177
00178
00179 if (wc != WATER_CLASS_RIVER || GetInclinedSlopeDirection(slope) == INVALID_DIAGDIR) {
00180 wc = WATER_CLASS_INVALID;
00181 }
00182 }
00183
00184 if (wc == WATER_CLASS_SEA && z > 0) {
00185
00186 Company *c = Company::GetIfValid(o);
00187 if (c != NULL) {
00188 c->infrastructure.water++;
00189 DirtyCompanyInfrastructureWindows(c->index);
00190 }
00191
00192 wc = WATER_CLASS_CANAL;
00193 }
00194
00195
00196 DoClearSquare(tile);
00197
00198
00199 switch (wc) {
00200 case WATER_CLASS_SEA: MakeSea(tile); break;
00201 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
00202 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
00203 default: break;
00204 }
00205
00206 MarkTileDirtyByTile(tile);
00207 }
00208
00209 static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
00210 {
00211 if (!IsShipDepot(tile)) return CMD_ERROR;
00212
00213 CommandCost ret = CheckTileOwnership(tile);
00214 if (ret.Failed()) return ret;
00215
00216 TileIndex tile2 = GetOtherShipDepotTile(tile);
00217
00218
00219 if (!(flags & DC_BANKRUPT)) {
00220 CommandCost ret = EnsureNoVehicleOnGround(tile);
00221 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
00222 if (ret.Failed()) return ret;
00223 }
00224
00225 if (flags & DC_EXEC) {
00226 delete Depot::GetByTile(tile);
00227
00228 Company *c = Company::GetIfValid(GetTileOwner(tile));
00229 if (c != NULL) {
00230 c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR;
00231 DirtyCompanyInfrastructureWindows(c->index);
00232 }
00233
00234 MakeWaterKeepingClass(tile, GetTileOwner(tile));
00235 MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
00236 }
00237
00238 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
00239 }
00240
00248 static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag flags)
00249 {
00250 CommandCost cost(EXPENSES_CONSTRUCTION);
00251
00252 int delta = TileOffsByDiagDir(dir);
00253 CommandCost ret = EnsureNoVehicleOnGround(tile);
00254 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
00255 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
00256 if (ret.Failed()) return ret;
00257
00258
00259 WaterClass wc_middle = IsWaterTile(tile) ? GetWaterClass(tile) : WATER_CLASS_CANAL;
00260 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00261 if (ret.Failed()) return ret;
00262 cost.AddCost(ret);
00263
00264
00265 WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
00266
00267 if (!IsWaterTile(tile - delta)) {
00268 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00269 if (ret.Failed()) return ret;
00270 cost.AddCost(ret);
00271 cost.AddCost(_price[PR_BUILD_CANAL]);
00272 }
00273 if (!IsTileFlat(tile - delta)) {
00274 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00275 }
00276
00277
00278 WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
00279
00280 if (!IsWaterTile(tile + delta)) {
00281 ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00282 if (ret.Failed()) return ret;
00283 cost.AddCost(ret);
00284 cost.AddCost(_price[PR_BUILD_CANAL]);
00285 }
00286 if (!IsTileFlat(tile + delta)) {
00287 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00288 }
00289
00290 if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
00291 (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
00292 (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
00293 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00294 }
00295
00296 if (flags & DC_EXEC) {
00297
00298 Company *c = Company::GetIfValid(_current_company);
00299 if (c != NULL) {
00300
00301 if (!IsWaterTile(tile - delta)) c->infrastructure.water++;
00302 if (!IsWaterTile(tile + delta)) c->infrastructure.water++;
00303
00304 c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR;
00305 DirtyCompanyInfrastructureWindows(_current_company);
00306 }
00307
00308 MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
00309 MarkTileDirtyByTile(tile);
00310 MarkTileDirtyByTile(tile - delta);
00311 MarkTileDirtyByTile(tile + delta);
00312 MarkCanalsAndRiversAroundDirty(tile - delta);
00313 MarkCanalsAndRiversAroundDirty(tile + delta);
00314 }
00315 cost.AddCost(_price[PR_BUILD_LOCK]);
00316
00317 return cost;
00318 }
00319
00326 static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags)
00327 {
00328 if (GetTileOwner(tile) != OWNER_NONE) {
00329 CommandCost ret = CheckTileOwnership(tile);
00330 if (ret.Failed()) return ret;
00331 }
00332
00333 TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
00334
00335
00336 CommandCost ret = EnsureNoVehicleOnGround(tile);
00337 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
00338 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
00339 if (ret.Failed()) return ret;
00340
00341 if (flags & DC_EXEC) {
00342
00343 Company *c = Company::GetIfValid(GetTileOwner(tile));
00344 if (c != NULL) {
00345 c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR;
00346 DirtyCompanyInfrastructureWindows(c->index);
00347 }
00348
00349 if (GetWaterClass(tile) == WATER_CLASS_RIVER) {
00350 MakeRiver(tile, Random());
00351 } else {
00352 DoClearSquare(tile);
00353 }
00354 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta));
00355 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
00356 MarkCanalsAndRiversAroundDirty(tile);
00357 MarkCanalsAndRiversAroundDirty(tile - delta);
00358 MarkCanalsAndRiversAroundDirty(tile + delta);
00359 }
00360
00361 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
00362 }
00363
00373 CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00374 {
00375 DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
00376 if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00377
00378 return DoBuildLock(tile, dir, flags);
00379 }
00380
00382 bool RiverModifyDesertZone(TileIndex tile, void *)
00383 {
00384 if (GetTropicZone(tile) == TROPICZONE_DESERT) SetTropicZone(tile, TROPICZONE_NORMAL);
00385 return false;
00386 }
00387
00397 CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00398 {
00399 WaterClass wc = Extract<WaterClass, 0, 2>(p2);
00400 if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
00401
00402
00403 if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
00404
00405 TileArea ta(tile, p1);
00406
00407
00408 if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
00409
00410 CommandCost cost(EXPENSES_CONSTRUCTION);
00411 TILE_AREA_LOOP(tile, ta) {
00412 CommandCost ret;
00413
00414 Slope slope = GetTileSlope(tile);
00415 if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
00416 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00417 }
00418
00419
00420 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
00421
00422 bool water = IsWaterTile(tile);
00423 ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
00424 if (ret.Failed()) return ret;
00425
00426 if (!water) cost.AddCost(ret);
00427
00428 if (flags & DC_EXEC) {
00429 switch (wc) {
00430 case WATER_CLASS_RIVER:
00431 MakeRiver(tile, Random());
00432 if (_game_mode == GM_EDITOR) {
00433 TileIndex tile2 = tile;
00434 CircularTileSearch(&tile2, 5, RiverModifyDesertZone, NULL);
00435 }
00436 break;
00437
00438 case WATER_CLASS_SEA:
00439 if (TileHeight(tile) == 0) {
00440 MakeSea(tile);
00441 break;
00442 }
00443
00444
00445 default:
00446 MakeCanal(tile, _current_company, Random());
00447 if (Company::IsValidID(_current_company)) {
00448 Company::Get(_current_company)->infrastructure.water++;
00449 DirtyCompanyInfrastructureWindows(_current_company);
00450 }
00451 break;
00452 }
00453 MarkTileDirtyByTile(tile);
00454 MarkCanalsAndRiversAroundDirty(tile);
00455 }
00456
00457 cost.AddCost(_price[PR_BUILD_CANAL]);
00458 }
00459
00460 if (cost.GetCost() == 0) {
00461 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00462 } else {
00463 return cost;
00464 }
00465 }
00466
00467 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00468 {
00469 switch (GetWaterTileType(tile)) {
00470 case WATER_TILE_CLEAR: {
00471 if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00472
00473 Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
00474
00475 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00476 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00477 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00478 }
00479
00480
00481 CommandCost ret = EnsureNoVehicleOnGround(tile);
00482 if (ret.Failed()) return ret;
00483
00484 Owner owner = GetTileOwner(tile);
00485 if (owner != OWNER_WATER && owner != OWNER_NONE) {
00486 CommandCost ret = CheckTileOwnership(tile);
00487 if (ret.Failed()) return ret;
00488 }
00489
00490 if (flags & DC_EXEC) {
00491 if (IsCanal(tile) && Company::IsValidID(owner)) {
00492 Company::Get(owner)->infrastructure.water--;
00493 DirtyCompanyInfrastructureWindows(owner);
00494 }
00495 DoClearSquare(tile);
00496 MarkCanalsAndRiversAroundDirty(tile);
00497 }
00498
00499 return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
00500 }
00501
00502 case WATER_TILE_COAST: {
00503 Slope slope = GetTileSlope(tile);
00504
00505
00506 CommandCost ret = EnsureNoVehicleOnGround(tile);
00507 if (ret.Failed()) return ret;
00508
00509 if (flags & DC_EXEC) {
00510 DoClearSquare(tile);
00511 MarkCanalsAndRiversAroundDirty(tile);
00512 }
00513 if (IsSlopeWithOneCornerRaised(slope)) {
00514 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00515 } else {
00516 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00517 }
00518 }
00519
00520 case WATER_TILE_LOCK: {
00521 static const TileIndexDiffC _lock_tomiddle_offs[][DIAGDIR_END] = {
00522
00523 { { 0, 0}, {0, 0}, { 0, 0}, {0, 0} },
00524 { {-1, 0}, {0, 1}, { 1, 0}, {0, -1} },
00525 { { 1, 0}, {0, -1}, {-1, 0}, {0, 1} },
00526 };
00527
00528 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00529 if (_current_company == OWNER_WATER) return CMD_ERROR;
00530
00531 return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetLockPart(tile)][GetLockDirection(tile)]), flags);
00532 }
00533
00534 case WATER_TILE_DEPOT:
00535 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00536 return RemoveShipDepot(tile, flags);
00537
00538 default:
00539 NOT_REACHED();
00540 }
00541 }
00542
00551 bool IsWateredTile(TileIndex tile, Direction from)
00552 {
00553 switch (GetTileType(tile)) {
00554 case MP_WATER:
00555 switch (GetWaterTileType(tile)) {
00556 default: NOT_REACHED();
00557 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00558 case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00559
00560 case WATER_TILE_COAST:
00561 switch (GetTileSlope(tile)) {
00562 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00563 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00564 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00565 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00566 default: return false;
00567 }
00568 }
00569
00570 case MP_RAILWAY:
00571 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00572 assert(IsPlainRail(tile));
00573 switch (GetTileSlope(tile)) {
00574 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00575 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00576 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00577 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00578 default: return false;
00579 }
00580 }
00581 return false;
00582
00583 case MP_STATION:
00584 if (IsOilRig(tile)) {
00585
00586
00587 TileIndex src_tile = tile + TileOffsByDir(from);
00588 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00589 (IsTileType(src_tile, MP_INDUSTRY))) return true;
00590
00591 return IsTileOnWater(tile);
00592 }
00593 return (IsDock(tile) && IsTileFlat(tile)) || IsBuoy(tile);
00594
00595 case MP_INDUSTRY: {
00596
00597
00598 TileIndex src_tile = tile + TileOffsByDir(from);
00599 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00600 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00601
00602 return IsTileOnWater(tile);
00603 }
00604
00605 case MP_OBJECT: return IsTileOnWater(tile);
00606
00607 case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00608
00609 case MP_VOID: return true;
00610
00611 default: return false;
00612 }
00613 }
00614
00622 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
00623 {
00624 if (base != SPR_FLAT_WATER_TILE) {
00625
00626 offset = GetCanalSpriteOffset(feature, tile, offset);
00627 }
00628 DrawGroundSprite(base + offset, PAL_NONE);
00629 }
00630
00637 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
00638 {
00639 CanalFeature feature;
00640 SpriteID base = 0;
00641 if (canal) {
00642 feature = CF_DIKES;
00643 base = GetCanalSprite(CF_DIKES, tile);
00644 if (base == 0) base = SPR_CANAL_DIKES_BASE;
00645 } else {
00646 feature = CF_RIVER_EDGE;
00647 base = GetCanalSprite(CF_RIVER_EDGE, tile);
00648 if (base == 0) return;
00649 }
00650
00651 uint wa;
00652
00653
00654 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00655 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00656 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00657 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00658
00659 if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
00660 if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
00661 if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
00662 if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
00663
00664
00665 switch (wa & 0x03) {
00666 case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
00667 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
00668 }
00669
00670
00671 switch (wa & 0x06) {
00672 case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
00673 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
00674 }
00675
00676
00677 switch (wa & 0x0C) {
00678 case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
00679 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
00680 }
00681
00682
00683 switch (wa & 0x09) {
00684 case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
00685 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
00686 }
00687 }
00688
00690 static void DrawSeaWater(TileIndex tile)
00691 {
00692 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00693 }
00694
00696 static void DrawCanalWater(TileIndex tile)
00697 {
00698 SpriteID image = SPR_FLAT_WATER_TILE;
00699 if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00700
00701 image = GetCanalSprite(CF_WATERSLOPE, tile);
00702 if (image == 0) image = SPR_FLAT_WATER_TILE;
00703 }
00704 DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
00705
00706 DrawWaterEdges(true, 0, tile);
00707 }
00708
00709 #include "table/water_land.h"
00710
00720 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
00721 {
00722
00723 if (IsInvisibilitySet(TO_BUILDINGS)) return;
00724
00725 for (; !dtss->IsTerminator(); dtss++) {
00726 uint tile_offs = offset + dtss->image.sprite;
00727 if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
00728 AddSortableSpriteToDraw(base + tile_offs, palette,
00729 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
00730 dtss->size_x, dtss->size_y,
00731 dtss->size_z, ti->z + dtss->delta_z,
00732 IsTransparencySet(TO_BUILDINGS));
00733 }
00734 }
00735
00737 static void DrawWaterLock(const TileInfo *ti)
00738 {
00739 int part = GetLockPart(ti->tile);
00740 const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)];
00741
00742
00743 SpriteID image = dts.ground.sprite;
00744
00745 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00746 if (water_base == 0) {
00747
00748 water_base = SPR_CANALS_BASE;
00749 } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00750
00751 if (image == SPR_FLAT_WATER_TILE) {
00752 image = water_base;
00753 } else {
00754 image++;
00755 }
00756 }
00757
00758 if (image < 5) image += water_base;
00759 DrawGroundSprite(image, PAL_NONE);
00760
00761
00762 uint zoffs = 0;
00763 SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
00764
00765 if (base == 0) {
00766
00767 base = SPR_LOCK_BASE;
00768 uint8 z_threshold = part == LOCK_PART_UPPER ? 8 : 0;
00769 zoffs = ti->z > z_threshold ? 24 : 0;
00770 }
00771
00772 DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
00773 }
00774
00776 static void DrawWaterDepot(const TileInfo *ti)
00777 {
00778 DrawWaterClassGround(ti);
00779 DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
00780 }
00781
00782 static void DrawRiverWater(const TileInfo *ti)
00783 {
00784 SpriteID image = SPR_FLAT_WATER_TILE;
00785 uint offset = 0;
00786 uint edges_offset = 0;
00787
00788 if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00789 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00790 if (image == 0) {
00791 switch (ti->tileh) {
00792 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00793 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
00794 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
00795 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00796 default: image = SPR_FLAT_WATER_TILE; break;
00797 }
00798 } else {
00799
00800 offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
00801
00802 switch (ti->tileh) {
00803 case SLOPE_SE: edges_offset += 12; break;
00804 case SLOPE_NE: offset += 1; edges_offset += 24; break;
00805 case SLOPE_SW: offset += 2; edges_offset += 36; break;
00806 case SLOPE_NW: offset += 3; edges_offset += 48; break;
00807 default: offset = 0; break;
00808 }
00809
00810 offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
00811 }
00812 }
00813
00814 DrawGroundSprite(image + offset, PAL_NONE);
00815
00816
00817 DrawWaterEdges(false, edges_offset, ti->tile);
00818 }
00819
00820 void DrawShoreTile(Slope tileh)
00821 {
00822
00823
00824 static const byte tileh_to_shoresprite[32] = {
00825 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
00827 };
00828
00829 assert(!IsHalftileSlope(tileh));
00830 assert(tileh != SLOPE_FLAT);
00831
00832 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
00833
00834 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00835 }
00836
00837 void DrawWaterClassGround(const TileInfo *ti)
00838 {
00839 switch (GetWaterClass(ti->tile)) {
00840 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00841 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00842 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00843 default: NOT_REACHED();
00844 }
00845 }
00846
00847 static void DrawTile_Water(TileInfo *ti)
00848 {
00849 switch (GetWaterTileType(ti->tile)) {
00850 case WATER_TILE_CLEAR:
00851 DrawWaterClassGround(ti);
00852 DrawBridgeMiddle(ti);
00853 break;
00854
00855 case WATER_TILE_COAST: {
00856 DrawShoreTile(ti->tileh);
00857 DrawBridgeMiddle(ti);
00858 break;
00859 }
00860
00861 case WATER_TILE_LOCK:
00862 DrawWaterLock(ti);
00863 break;
00864
00865 case WATER_TILE_DEPOT:
00866 DrawWaterDepot(ti);
00867 break;
00868 }
00869 }
00870
00871 void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part)
00872 {
00873 const DrawTileSprites &dts = _shipdepot_display_data[axis][part];
00874
00875 DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
00876 DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
00877 }
00878
00879
00880 static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y)
00881 {
00882 int z;
00883 Slope tileh = GetTilePixelSlope(tile, &z);
00884
00885 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
00886 }
00887
00888 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00889 {
00890 return FOUNDATION_NONE;
00891 }
00892
00893 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00894 {
00895 switch (GetWaterTileType(tile)) {
00896 case WATER_TILE_CLEAR:
00897 switch (GetWaterClass(tile)) {
00898 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00899 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00900 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00901 default: NOT_REACHED(); break;
00902 }
00903 break;
00904 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00905 case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
00906 case WATER_TILE_DEPOT:
00907 td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
00908 td->build_date = Depot::GetByTile(tile)->build_date;
00909 break;
00910 default: NOT_REACHED(); break;
00911 }
00912
00913 td->owner[0] = GetTileOwner(tile);
00914 }
00915
00921 static void FloodVehicle(Vehicle *v)
00922 {
00923 uint pass = v->Crash(true);
00924
00925 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00926 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00927 SetDParam(0, pass);
00928 AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NT_ACCIDENT, v->index);
00929 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00930 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
00931 }
00932
00939 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00940 {
00941 if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
00942
00943 switch (v->type) {
00944 default: break;
00945
00946 case VEH_AIRCRAFT: {
00947 if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
00948 if (v->subtype == AIR_SHADOW) break;
00949
00950
00951
00952 const Station *st = Station::GetByTile(v->tile);
00953 const AirportFTAClass *airport = st->airport.GetFTA();
00954 if (v->z_pos != airport->delta_z + 1) break;
00955
00956 FloodVehicle(v);
00957 break;
00958 }
00959
00960 case VEH_TRAIN:
00961 case VEH_ROAD: {
00962 int z = *(int*)data;
00963 if (v->z_pos > z) break;
00964 FloodVehicle(v->First());
00965 break;
00966 }
00967 }
00968
00969 return NULL;
00970 }
00971
00977 static void FloodVehicles(TileIndex tile)
00978 {
00979 int z = 0;
00980
00981 if (IsAirportTile(tile)) {
00982 const Station *st = Station::GetByTile(tile);
00983 TILE_AREA_LOOP(tile, st->airport) {
00984 if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00985 }
00986
00987
00988 return;
00989 }
00990
00991 if (!IsBridgeTile(tile)) {
00992 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00993 return;
00994 }
00995
00996 TileIndex end = GetOtherBridgeEnd(tile);
00997 z = GetBridgePixelHeight(tile);
00998
00999 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
01000 FindVehicleOnPos(end, &z, &FloodVehicleProc);
01001 }
01002
01008 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
01009 {
01010
01011
01012
01013
01014
01015 switch (GetTileType(tile)) {
01016 case MP_WATER:
01017 if (IsCoast(tile)) {
01018 Slope tileh = GetTileSlope(tile);
01019 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01020 }
01021
01022 case MP_STATION:
01023 case MP_INDUSTRY:
01024 case MP_OBJECT:
01025 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
01026
01027 case MP_RAILWAY:
01028 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
01029 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01030 }
01031 return FLOOD_NONE;
01032
01033 case MP_TREES:
01034 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
01035
01036 default:
01037 return FLOOD_NONE;
01038 }
01039 }
01040
01044 void DoFloodTile(TileIndex target)
01045 {
01046 assert(!IsTileType(target, MP_WATER));
01047
01048 bool flooded = false;
01049
01050 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01051
01052 Slope tileh = GetTileSlope(target);
01053 if (tileh != SLOPE_FLAT) {
01054
01055 switch (GetTileType(target)) {
01056 case MP_RAILWAY: {
01057 if (!IsPlainRail(target)) break;
01058 FloodVehicles(target);
01059 flooded = FloodHalftile(target);
01060 break;
01061 }
01062
01063 case MP_TREES:
01064 if (!IsSlopeWithOneCornerRaised(tileh)) {
01065 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
01066 MarkTileDirtyByTile(target);
01067 flooded = true;
01068 break;
01069 }
01070
01071
01072 case MP_CLEAR:
01073 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01074 MakeShore(target);
01075 MarkTileDirtyByTile(target);
01076 flooded = true;
01077 }
01078 break;
01079
01080 default:
01081 break;
01082 }
01083 } else {
01084
01085 FloodVehicles(target);
01086
01087
01088 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01089 MakeSea(target);
01090 MarkTileDirtyByTile(target);
01091 flooded = true;
01092 }
01093 }
01094
01095 if (flooded) {
01096
01097 MarkCanalsAndRiversAroundDirty(target);
01098
01099
01100 UpdateSignalsInBuffer();
01101 }
01102
01103 cur_company.Restore();
01104 }
01105
01109 static void DoDryUp(TileIndex tile)
01110 {
01111 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01112
01113 switch (GetTileType(tile)) {
01114 case MP_RAILWAY:
01115 assert(IsPlainRail(tile));
01116 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
01117
01118 RailGroundType new_ground;
01119 switch (GetTrackBits(tile)) {
01120 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
01121 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
01122 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
01123 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
01124 default: NOT_REACHED();
01125 }
01126 SetRailGroundType(tile, new_ground);
01127 MarkTileDirtyByTile(tile);
01128 break;
01129
01130 case MP_TREES:
01131 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
01132 MarkTileDirtyByTile(tile);
01133 break;
01134
01135 case MP_WATER:
01136 assert(IsCoast(tile));
01137
01138 if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01139 MakeClear(tile, CLEAR_GRASS, 3);
01140 MarkTileDirtyByTile(tile);
01141 }
01142 break;
01143
01144 default: NOT_REACHED();
01145 }
01146
01147 cur_company.Restore();
01148 }
01149
01156 void TileLoop_Water(TileIndex tile)
01157 {
01158 if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile);
01159
01160 switch (GetFloodingBehaviour(tile)) {
01161 case FLOOD_ACTIVE:
01162 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01163 TileIndex dest = tile + TileOffsByDir(dir);
01164 if (!IsValidTile(dest)) continue;
01165
01166 if (IsTileType(dest, MP_WATER)) continue;
01167
01168 int z_dest;
01169 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01170 if (z_dest > 0) continue;
01171
01172 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01173
01174 DoFloodTile(dest);
01175 }
01176 break;
01177
01178 case FLOOD_DRYUP: {
01179 Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01180 uint dir;
01181 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
01182 TileIndex dest = tile + TileOffsByDir((Direction)dir);
01183 if (!IsValidTile(dest)) continue;
01184
01185 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01186 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01187 }
01188 DoDryUp(tile);
01189 break;
01190 }
01191
01192 default: return;
01193 }
01194 }
01195
01196 void ConvertGroundTilesIntoWaterTiles()
01197 {
01198 int z;
01199
01200 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
01201 Slope slope = GetTileSlope(tile, &z);
01202 if (IsTileType(tile, MP_CLEAR) && z == 0) {
01203
01204
01205
01206 switch (slope) {
01207 case SLOPE_FLAT:
01208 MakeSea(tile);
01209 break;
01210
01211 case SLOPE_N:
01212 case SLOPE_E:
01213 case SLOPE_S:
01214 case SLOPE_W:
01215 MakeShore(tile);
01216 break;
01217
01218 default:
01219 uint dir;
01220 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
01221 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01222 Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
01223 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01224 MakeShore(tile);
01225 break;
01226 }
01227 }
01228 break;
01229 }
01230 }
01231 }
01232 }
01233
01234 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01235 {
01236 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01237
01238 TrackBits ts;
01239
01240 if (mode != TRANSPORT_WATER) return 0;
01241
01242 switch (GetWaterTileType(tile)) {
01243 case WATER_TILE_CLEAR: ts = IsTileFlat(tile) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01244 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break;
01245 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01246 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01247 default: return 0;
01248 }
01249 if (TileX(tile) == 0) {
01250
01251 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01252 }
01253 if (TileY(tile) == 0) {
01254
01255 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01256 }
01257 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01258 }
01259
01260 static bool ClickTile_Water(TileIndex tile)
01261 {
01262 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01263 ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
01264 return true;
01265 }
01266 return false;
01267 }
01268
01269 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01270 {
01271 if (!IsTileOwner(tile, old_owner)) return;
01272
01273 bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
01274
01275
01276 if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR;
01277 if (new_owner != INVALID_OWNER) {
01278 if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR;
01279
01280
01281 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
01282 Company::Get(old_owner)->infrastructure.water--;
01283 Company::Get(new_owner)->infrastructure.water++;
01284 }
01285 if (IsShipDepot(tile)) {
01286 Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
01287 Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
01288 }
01289
01290 SetTileOwner(tile, new_owner);
01291 return;
01292 }
01293
01294
01295 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01296
01297
01298
01299 if (IsTileOwner(tile, old_owner)) {
01300 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
01301 SetTileOwner(tile, OWNER_NONE);
01302 }
01303 }
01304
01305 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01306 {
01307 return VETSB_CONTINUE;
01308 }
01309
01310 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
01311 {
01312
01313 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01314
01315 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01316 }
01317
01318
01319 extern const TileTypeProcs _tile_type_water_procs = {
01320 DrawTile_Water,
01321 GetSlopePixelZ_Water,
01322 ClearTile_Water,
01323 NULL,
01324 GetTileDesc_Water,
01325 GetTileTrackStatus_Water,
01326 ClickTile_Water,
01327 NULL,
01328 TileLoop_Water,
01329 ChangeTileOwner_Water,
01330 NULL,
01331 VehicleEnter_Water,
01332 GetFoundation_Water,
01333 TerraformTile_Water,
01334 };