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 (GetTileSlope(tile) != SLOPE_FLAT || GetTileSlope(tile2) != SLOPE_FLAT) {
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 (GetTileSlope(tile - delta) != SLOPE_FLAT) {
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 (GetTileSlope(tile + delta) != SLOPE_FLAT) {
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 ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
00423 if (ret.Failed()) return ret;
00424 cost.AddCost(ret);
00425
00426 if (flags & DC_EXEC) {
00427 switch (wc) {
00428 case WATER_CLASS_RIVER:
00429 MakeRiver(tile, Random());
00430 if (_game_mode == GM_EDITOR) {
00431 TileIndex tile2 = tile;
00432 CircularTileSearch(&tile2, 5, RiverModifyDesertZone, NULL);
00433 }
00434 break;
00435
00436 case WATER_CLASS_SEA:
00437 if (TileHeight(tile) == 0) {
00438 MakeSea(tile);
00439 break;
00440 }
00441
00442
00443 default:
00444 MakeCanal(tile, _current_company, Random());
00445 if (Company::IsValidID(_current_company)) {
00446 Company::Get(_current_company)->infrastructure.water++;
00447 DirtyCompanyInfrastructureWindows(_current_company);
00448 }
00449 break;
00450 }
00451 MarkTileDirtyByTile(tile);
00452 MarkCanalsAndRiversAroundDirty(tile);
00453 }
00454
00455 cost.AddCost(_price[PR_BUILD_CANAL]);
00456 }
00457
00458 if (cost.GetCost() == 0) {
00459 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00460 } else {
00461 return cost;
00462 }
00463 }
00464
00465 static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
00466 {
00467 switch (GetWaterTileType(tile)) {
00468 case WATER_TILE_CLEAR: {
00469 if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00470
00471 Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
00472
00473 if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
00474 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
00475 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
00476 }
00477
00478
00479 CommandCost ret = EnsureNoVehicleOnGround(tile);
00480 if (ret.Failed()) return ret;
00481
00482 Owner owner = GetTileOwner(tile);
00483 if (owner != OWNER_WATER && owner != OWNER_NONE) {
00484 CommandCost ret = CheckTileOwnership(tile);
00485 if (ret.Failed()) return ret;
00486 }
00487
00488 if (flags & DC_EXEC) {
00489 if (IsCanal(tile) && Company::IsValidID(owner)) {
00490 Company::Get(owner)->infrastructure.water--;
00491 DirtyCompanyInfrastructureWindows(owner);
00492 }
00493 DoClearSquare(tile);
00494 MarkCanalsAndRiversAroundDirty(tile);
00495 }
00496
00497 return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
00498 }
00499
00500 case WATER_TILE_COAST: {
00501 Slope slope = GetTileSlope(tile);
00502
00503
00504 CommandCost ret = EnsureNoVehicleOnGround(tile);
00505 if (ret.Failed()) return ret;
00506
00507 if (flags & DC_EXEC) {
00508 DoClearSquare(tile);
00509 MarkCanalsAndRiversAroundDirty(tile);
00510 }
00511 if (IsSlopeWithOneCornerRaised(slope)) {
00512 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
00513 } else {
00514 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
00515 }
00516 }
00517
00518 case WATER_TILE_LOCK: {
00519 static const TileIndexDiffC _lock_tomiddle_offs[][DIAGDIR_END] = {
00520
00521 { { 0, 0}, {0, 0}, { 0, 0}, {0, 0} },
00522 { {-1, 0}, {0, 1}, { 1, 0}, {0, -1} },
00523 { { 1, 0}, {0, -1}, {-1, 0}, {0, 1} },
00524 };
00525
00526 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00527 if (_current_company == OWNER_WATER) return CMD_ERROR;
00528
00529 return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetLockPart(tile)][GetLockDirection(tile)]), flags);
00530 }
00531
00532 case WATER_TILE_DEPOT:
00533 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00534 return RemoveShipDepot(tile, flags);
00535
00536 default:
00537 NOT_REACHED();
00538 }
00539 }
00540
00549 static bool IsWateredTile(TileIndex tile, Direction from)
00550 {
00551 switch (GetTileType(tile)) {
00552 case MP_WATER:
00553 switch (GetWaterTileType(tile)) {
00554 default: NOT_REACHED();
00555 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
00556 case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from));
00557
00558 case WATER_TILE_COAST:
00559 switch (GetTileSlope(tile)) {
00560 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00561 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00562 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00563 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00564 default: return false;
00565 }
00566 }
00567
00568 case MP_RAILWAY:
00569 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
00570 assert(IsPlainRail(tile));
00571 switch (GetTileSlope(tile)) {
00572 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
00573 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
00574 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
00575 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
00576 default: return false;
00577 }
00578 }
00579 return false;
00580
00581 case MP_STATION:
00582 if (IsOilRig(tile)) {
00583
00584
00585 TileIndex src_tile = tile + TileOffsByDir(from);
00586 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00587 (IsTileType(src_tile, MP_INDUSTRY))) return true;
00588
00589 return IsTileOnWater(tile);
00590 }
00591 return (IsDock(tile) && GetTileSlope(tile) == SLOPE_FLAT) || IsBuoy(tile);
00592
00593 case MP_INDUSTRY: {
00594
00595
00596 TileIndex src_tile = tile + TileOffsByDir(from);
00597 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
00598 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
00599
00600 return IsTileOnWater(tile);
00601 }
00602
00603 case MP_OBJECT: return IsTileOnWater(tile);
00604
00605 case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from);
00606
00607 default: return false;
00608 }
00609 }
00610
00618 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
00619 {
00620 if (base != SPR_FLAT_WATER_TILE) {
00621
00622 offset = GetCanalSpriteOffset(feature, tile, offset);
00623 }
00624 DrawGroundSprite(base + offset, PAL_NONE);
00625 }
00626
00633 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
00634 {
00635 CanalFeature feature;
00636 SpriteID base = 0;
00637 if (canal) {
00638 feature = CF_DIKES;
00639 base = GetCanalSprite(CF_DIKES, tile);
00640 if (base == 0) base = SPR_CANAL_DIKES_BASE;
00641 } else {
00642 feature = CF_RIVER_EDGE;
00643 base = GetCanalSprite(CF_RIVER_EDGE, tile);
00644 if (base == 0) return;
00645 }
00646
00647 uint wa;
00648
00649
00650 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00651 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00652 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00653 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00654
00655 if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
00656 if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
00657 if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
00658 if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
00659
00660
00661 switch (wa & 0x03) {
00662 case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
00663 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
00664 }
00665
00666
00667 switch (wa & 0x06) {
00668 case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
00669 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
00670 }
00671
00672
00673 switch (wa & 0x0C) {
00674 case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
00675 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
00676 }
00677
00678
00679 switch (wa & 0x09) {
00680 case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
00681 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
00682 }
00683 }
00684
00686 static void DrawSeaWater(TileIndex tile)
00687 {
00688 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00689 }
00690
00692 static void DrawCanalWater(TileIndex tile)
00693 {
00694 SpriteID image = SPR_FLAT_WATER_TILE;
00695 if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00696
00697 image = GetCanalSprite(CF_WATERSLOPE, tile);
00698 if (image == 0) image = SPR_FLAT_WATER_TILE;
00699 }
00700 DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
00701
00702 DrawWaterEdges(true, 0, tile);
00703 }
00704
00705 #include "table/water_land.h"
00706
00716 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
00717 {
00718
00719 if (IsInvisibilitySet(TO_BUILDINGS)) return;
00720
00721 for (; !dtss->IsTerminator(); dtss++) {
00722 uint tile_offs = offset + dtss->image.sprite;
00723 if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
00724 AddSortableSpriteToDraw(base + tile_offs, palette,
00725 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
00726 dtss->size_x, dtss->size_y,
00727 dtss->size_z, ti->z + dtss->delta_z,
00728 IsTransparencySet(TO_BUILDINGS));
00729 }
00730 }
00731
00733 static void DrawWaterLock(const TileInfo *ti)
00734 {
00735 int part = GetLockPart(ti->tile);
00736 const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)];
00737
00738
00739 SpriteID image = dts.ground.sprite;
00740
00741 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00742 if (water_base == 0) {
00743
00744 water_base = SPR_CANALS_BASE;
00745 } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00746
00747 if (image == SPR_FLAT_WATER_TILE) {
00748 image = water_base;
00749 } else {
00750 image++;
00751 }
00752 }
00753
00754 if (image < 5) image += water_base;
00755 DrawGroundSprite(image, PAL_NONE);
00756
00757
00758 uint zoffs = 0;
00759 SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
00760
00761 if (base == 0) {
00762
00763 base = SPR_LOCK_BASE;
00764 uint8 z_threshold = part == LOCK_PART_UPPER ? 8 : 0;
00765 zoffs = ti->z > z_threshold ? 24 : 0;
00766 }
00767
00768 DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
00769 }
00770
00772 static void DrawWaterDepot(const TileInfo *ti)
00773 {
00774 DrawWaterClassGround(ti);
00775 DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
00776 }
00777
00778 static void DrawRiverWater(const TileInfo *ti)
00779 {
00780 SpriteID image = SPR_FLAT_WATER_TILE;
00781 uint offset = 0;
00782 uint edges_offset = 0;
00783
00784 if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00785 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00786 if (image == 0) {
00787 switch (ti->tileh) {
00788 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00789 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
00790 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
00791 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00792 default: image = SPR_FLAT_WATER_TILE; break;
00793 }
00794 } else {
00795
00796 offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
00797
00798 switch (ti->tileh) {
00799 case SLOPE_SE: edges_offset += 12; break;
00800 case SLOPE_NE: offset += 1; edges_offset += 24; break;
00801 case SLOPE_SW: offset += 2; edges_offset += 36; break;
00802 case SLOPE_NW: offset += 3; edges_offset += 48; break;
00803 default: offset = 0; break;
00804 }
00805
00806 offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
00807 }
00808 }
00809
00810 DrawGroundSprite(image + offset, PAL_NONE);
00811
00812
00813 DrawWaterEdges(false, edges_offset, ti->tile);
00814 }
00815
00816 void DrawShoreTile(Slope tileh)
00817 {
00818
00819
00820 static const byte tileh_to_shoresprite[32] = {
00821 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
00823 };
00824
00825 assert(!IsHalftileSlope(tileh));
00826 assert(tileh != SLOPE_FLAT);
00827
00828 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
00829
00830 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00831 }
00832
00833 void DrawWaterClassGround(const TileInfo *ti)
00834 {
00835 switch (GetWaterClass(ti->tile)) {
00836 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00837 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00838 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00839 default: NOT_REACHED();
00840 }
00841 }
00842
00843 static void DrawTile_Water(TileInfo *ti)
00844 {
00845 switch (GetWaterTileType(ti->tile)) {
00846 case WATER_TILE_CLEAR:
00847 DrawWaterClassGround(ti);
00848 DrawBridgeMiddle(ti);
00849 break;
00850
00851 case WATER_TILE_COAST: {
00852 DrawShoreTile(ti->tileh);
00853 DrawBridgeMiddle(ti);
00854 break;
00855 }
00856
00857 case WATER_TILE_LOCK:
00858 DrawWaterLock(ti);
00859 break;
00860
00861 case WATER_TILE_DEPOT:
00862 DrawWaterDepot(ti);
00863 break;
00864 }
00865 }
00866
00867 void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part)
00868 {
00869 const DrawTileSprites &dts = _shipdepot_display_data[axis][part];
00870
00871 DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
00872 DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
00873 }
00874
00875
00876 static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y)
00877 {
00878 int z;
00879 Slope tileh = GetTilePixelSlope(tile, &z);
00880
00881 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
00882 }
00883
00884 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00885 {
00886 return FOUNDATION_NONE;
00887 }
00888
00889 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00890 {
00891 switch (GetWaterTileType(tile)) {
00892 case WATER_TILE_CLEAR:
00893 switch (GetWaterClass(tile)) {
00894 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00895 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00896 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00897 default: NOT_REACHED(); break;
00898 }
00899 break;
00900 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00901 case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
00902 case WATER_TILE_DEPOT:
00903 td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
00904 td->build_date = Depot::GetByTile(tile)->build_date;
00905 break;
00906 default: NOT_REACHED(); break;
00907 }
00908
00909 td->owner[0] = GetTileOwner(tile);
00910 }
00911
00917 static void FloodVehicle(Vehicle *v)
00918 {
00919 uint pass = v->Crash(true);
00920
00921 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00922 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00923 SetDParam(0, pass);
00924 AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NT_ACCIDENT, v->index);
00925 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00926 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
00927 }
00928
00935 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00936 {
00937 if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
00938
00939 switch (v->type) {
00940 default: break;
00941
00942 case VEH_AIRCRAFT: {
00943 if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
00944 if (v->subtype == AIR_SHADOW) break;
00945
00946
00947
00948 const Station *st = Station::GetByTile(v->tile);
00949 const AirportFTAClass *airport = st->airport.GetFTA();
00950 if (v->z_pos != airport->delta_z + 1) break;
00951
00952 FloodVehicle(v);
00953 break;
00954 }
00955
00956 case VEH_TRAIN:
00957 case VEH_ROAD: {
00958 int z = *(int*)data;
00959 if (v->z_pos > z) break;
00960 FloodVehicle(v->First());
00961 break;
00962 }
00963 }
00964
00965 return NULL;
00966 }
00967
00973 static void FloodVehicles(TileIndex tile)
00974 {
00975 int z = 0;
00976
00977 if (IsAirportTile(tile)) {
00978 const Station *st = Station::GetByTile(tile);
00979 TILE_AREA_LOOP(tile, st->airport) {
00980 if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00981 }
00982
00983
00984 return;
00985 }
00986
00987 if (!IsBridgeTile(tile)) {
00988 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00989 return;
00990 }
00991
00992 TileIndex end = GetOtherBridgeEnd(tile);
00993 z = GetBridgePixelHeight(tile);
00994
00995 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00996 FindVehicleOnPos(end, &z, &FloodVehicleProc);
00997 }
00998
01004 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
01005 {
01006
01007
01008
01009
01010
01011 switch (GetTileType(tile)) {
01012 case MP_WATER:
01013 if (IsCoast(tile)) {
01014 Slope tileh = GetTileSlope(tile);
01015 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01016 }
01017
01018 case MP_STATION:
01019 case MP_INDUSTRY:
01020 case MP_OBJECT:
01021 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
01022
01023 case MP_RAILWAY:
01024 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
01025 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01026 }
01027 return FLOOD_NONE;
01028
01029 case MP_TREES:
01030 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
01031
01032 default:
01033 return FLOOD_NONE;
01034 }
01035 }
01036
01040 void DoFloodTile(TileIndex target)
01041 {
01042 assert(!IsTileType(target, MP_WATER));
01043
01044 bool flooded = false;
01045
01046 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01047
01048 Slope tileh = GetTileSlope(target);
01049 if (tileh != SLOPE_FLAT) {
01050
01051 switch (GetTileType(target)) {
01052 case MP_RAILWAY: {
01053 if (!IsPlainRail(target)) break;
01054 FloodVehicles(target);
01055 flooded = FloodHalftile(target);
01056 break;
01057 }
01058
01059 case MP_TREES:
01060 if (!IsSlopeWithOneCornerRaised(tileh)) {
01061 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
01062 MarkTileDirtyByTile(target);
01063 flooded = true;
01064 break;
01065 }
01066
01067
01068 case MP_CLEAR:
01069 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01070 MakeShore(target);
01071 MarkTileDirtyByTile(target);
01072 flooded = true;
01073 }
01074 break;
01075
01076 default:
01077 break;
01078 }
01079 } else {
01080
01081 FloodVehicles(target);
01082
01083
01084 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01085 MakeSea(target);
01086 MarkTileDirtyByTile(target);
01087 flooded = true;
01088 }
01089 }
01090
01091 if (flooded) {
01092
01093 MarkCanalsAndRiversAroundDirty(target);
01094
01095
01096 UpdateSignalsInBuffer();
01097 }
01098
01099 cur_company.Restore();
01100 }
01101
01105 static void DoDryUp(TileIndex tile)
01106 {
01107 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01108
01109 switch (GetTileType(tile)) {
01110 case MP_RAILWAY:
01111 assert(IsPlainRail(tile));
01112 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
01113
01114 RailGroundType new_ground;
01115 switch (GetTrackBits(tile)) {
01116 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
01117 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
01118 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
01119 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
01120 default: NOT_REACHED();
01121 }
01122 SetRailGroundType(tile, new_ground);
01123 MarkTileDirtyByTile(tile);
01124 break;
01125
01126 case MP_TREES:
01127 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
01128 MarkTileDirtyByTile(tile);
01129 break;
01130
01131 case MP_WATER:
01132 assert(IsCoast(tile));
01133
01134 if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01135 MakeClear(tile, CLEAR_GRASS, 3);
01136 MarkTileDirtyByTile(tile);
01137 }
01138 break;
01139
01140 default: NOT_REACHED();
01141 }
01142
01143 cur_company.Restore();
01144 }
01145
01152 void TileLoop_Water(TileIndex tile)
01153 {
01154 if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile);
01155
01156 switch (GetFloodingBehaviour(tile)) {
01157 case FLOOD_ACTIVE:
01158 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01159 TileIndex dest = tile + TileOffsByDir(dir);
01160 if (!IsValidTile(dest)) continue;
01161
01162 if (IsTileType(dest, MP_WATER)) continue;
01163
01164 int z_dest;
01165 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01166 if (z_dest > 0) continue;
01167
01168 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01169
01170 DoFloodTile(dest);
01171 }
01172 break;
01173
01174 case FLOOD_DRYUP: {
01175 Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01176 uint dir;
01177 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
01178 TileIndex dest = tile + TileOffsByDir((Direction)dir);
01179 if (!IsValidTile(dest)) continue;
01180
01181 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01182 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01183 }
01184 DoDryUp(tile);
01185 break;
01186 }
01187
01188 default: return;
01189 }
01190 }
01191
01192 void ConvertGroundTilesIntoWaterTiles()
01193 {
01194 int z;
01195
01196 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
01197 Slope slope = GetTileSlope(tile, &z);
01198 if (IsTileType(tile, MP_CLEAR) && z == 0) {
01199
01200
01201
01202 switch (slope) {
01203 case SLOPE_FLAT:
01204 MakeSea(tile);
01205 break;
01206
01207 case SLOPE_N:
01208 case SLOPE_E:
01209 case SLOPE_S:
01210 case SLOPE_W:
01211 MakeShore(tile);
01212 break;
01213
01214 default:
01215 uint dir;
01216 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
01217 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01218 Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
01219 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01220 MakeShore(tile);
01221 break;
01222 }
01223 }
01224 break;
01225 }
01226 }
01227 }
01228 }
01229
01230 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01231 {
01232 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01233
01234 TrackBits ts;
01235
01236 if (mode != TRANSPORT_WATER) return 0;
01237
01238 switch (GetWaterTileType(tile)) {
01239 case WATER_TILE_CLEAR: ts = (GetTileSlope(tile) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01240 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break;
01241 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01242 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01243 default: return 0;
01244 }
01245 if (TileX(tile) == 0) {
01246
01247 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01248 }
01249 if (TileY(tile) == 0) {
01250
01251 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01252 }
01253 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01254 }
01255
01256 static bool ClickTile_Water(TileIndex tile)
01257 {
01258 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01259 ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
01260 return true;
01261 }
01262 return false;
01263 }
01264
01265 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01266 {
01267 if (!IsTileOwner(tile, old_owner)) return;
01268
01269 bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
01270
01271
01272 if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR;
01273 if (new_owner != INVALID_OWNER) {
01274 if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR;
01275
01276
01277 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
01278 Company::Get(old_owner)->infrastructure.water--;
01279 Company::Get(new_owner)->infrastructure.water++;
01280 }
01281 if (IsShipDepot(tile)) {
01282 Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
01283 Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
01284 }
01285
01286 SetTileOwner(tile, new_owner);
01287 return;
01288 }
01289
01290
01291 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01292
01293
01294
01295 if (IsTileOwner(tile, old_owner)) {
01296 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
01297 SetTileOwner(tile, OWNER_NONE);
01298 }
01299 }
01300
01301 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01302 {
01303 return VETSB_CONTINUE;
01304 }
01305
01306 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
01307 {
01308
01309 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01310
01311 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01312 }
01313
01314
01315 extern const TileTypeProcs _tile_type_water_procs = {
01316 DrawTile_Water,
01317 GetSlopePixelZ_Water,
01318 ClearTile_Water,
01319 NULL,
01320 GetTileDesc_Water,
01321 GetTileTrackStatus_Water,
01322 ClickTile_Water,
01323 NULL,
01324 TileLoop_Water,
01325 ChangeTileOwner_Water,
01326 NULL,
01327 VehicleEnter_Water,
01328 GetFoundation_Water,
01329 TerraformTile_Water,
01330 };