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