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