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