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 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 static 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) && GetTileSlope(tile) == SLOPE_FLAT) || 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 default: return false;
00610 }
00611 }
00612
00620 static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
00621 {
00622 if (base != SPR_FLAT_WATER_TILE) {
00623
00624 offset = GetCanalSpriteOffset(feature, tile, offset);
00625 }
00626 DrawGroundSprite(base + offset, PAL_NONE);
00627 }
00628
00635 static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
00636 {
00637 CanalFeature feature;
00638 SpriteID base = 0;
00639 if (canal) {
00640 feature = CF_DIKES;
00641 base = GetCanalSprite(CF_DIKES, tile);
00642 if (base == 0) base = SPR_CANAL_DIKES_BASE;
00643 } else {
00644 feature = CF_RIVER_EDGE;
00645 base = GetCanalSprite(CF_RIVER_EDGE, tile);
00646 if (base == 0) return;
00647 }
00648
00649 uint wa;
00650
00651
00652 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0;
00653 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1;
00654 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2;
00655 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3;
00656
00657 if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
00658 if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
00659 if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
00660 if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
00661
00662
00663 switch (wa & 0x03) {
00664 case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
00665 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
00666 }
00667
00668
00669 switch (wa & 0x06) {
00670 case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
00671 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
00672 }
00673
00674
00675 switch (wa & 0x0C) {
00676 case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
00677 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
00678 }
00679
00680
00681 switch (wa & 0x09) {
00682 case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
00683 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
00684 }
00685 }
00686
00688 static void DrawSeaWater(TileIndex tile)
00689 {
00690 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
00691 }
00692
00694 static void DrawCanalWater(TileIndex tile)
00695 {
00696 SpriteID image = SPR_FLAT_WATER_TILE;
00697 if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00698
00699 image = GetCanalSprite(CF_WATERSLOPE, tile);
00700 if (image == 0) image = SPR_FLAT_WATER_TILE;
00701 }
00702 DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
00703
00704 DrawWaterEdges(true, 0, tile);
00705 }
00706
00707 #include "table/water_land.h"
00708
00718 static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
00719 {
00720
00721 if (IsInvisibilitySet(TO_BUILDINGS)) return;
00722
00723 for (; !dtss->IsTerminator(); dtss++) {
00724 uint tile_offs = offset + dtss->image.sprite;
00725 if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
00726 AddSortableSpriteToDraw(base + tile_offs, palette,
00727 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
00728 dtss->size_x, dtss->size_y,
00729 dtss->size_z, ti->z + dtss->delta_z,
00730 IsTransparencySet(TO_BUILDINGS));
00731 }
00732 }
00733
00735 static void DrawWaterLock(const TileInfo *ti)
00736 {
00737 int part = GetLockPart(ti->tile);
00738 const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)];
00739
00740
00741 SpriteID image = dts.ground.sprite;
00742
00743 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
00744 if (water_base == 0) {
00745
00746 water_base = SPR_CANALS_BASE;
00747 } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00748
00749 if (image == SPR_FLAT_WATER_TILE) {
00750 image = water_base;
00751 } else {
00752 image++;
00753 }
00754 }
00755
00756 if (image < 5) image += water_base;
00757 DrawGroundSprite(image, PAL_NONE);
00758
00759
00760 uint zoffs = 0;
00761 SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
00762
00763 if (base == 0) {
00764
00765 base = SPR_LOCK_BASE;
00766 uint8 z_threshold = part == LOCK_PART_UPPER ? 8 : 0;
00767 zoffs = ti->z > z_threshold ? 24 : 0;
00768 }
00769
00770 DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS);
00771 }
00772
00774 static void DrawWaterDepot(const TileInfo *ti)
00775 {
00776 DrawWaterClassGround(ti);
00777 DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END);
00778 }
00779
00780 static void DrawRiverWater(const TileInfo *ti)
00781 {
00782 SpriteID image = SPR_FLAT_WATER_TILE;
00783 uint offset = 0;
00784 uint edges_offset = 0;
00785
00786 if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
00787 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
00788 if (image == 0) {
00789 switch (ti->tileh) {
00790 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
00791 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
00792 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
00793 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
00794 default: image = SPR_FLAT_WATER_TILE; break;
00795 }
00796 } else {
00797
00798 offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
00799
00800 switch (ti->tileh) {
00801 case SLOPE_SE: edges_offset += 12; break;
00802 case SLOPE_NE: offset += 1; edges_offset += 24; break;
00803 case SLOPE_SW: offset += 2; edges_offset += 36; break;
00804 case SLOPE_NW: offset += 3; edges_offset += 48; break;
00805 default: offset = 0; break;
00806 }
00807
00808 offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
00809 }
00810 }
00811
00812 DrawGroundSprite(image + offset, PAL_NONE);
00813
00814
00815 DrawWaterEdges(false, edges_offset, ti->tile);
00816 }
00817
00818 void DrawShoreTile(Slope tileh)
00819 {
00820
00821
00822 static const byte tileh_to_shoresprite[32] = {
00823 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
00824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
00825 };
00826
00827 assert(!IsHalftileSlope(tileh));
00828 assert(tileh != SLOPE_FLAT);
00829
00830 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS));
00831
00832 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
00833 }
00834
00835 void DrawWaterClassGround(const TileInfo *ti)
00836 {
00837 switch (GetWaterClass(ti->tile)) {
00838 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
00839 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
00840 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
00841 default: NOT_REACHED();
00842 }
00843 }
00844
00845 static void DrawTile_Water(TileInfo *ti)
00846 {
00847 switch (GetWaterTileType(ti->tile)) {
00848 case WATER_TILE_CLEAR:
00849 DrawWaterClassGround(ti);
00850 DrawBridgeMiddle(ti);
00851 break;
00852
00853 case WATER_TILE_COAST: {
00854 DrawShoreTile(ti->tileh);
00855 DrawBridgeMiddle(ti);
00856 break;
00857 }
00858
00859 case WATER_TILE_LOCK:
00860 DrawWaterLock(ti);
00861 break;
00862
00863 case WATER_TILE_DEPOT:
00864 DrawWaterDepot(ti);
00865 break;
00866 }
00867 }
00868
00869 void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part)
00870 {
00871 const DrawTileSprites &dts = _shipdepot_display_data[axis][part];
00872
00873 DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
00874 DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company));
00875 }
00876
00877
00878 static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y)
00879 {
00880 int z;
00881 Slope tileh = GetTilePixelSlope(tile, &z);
00882
00883 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
00884 }
00885
00886 static Foundation GetFoundation_Water(TileIndex tile, Slope tileh)
00887 {
00888 return FOUNDATION_NONE;
00889 }
00890
00891 static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
00892 {
00893 switch (GetWaterTileType(tile)) {
00894 case WATER_TILE_CLEAR:
00895 switch (GetWaterClass(tile)) {
00896 case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
00897 case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
00898 case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
00899 default: NOT_REACHED(); break;
00900 }
00901 break;
00902 case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
00903 case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
00904 case WATER_TILE_DEPOT:
00905 td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
00906 td->build_date = Depot::GetByTile(tile)->build_date;
00907 break;
00908 default: NOT_REACHED(); break;
00909 }
00910
00911 td->owner[0] = GetTileOwner(tile);
00912 }
00913
00919 static void FloodVehicle(Vehicle *v)
00920 {
00921 uint pass = v->Crash(true);
00922
00923 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00924 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED));
00925 SetDParam(0, pass);
00926 AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NT_ACCIDENT, v->index);
00927 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00928 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
00929 }
00930
00937 static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
00938 {
00939 if ((v->vehstatus & VS_CRASHED) != 0) return NULL;
00940
00941 switch (v->type) {
00942 default: break;
00943
00944 case VEH_AIRCRAFT: {
00945 if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
00946 if (v->subtype == AIR_SHADOW) break;
00947
00948
00949
00950 const Station *st = Station::GetByTile(v->tile);
00951 const AirportFTAClass *airport = st->airport.GetFTA();
00952 if (v->z_pos != airport->delta_z + 1) break;
00953
00954 FloodVehicle(v);
00955 break;
00956 }
00957
00958 case VEH_TRAIN:
00959 case VEH_ROAD: {
00960 int z = *(int*)data;
00961 if (v->z_pos > z) break;
00962 FloodVehicle(v->First());
00963 break;
00964 }
00965 }
00966
00967 return NULL;
00968 }
00969
00975 static void FloodVehicles(TileIndex tile)
00976 {
00977 int z = 0;
00978
00979 if (IsAirportTile(tile)) {
00980 const Station *st = Station::GetByTile(tile);
00981 TILE_AREA_LOOP(tile, st->airport) {
00982 if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00983 }
00984
00985
00986 return;
00987 }
00988
00989 if (!IsBridgeTile(tile)) {
00990 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00991 return;
00992 }
00993
00994 TileIndex end = GetOtherBridgeEnd(tile);
00995 z = GetBridgePixelHeight(tile);
00996
00997 FindVehicleOnPos(tile, &z, &FloodVehicleProc);
00998 FindVehicleOnPos(end, &z, &FloodVehicleProc);
00999 }
01000
01006 FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
01007 {
01008
01009
01010
01011
01012
01013 switch (GetTileType(tile)) {
01014 case MP_WATER:
01015 if (IsCoast(tile)) {
01016 Slope tileh = GetTileSlope(tile);
01017 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01018 }
01019
01020 case MP_STATION:
01021 case MP_INDUSTRY:
01022 case MP_OBJECT:
01023 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
01024
01025 case MP_RAILWAY:
01026 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
01027 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
01028 }
01029 return FLOOD_NONE;
01030
01031 case MP_TREES:
01032 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
01033
01034 default:
01035 return FLOOD_NONE;
01036 }
01037 }
01038
01042 void DoFloodTile(TileIndex target)
01043 {
01044 assert(!IsTileType(target, MP_WATER));
01045
01046 bool flooded = false;
01047
01048 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01049
01050 Slope tileh = GetTileSlope(target);
01051 if (tileh != SLOPE_FLAT) {
01052
01053 switch (GetTileType(target)) {
01054 case MP_RAILWAY: {
01055 if (!IsPlainRail(target)) break;
01056 FloodVehicles(target);
01057 flooded = FloodHalftile(target);
01058 break;
01059 }
01060
01061 case MP_TREES:
01062 if (!IsSlopeWithOneCornerRaised(tileh)) {
01063 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
01064 MarkTileDirtyByTile(target);
01065 flooded = true;
01066 break;
01067 }
01068
01069
01070 case MP_CLEAR:
01071 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01072 MakeShore(target);
01073 MarkTileDirtyByTile(target);
01074 flooded = true;
01075 }
01076 break;
01077
01078 default:
01079 break;
01080 }
01081 } else {
01082
01083 FloodVehicles(target);
01084
01085
01086 if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01087 MakeSea(target);
01088 MarkTileDirtyByTile(target);
01089 flooded = true;
01090 }
01091 }
01092
01093 if (flooded) {
01094
01095 MarkCanalsAndRiversAroundDirty(target);
01096
01097
01098 UpdateSignalsInBuffer();
01099 }
01100
01101 cur_company.Restore();
01102 }
01103
01107 static void DoDryUp(TileIndex tile)
01108 {
01109 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
01110
01111 switch (GetTileType(tile)) {
01112 case MP_RAILWAY:
01113 assert(IsPlainRail(tile));
01114 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
01115
01116 RailGroundType new_ground;
01117 switch (GetTrackBits(tile)) {
01118 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
01119 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
01120 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
01121 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
01122 default: NOT_REACHED();
01123 }
01124 SetRailGroundType(tile, new_ground);
01125 MarkTileDirtyByTile(tile);
01126 break;
01127
01128 case MP_TREES:
01129 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
01130 MarkTileDirtyByTile(tile);
01131 break;
01132
01133 case MP_WATER:
01134 assert(IsCoast(tile));
01135
01136 if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01137 MakeClear(tile, CLEAR_GRASS, 3);
01138 MarkTileDirtyByTile(tile);
01139 }
01140 break;
01141
01142 default: NOT_REACHED();
01143 }
01144
01145 cur_company.Restore();
01146 }
01147
01154 void TileLoop_Water(TileIndex tile)
01155 {
01156 if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile);
01157
01158 switch (GetFloodingBehaviour(tile)) {
01159 case FLOOD_ACTIVE:
01160 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
01161 TileIndex dest = tile + TileOffsByDir(dir);
01162 if (!IsValidTile(dest)) continue;
01163
01164 if (IsTileType(dest, MP_WATER)) continue;
01165
01166 int z_dest;
01167 Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01168 if (z_dest > 0) continue;
01169
01170 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
01171
01172 DoFloodTile(dest);
01173 }
01174 break;
01175
01176 case FLOOD_DRYUP: {
01177 Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
01178 uint dir;
01179 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) {
01180 TileIndex dest = tile + TileOffsByDir((Direction)dir);
01181 if (!IsValidTile(dest)) continue;
01182
01183 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
01184 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
01185 }
01186 DoDryUp(tile);
01187 break;
01188 }
01189
01190 default: return;
01191 }
01192 }
01193
01194 void ConvertGroundTilesIntoWaterTiles()
01195 {
01196 int z;
01197
01198 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
01199 Slope slope = GetTileSlope(tile, &z);
01200 if (IsTileType(tile, MP_CLEAR) && z == 0) {
01201
01202
01203
01204 switch (slope) {
01205 case SLOPE_FLAT:
01206 MakeSea(tile);
01207 break;
01208
01209 case SLOPE_N:
01210 case SLOPE_E:
01211 case SLOPE_S:
01212 case SLOPE_W:
01213 MakeShore(tile);
01214 break;
01215
01216 default:
01217 uint dir;
01218 FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) {
01219 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
01220 Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
01221 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
01222 MakeShore(tile);
01223 break;
01224 }
01225 }
01226 break;
01227 }
01228 }
01229 }
01230 }
01231
01232 static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01233 {
01234 static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
01235
01236 TrackBits ts;
01237
01238 if (mode != TRANSPORT_WATER) return 0;
01239
01240 switch (GetWaterTileType(tile)) {
01241 case WATER_TILE_CLEAR: ts = (GetTileSlope(tile) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
01242 case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break;
01243 case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
01244 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
01245 default: return 0;
01246 }
01247 if (TileX(tile) == 0) {
01248
01249 ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
01250 }
01251 if (TileY(tile) == 0) {
01252
01253 ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
01254 }
01255 return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE);
01256 }
01257
01258 static bool ClickTile_Water(TileIndex tile)
01259 {
01260 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
01261 ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP);
01262 return true;
01263 }
01264 return false;
01265 }
01266
01267 static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
01268 {
01269 if (!IsTileOwner(tile, old_owner)) return;
01270
01271 bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
01272
01273
01274 if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR;
01275 if (new_owner != INVALID_OWNER) {
01276 if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR;
01277
01278
01279 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
01280 Company::Get(old_owner)->infrastructure.water--;
01281 Company::Get(new_owner)->infrastructure.water++;
01282 }
01283 if (IsShipDepot(tile)) {
01284 Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
01285 Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
01286 }
01287
01288 SetTileOwner(tile, new_owner);
01289 return;
01290 }
01291
01292
01293 if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01294
01295
01296
01297 if (IsTileOwner(tile, old_owner)) {
01298 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
01299 SetTileOwner(tile, OWNER_NONE);
01300 }
01301 }
01302
01303 static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
01304 {
01305 return VETSB_CONTINUE;
01306 }
01307
01308 static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
01309 {
01310
01311 if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
01312
01313 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01314 }
01315
01316
01317 extern const TileTypeProcs _tile_type_water_procs = {
01318 DrawTile_Water,
01319 GetSlopePixelZ_Water,
01320 ClearTile_Water,
01321 NULL,
01322 GetTileDesc_Water,
01323 GetTileTrackStatus_Water,
01324 ClickTile_Water,
01325 NULL,
01326 TileLoop_Water,
01327 ChangeTileOwner_Water,
01328 NULL,
01329 VehicleEnter_Water,
01330 GetFoundation_Water,
01331 TerraformTile_Water,
01332 };