00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "viewport_func.h"
00015 #include "command_func.h"
00016 #include "depot_base.h"
00017 #include "pathfinder/yapf/yapf_cache.h"
00018 #include "newgrf_debug.h"
00019 #include "newgrf_railtype.h"
00020 #include "train.h"
00021 #include "autoslope.h"
00022 #include "water.h"
00023 #include "tunnelbridge_map.h"
00024 #include "window_func.h"
00025 #include "vehicle_func.h"
00026 #include "sound_func.h"
00027 #include "tunnelbridge.h"
00028 #include "elrail_func.h"
00029 #include "town.h"
00030 #include "pbs.h"
00031 #include "company_base.h"
00032 #include "core/backup_type.hpp"
00033 #include "date_func.h"
00034 #include "strings_func.h"
00035 #include "company_gui.h"
00036
00037 #include "table/strings.h"
00038 #include "table/railtypes.h"
00039 #include "table/track_land.h"
00040
00042 typedef SmallVector<Train *, 16> TrainList;
00043
00044 RailtypeInfo _railtypes[RAILTYPE_END];
00045
00046 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
00047
00051 void ResetRailTypes()
00052 {
00053 memset(_railtypes, 0, sizeof(_railtypes));
00054 memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes));
00055 }
00056
00057 void ResolveRailTypeGUISprites(RailtypeInfo *rti)
00058 {
00059 SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
00060 if (cursors_base != 0) {
00061 rti->gui_sprites.build_ns_rail = cursors_base + 0;
00062 rti->gui_sprites.build_x_rail = cursors_base + 1;
00063 rti->gui_sprites.build_ew_rail = cursors_base + 2;
00064 rti->gui_sprites.build_y_rail = cursors_base + 3;
00065 rti->gui_sprites.auto_rail = cursors_base + 4;
00066 rti->gui_sprites.build_depot = cursors_base + 5;
00067 rti->gui_sprites.build_tunnel = cursors_base + 6;
00068 rti->gui_sprites.convert_rail = cursors_base + 7;
00069 rti->cursor.rail_ns = cursors_base + 8;
00070 rti->cursor.rail_swne = cursors_base + 9;
00071 rti->cursor.rail_ew = cursors_base + 10;
00072 rti->cursor.rail_nwse = cursors_base + 11;
00073 rti->cursor.autorail = cursors_base + 12;
00074 rti->cursor.depot = cursors_base + 13;
00075 rti->cursor.tunnel = cursors_base + 14;
00076 rti->cursor.convert = cursors_base + 15;
00077 }
00078 }
00079
00083 void InitRailTypes()
00084 {
00085 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00086 RailtypeInfo *rti = &_railtypes[rt];
00087 ResolveRailTypeGUISprites(rti);
00088 }
00089 }
00090
00094 RailType AllocateRailType(RailTypeLabel label)
00095 {
00096 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00097 RailtypeInfo *rti = &_railtypes[rt];
00098
00099 if (rti->label == 0) {
00100
00101 memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti));
00102 rti->label = label;
00103
00104
00105 rti->powered_railtypes = (RailTypes)(1 << rt);
00106 rti->compatible_railtypes = (RailTypes)(1 << rt);
00107
00108
00109 rti->introduces_railtypes = (RailTypes)(1 << rt);
00110
00111
00112
00113
00114
00115
00116
00117 rti->sorting_order = rt << 4 | 7;
00118 return rt;
00119 }
00120 }
00121
00122 return INVALID_RAILTYPE;
00123 }
00124
00125 static const byte _track_sloped_sprites[14] = {
00126 14, 15, 22, 13,
00127 0, 21, 17, 12,
00128 23, 0, 18, 20,
00129 19, 16
00130 };
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00172 static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track)
00173 {
00174 TrackBits rail_bits = TrackToTrackBits(track);
00175 return EnsureNoTrainOnTrackBits(tile, rail_bits);
00176 }
00177
00185 static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00186 {
00187 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00188
00189
00190
00191 TrackBits current = GetTrackBits(tile);
00192 TrackBits future = current | to_build;
00193
00194
00195 if (current == future) {
00196
00197 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00198 }
00199
00200
00201 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00202
00203
00204 if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
00205 return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
00206 }
00207 }
00208
00209 return CommandCost();
00210 }
00211
00212
00214 static const TrackBits _valid_tracks_without_foundation[15] = {
00215 TRACK_BIT_ALL,
00216 TRACK_BIT_RIGHT,
00217 TRACK_BIT_UPPER,
00218 TRACK_BIT_X,
00219
00220 TRACK_BIT_LEFT,
00221 TRACK_BIT_NONE,
00222 TRACK_BIT_Y,
00223 TRACK_BIT_LOWER,
00224
00225 TRACK_BIT_LOWER,
00226 TRACK_BIT_Y,
00227 TRACK_BIT_NONE,
00228 TRACK_BIT_LEFT,
00229
00230 TRACK_BIT_X,
00231 TRACK_BIT_UPPER,
00232 TRACK_BIT_RIGHT,
00233 };
00234
00236 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00237 TRACK_BIT_NONE,
00238 TRACK_BIT_LEFT,
00239 TRACK_BIT_LOWER,
00240 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00241
00242 TRACK_BIT_RIGHT,
00243 TRACK_BIT_ALL,
00244 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00245 TRACK_BIT_ALL,
00246
00247 TRACK_BIT_UPPER,
00248 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00249 TRACK_BIT_ALL,
00250 TRACK_BIT_ALL,
00251
00252 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00253 TRACK_BIT_ALL,
00254 TRACK_BIT_ALL
00255 };
00256
00264 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00265 {
00266 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00267
00268 if (IsSteepSlope(tileh)) {
00269
00270 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00271 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00272
00273
00274 Corner highest_corner = GetHighestSlopeCorner(tileh);
00275 TrackBits higher_track = CornerToTrackBits(highest_corner);
00276
00277
00278 if (bits == higher_track) return HalftileFoundation(highest_corner);
00279
00280
00281 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00282
00283
00284 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00285 } else {
00286 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00287
00288 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00289
00290 Corner track_corner;
00291 switch (bits) {
00292 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00293 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00294 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00295 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00296
00297 case TRACK_BIT_HORZ:
00298 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00299 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00300 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00301
00302 case TRACK_BIT_VERT:
00303 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00304 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00305 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00306
00307 case TRACK_BIT_X:
00308 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00309 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00310
00311 case TRACK_BIT_Y:
00312 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00313 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00314
00315 default:
00316 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00317 }
00318
00319
00320
00321 if (!valid_on_leveled) return FOUNDATION_INVALID;
00322
00323
00324 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00325
00326
00327 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00328
00329
00330 return SpecialRailFoundation(track_corner);
00331 }
00332 }
00333
00334
00344 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00345 {
00346
00347 if (GetFloodingBehaviour(tile) != FLOOD_NONE) {
00348 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00349 }
00350
00351 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00352
00353
00354 if ((f_new == FOUNDATION_INVALID) ||
00355 ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00356 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00357 }
00358
00359 Foundation f_old = GetRailFoundation(tileh, existing);
00360 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00361 }
00362
00363
00364 static inline bool ValParamTrackOrientation(Track track)
00365 {
00366 return IsValidTrack(track);
00367 }
00368
00378 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00379 {
00380 RailType railtype = Extract<RailType, 0, 4>(p1);
00381 Track track = Extract<Track, 0, 3>(p2);
00382 CommandCost cost(EXPENSES_CONSTRUCTION);
00383
00384 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00385
00386 Slope tileh = GetTileSlope(tile);
00387 TrackBits trackbit = TrackToTrackBits(track);
00388
00389 switch (GetTileType(tile)) {
00390 case MP_RAILWAY: {
00391 CommandCost ret = CheckTileOwnership(tile);
00392 if (ret.Failed()) return ret;
00393
00394 if (!IsPlainRail(tile)) return CMD_ERROR;
00395
00396 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00397
00398 ret = CheckTrackCombination(tile, trackbit, flags);
00399 if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
00400 if (ret.Failed()) return ret;
00401
00402 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00403 if (ret.Failed()) return ret;
00404 cost.AddCost(ret);
00405
00406
00407
00408
00409 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00410 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00411 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00412 if (ret.Failed()) return ret;
00413 cost.AddCost(ret);
00414 } else {
00415 return CMD_ERROR;
00416 }
00417 }
00418
00419 if (flags & DC_EXEC) {
00420 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00421 TrackBits bits = GetTrackBits(tile);
00422 SetTrackBits(tile, bits | trackbit);
00423
00424 uint pieces = CountBits(bits);
00425 if (TracksOverlap(bits)) pieces *= pieces;
00426 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
00427
00428 pieces = CountBits(bits | trackbit);
00429 if (TracksOverlap(bits | trackbit)) pieces *= pieces;
00430 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
00431 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
00432 }
00433 break;
00434 }
00435
00436 case MP_ROAD: {
00437
00438 if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00439
00440 CommandCost ret = EnsureNoVehicleOnGround(tile);
00441 if (ret.Failed()) return ret;
00442
00443 if (IsNormalRoad(tile)) {
00444 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00445
00446 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00447
00448 if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED);
00449
00450 RoadTypes roadtypes = GetRoadTypes(tile);
00451 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00452 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00453 switch (roadtypes) {
00454 default: break;
00455 case ROADTYPES_TRAM:
00456
00457 if (flags & DC_EXEC) {
00458 SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00459 Company *c = Company::GetIfValid(_current_company);
00460 if (c != NULL) {
00461
00462 c->infrastructure.road[ROADTYPE_ROAD] += 2;
00463 DirtyCompanyInfrastructureWindows(c->index);
00464 }
00465 }
00466 roadtypes |= ROADTYPES_ROAD;
00467 break;
00468
00469 case ROADTYPES_ALL:
00470 if (road != tram) return CMD_ERROR;
00471 break;
00472 }
00473
00474 road |= tram;
00475
00476 if ((track == TRACK_X && road == ROAD_Y) ||
00477 (track == TRACK_Y && road == ROAD_X)) {
00478 if (flags & DC_EXEC) {
00479 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00480 UpdateLevelCrossing(tile, false);
00481 Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR;
00482 DirtyCompanyInfrastructureWindows(_current_company);
00483 }
00484 break;
00485 }
00486 }
00487
00488 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00489 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00490 }
00491
00492 }
00493
00494 default: {
00495
00496 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00497
00498 CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00499 if (ret.Failed()) return ret;
00500 cost.AddCost(ret);
00501
00502 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00503 if (ret.Failed()) return ret;
00504 cost.AddCost(ret);
00505
00506 if (water_ground) {
00507 cost.AddCost(-_price[PR_CLEAR_WATER]);
00508 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00509 }
00510
00511 if (flags & DC_EXEC) {
00512 MakeRailNormal(tile, _current_company, trackbit, railtype);
00513 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00514 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00515 DirtyCompanyInfrastructureWindows(_current_company);
00516 }
00517 break;
00518 }
00519 }
00520
00521 if (flags & DC_EXEC) {
00522 MarkTileDirtyByTile(tile);
00523 AddTrackToSignalBuffer(tile, track, _current_company);
00524 YapfNotifyTrackLayoutChange(tile, track);
00525 }
00526
00527 cost.AddCost(RailBuildCost(railtype));
00528 return cost;
00529 }
00530
00540 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00541 {
00542 Track track = Extract<Track, 0, 3>(p2);
00543 CommandCost cost(EXPENSES_CONSTRUCTION);
00544 bool crossing = false;
00545
00546 if (!ValParamTrackOrientation(track)) return CMD_ERROR;
00547 TrackBits trackbit = TrackToTrackBits(track);
00548
00549
00550
00551
00552
00553 Owner owner = INVALID_OWNER;
00554
00555 Train *v = NULL;
00556
00557 switch (GetTileType(tile)) {
00558 case MP_ROAD: {
00559 if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00560
00561 if (_current_company != OWNER_WATER) {
00562 CommandCost ret = CheckTileOwnership(tile);
00563 if (ret.Failed()) return ret;
00564 }
00565
00566 if (!(flags & DC_BANKRUPT)) {
00567 CommandCost ret = EnsureNoVehicleOnGround(tile);
00568 if (ret.Failed()) return ret;
00569 }
00570
00571 cost.AddCost(RailClearCost(GetRailType(tile)));
00572
00573 if (flags & DC_EXEC) {
00574 if (HasReservedTracks(tile, trackbit)) {
00575 v = GetTrainForReservation(tile, track);
00576 if (v != NULL) FreeTrainTrackReservation(v);
00577 }
00578 owner = GetTileOwner(tile);
00579 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
00580 DirtyCompanyInfrastructureWindows(owner);
00581 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00582 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00583 }
00584 break;
00585 }
00586
00587 case MP_RAILWAY: {
00588 TrackBits present;
00589
00590 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00591
00592 if (_current_company != OWNER_WATER) {
00593 CommandCost ret = CheckTileOwnership(tile);
00594 if (ret.Failed()) return ret;
00595 }
00596
00597 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00598 if (ret.Failed()) return ret;
00599
00600 present = GetTrackBits(tile);
00601 if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00602 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00603
00604 cost.AddCost(RailClearCost(GetRailType(tile)));
00605
00606
00607 if (HasSignalOnTrack(tile, track)) {
00608 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00609 }
00610
00611 if (flags & DC_EXEC) {
00612 if (HasReservedTracks(tile, trackbit)) {
00613 v = GetTrainForReservation(tile, track);
00614 if (v != NULL) FreeTrainTrackReservation(v);
00615 }
00616
00617 owner = GetTileOwner(tile);
00618
00619
00620 uint pieces = CountBits(present);
00621 if (TracksOverlap(present)) pieces *= pieces;
00622 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces;
00623
00624 present ^= trackbit;
00625 pieces = CountBits(present);
00626 if (TracksOverlap(present)) pieces *= pieces;
00627 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
00628 DirtyCompanyInfrastructureWindows(owner);
00629
00630 if (present == 0) {
00631 Slope tileh = GetTileSlope(tile);
00632
00633 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00634 MakeShore(tile);
00635 } else {
00636 DoClearSquare(tile);
00637 }
00638 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00639 } else {
00640 SetTrackBits(tile, present);
00641 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00642 }
00643 }
00644 break;
00645 }
00646
00647 default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00648 }
00649
00650 if (flags & DC_EXEC) {
00651
00652 assert(Company::IsValidID(owner));
00653
00654 MarkTileDirtyByTile(tile);
00655 if (crossing) {
00656
00657
00658
00659
00660 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00661 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00662 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00663 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00664 } else {
00665 AddTrackToSignalBuffer(tile, track, owner);
00666 YapfNotifyTrackLayoutChange(tile, track);
00667 }
00668
00669 if (v != NULL) TryPathReserve(v, true);
00670 }
00671
00672 return cost;
00673 }
00674
00675
00683 bool FloodHalftile(TileIndex t)
00684 {
00685 assert(IsPlainRailTile(t));
00686
00687 bool flooded = false;
00688 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00689
00690 Slope tileh = GetTileSlope(t);
00691 TrackBits rail_bits = GetTrackBits(t);
00692
00693 if (IsSlopeWithOneCornerRaised(tileh)) {
00694 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00695
00696 TrackBits to_remove = lower_track & rail_bits;
00697 if (to_remove != 0) {
00698 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
00699 flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded();
00700 cur_company.Restore();
00701 if (!flooded) return flooded;
00702 rail_bits = rail_bits & ~to_remove;
00703 if (rail_bits == 0) {
00704 MakeShore(t);
00705 MarkTileDirtyByTile(t);
00706 return flooded;
00707 }
00708 }
00709
00710 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00711 flooded = true;
00712 SetRailGroundType(t, RAIL_GROUND_WATER);
00713 MarkTileDirtyByTile(t);
00714 }
00715 } else {
00716
00717 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00718 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00719 flooded = true;
00720 SetRailGroundType(t, RAIL_GROUND_WATER);
00721 MarkTileDirtyByTile(t);
00722 }
00723 }
00724 }
00725 return flooded;
00726 }
00727
00728 static const TileIndexDiffC _trackdelta[] = {
00729 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00730 { 0, 0 },
00731 { 0, 0 },
00732 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00733 { 0, 0 },
00734 { 0, 0 }
00735 };
00736
00737
00738 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00739 {
00740 int x = TileX(start);
00741 int y = TileY(start);
00742 int ex = TileX(end);
00743 int ey = TileY(end);
00744
00745 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00746
00747
00748 int dx = ex - x;
00749 int dy = ey - y;
00750
00751
00752 int trdx = _trackdelta[*trackdir].x;
00753 int trdy = _trackdelta[*trackdir].y;
00754
00755 if (!IsDiagonalTrackdir(*trackdir)) {
00756 trdx += _trackdelta[*trackdir ^ 1].x;
00757 trdy += _trackdelta[*trackdir ^ 1].y;
00758 }
00759
00760
00761 while ((trdx <= 0 && dx > 0) ||
00762 (trdx >= 0 && dx < 0) ||
00763 (trdy <= 0 && dy > 0) ||
00764 (trdy >= 0 && dy < 0)) {
00765 if (!HasBit(*trackdir, 3)) {
00766 SetBit(*trackdir, 3);
00767 trdx = -trdx;
00768 trdy = -trdy;
00769 } else {
00770 return CMD_ERROR;
00771 }
00772 }
00773
00774
00775
00776 if (!IsDiagonalTrackdir(*trackdir)) {
00777 trdx = _trackdelta[*trackdir].x;
00778 trdy = _trackdelta[*trackdir].y;
00779 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR;
00780 }
00781
00782 return CommandCost();
00783 }
00784
00798 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00799 {
00800 CommandCost total_cost(EXPENSES_CONSTRUCTION);
00801 Track track = Extract<Track, 4, 3>(p2);
00802 bool remove = HasBit(p2, 7);
00803 RailType railtype = Extract<RailType, 0, 4>(p2);
00804
00805 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00806 if (p1 >= MapSize()) return CMD_ERROR;
00807 TileIndex end_tile = p1;
00808 Trackdir trackdir = TrackToTrackdir(track);
00809
00810 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
00811 if (ret.Failed()) return ret;
00812
00813 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00814
00815 bool had_success = false;
00816 CommandCost last_error = CMD_ERROR;
00817 for (;;) {
00818 CommandCost ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00819
00820 if (ret.Failed()) {
00821 last_error = ret;
00822 if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
00823 if (HasBit(p2, 8)) return last_error;
00824 break;
00825 }
00826
00827
00828 if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
00829 } else {
00830 had_success = true;
00831 total_cost.AddCost(ret);
00832 }
00833
00834 if (tile == end_tile) break;
00835
00836 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00837
00838
00839 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00840 }
00841
00842 if (had_success) return total_cost;
00843 return last_error;
00844 }
00845
00860 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00861 {
00862 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00863 }
00864
00879 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00880 {
00881 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00882 }
00883
00896 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00897 {
00898
00899 RailType railtype = Extract<RailType, 0, 4>(p1);
00900 if (!ValParamRailtype(railtype)) return CMD_ERROR;
00901
00902 Slope tileh = GetTileSlope(tile);
00903
00904 DiagDirection dir = Extract<DiagDirection, 0, 2>(p2);
00905
00906
00907
00908
00909
00910
00911
00912
00913 if (tileh != SLOPE_FLAT && (
00914 !_settings_game.construction.build_on_slopes ||
00915 !CanBuildDepotByTileh(dir, tileh)
00916 )) {
00917 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00918 }
00919
00920 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00921 if (cost.Failed()) return cost;
00922
00923 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00924
00925 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00926
00927 if (flags & DC_EXEC) {
00928 Depot *d = new Depot(tile);
00929 d->build_date = _date;
00930
00931 MakeRailDepot(tile, _current_company, d->index, dir, railtype);
00932 MarkTileDirtyByTile(tile);
00933 MakeDefaultName(d);
00934
00935 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00936 DirtyCompanyInfrastructureWindows(_current_company);
00937
00938 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00939 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00940 }
00941
00942 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00943 cost.AddCost(RailBuildCost(railtype));
00944 return cost;
00945 }
00946
00968 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00969 {
00970 Track track = Extract<Track, 0, 3>(p1);
00971 bool ctrl_pressed = HasBit(p1, 3);
00972 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00973 SignalType sigtype = Extract<SignalType, 5, 3>(p1);
00974 bool convert_signal = HasBit(p1, 8);
00975 SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
00976 SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
00977 uint num_dir_cycle = GB(p1, 15, 2);
00978
00979 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00980 if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
00981
00982
00983 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00984 !HasTrack(tile, track)) {
00985 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00986 }
00987 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00988 if (ret.Failed()) return ret;
00989
00990
00991 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00992
00993 ret = CheckTileOwnership(tile);
00994 if (ret.Failed()) return ret;
00995
00996 {
00997
00998 TrackBits trackbits = GetTrackBits(tile);
00999 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
01000 trackbits != TRACK_BIT_HORZ &&
01001 trackbits != TRACK_BIT_VERT) {
01002 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01003 }
01004 }
01005
01006
01007 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01008
01009
01010 if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01011
01012 CommandCost cost;
01013 if (!HasSignalOnTrack(tile, track)) {
01014
01015 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01016 } else {
01017 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01018
01019 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01020
01021 } else if (convert_signal) {
01022
01023 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01024
01025 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01026 } else {
01027
01028 cost = CommandCost();
01029 }
01030
01031 } else {
01032
01033 cost = CommandCost();
01034 }
01035 }
01036
01037 if (flags & DC_EXEC) {
01038 Train *v = NULL;
01039
01040
01041
01042 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01043 v = GetTrainForReservation(tile, track);
01044 if (v != NULL) FreeTrainTrackReservation(v);
01045 }
01046
01047 if (!HasSignals(tile)) {
01048
01049 SetHasSignals(tile, true);
01050 SetSignalStates(tile, 0xF);
01051 SetPresentSignals(tile, 0);
01052 SetSignalType(tile, track, sigtype);
01053 SetSignalVariant(tile, track, sigvar);
01054 }
01055
01056
01057 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01058
01059 if (p2 == 0) {
01060 if (!HasSignalOnTrack(tile, track)) {
01061
01062 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01063 SetSignalType(tile, track, sigtype);
01064 SetSignalVariant(tile, track, sigvar);
01065 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01066 } else {
01067 if (convert_signal) {
01068
01069 if (ctrl_pressed) {
01070
01071 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01072
01073 sigtype = GetSignalType(tile, track);
01074 } else {
01075
01076 SetSignalType(tile, track, sigtype);
01077 SetSignalVariant(tile, track, sigvar);
01078 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01079 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01080 }
01081 }
01082
01083 } else if (ctrl_pressed) {
01084
01085 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01086
01087 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01088
01089 SetSignalType(tile, track, sigtype);
01090 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01091 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01092 }
01093 } else {
01094
01095 CycleSignalSide(tile, track);
01096
01097 sigtype = GetSignalType(tile, track);
01098 }
01099 }
01100 } else {
01101
01102
01103 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01104 SetSignalVariant(tile, track, sigvar);
01105 SetSignalType(tile, track, sigtype);
01106 }
01107
01108
01109 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01110 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01111
01112 if (IsPbsSignal(sigtype)) {
01113
01114 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01115 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01116 }
01117 MarkTileDirtyByTile(tile);
01118 AddTrackToSignalBuffer(tile, track, _current_company);
01119 YapfNotifyTrackLayoutChange(tile, track);
01120 if (v != NULL) {
01121
01122 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01123 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01124 TryPathReserve(v, true);
01125 }
01126 }
01127 }
01128
01129 return cost;
01130 }
01131
01132 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01133 {
01134 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01135 if (tile == INVALID_TILE) return false;
01136
01137
01138 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01139
01140 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01141 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01142
01143
01144 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01145
01146
01147 trackdir = RemoveFirstTrackdir(&trackdirbits);
01148
01149
01150 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01151
01152 switch (GetTileType(tile)) {
01153 case MP_RAILWAY:
01154 if (IsRailDepot(tile)) return false;
01155 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01156 signal_ctr++;
01157 if (IsDiagonalTrackdir(trackdir)) {
01158 signal_ctr++;
01159
01160 ClrBit(signal_ctr, 0);
01161 }
01162 return true;
01163
01164 case MP_ROAD:
01165 if (!IsLevelCrossing(tile)) return false;
01166 signal_ctr += 2;
01167 return true;
01168
01169 case MP_TUNNELBRIDGE: {
01170 TileIndex orig_tile = tile;
01171
01172 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01173 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01174
01175
01176
01177 tile = GetOtherTunnelBridgeEnd(tile);
01178
01179 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01180 return true;
01181 }
01182
01183 default: return false;
01184 }
01185 }
01186
01203 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01204 {
01205 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01206 TileIndex start_tile = tile;
01207
01208 Track track = Extract<Track, 0, 3>(p2);
01209 bool mode = HasBit(p2, 3);
01210 bool semaphores = HasBit(p2, 4);
01211 bool remove = HasBit(p2, 5);
01212 bool autofill = HasBit(p2, 6);
01213 byte signal_density = GB(p2, 24, 8);
01214
01215 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01216 TileIndex end_tile = p1;
01217 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01218
01219 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01220
01221
01222
01223 signal_density *= 2;
01224
01225 Trackdir trackdir = TrackToTrackdir(track);
01226 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01227 if (ret.Failed()) return ret;
01228
01229 track = TrackdirToTrack(trackdir);
01230 Trackdir start_trackdir = trackdir;
01231
01232
01233 if (!HasTrack(tile, track)) return CMD_ERROR;
01234
01235 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01236 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01237
01238 byte signals;
01239
01240 if (HasSignalOnTrack(tile, track)) {
01241 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01242 assert(signals != 0);
01243
01244
01245 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01246
01247 sigtype = GetSignalType(tile, track);
01248
01249 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01250 } else {
01251 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01252 }
01253
01254 byte signal_dir = 0;
01255 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01256 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 int signal_ctr = 0;
01267 CommandCost last_error = CMD_ERROR;
01268 bool had_success = false;
01269 for (;;) {
01270
01271 if (remove || signal_ctr % signal_density == 0) {
01272 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01273 SB(p1, 3, 1, mode);
01274 SB(p1, 4, 1, semaphores);
01275 SB(p1, 5, 3, sigtype);
01276 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01277
01278
01279 signals = 0;
01280 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01281 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01282
01283 CommandCost ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01284
01285
01286 if (ret.Succeeded()) {
01287 had_success = true;
01288 total_cost.AddCost(ret);
01289 } else {
01290
01291 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01292 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01293 last_error = ret;
01294 }
01295 }
01296 }
01297
01298 if (autofill) {
01299 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01300
01301
01302 if (tile == start_tile && trackdir == start_trackdir) break;
01303 } else {
01304 if (tile == end_tile) break;
01305
01306 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01307 signal_ctr++;
01308
01309
01310 if (IsDiagonalTrackdir(trackdir)) {
01311 signal_ctr++;
01312 } else {
01313 ToggleBit(trackdir, 0);
01314 }
01315 }
01316 }
01317
01318 return had_success ? total_cost : last_error;
01319 }
01320
01339 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01340 {
01341 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01342 }
01343
01356 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01357 {
01358 Track track = Extract<Track, 0, 3>(p1);
01359
01360 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01361 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01362 }
01363 if (!HasSignalOnTrack(tile, track)) {
01364 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01365 }
01366 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
01367 if (ret.Failed()) return ret;
01368
01369
01370 if (_current_company != OWNER_WATER) {
01371 CommandCost ret = CheckTileOwnership(tile);
01372 if (ret.Failed()) return ret;
01373 }
01374
01375
01376 if (flags & DC_EXEC) {
01377 Train *v = NULL;
01378 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01379 v = GetTrainForReservation(tile, track);
01380 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01381
01382 Trackdir td = TrackToTrackdir(track);
01383 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01384
01385 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01386 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01387 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01388 if (HasReservedTracks(next, tracks)) {
01389 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01390 }
01391 }
01392 }
01393 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01394 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01395 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01396 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01397
01398
01399 if (GetPresentSignals(tile) == 0) {
01400 SetSignalStates(tile, 0);
01401 SetHasSignals(tile, false);
01402 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01403 }
01404
01405 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01406 YapfNotifyTrackLayoutChange(tile, track);
01407 if (v != NULL) TryPathReserve(v, false);
01408
01409 MarkTileDirtyByTile(tile);
01410 }
01411
01412 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01413 }
01414
01433 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01434 {
01435 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01436 }
01437
01439 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01440 {
01441 if (v->type != VEH_TRAIN) return NULL;
01442
01443 TrainList *affected_trains = static_cast<TrainList*>(data);
01444 affected_trains->Include(Train::From(v)->First());
01445
01446 return NULL;
01447 }
01448
01461 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01462 {
01463 RailType totype = Extract<RailType, 0, 4>(p2);
01464
01465 if (!ValParamRailtype(totype)) return CMD_ERROR;
01466 if (p1 >= MapSize()) return CMD_ERROR;
01467
01468 TrainList affected_trains;
01469
01470 CommandCost cost(EXPENSES_CONSTRUCTION);
01471 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01472 TileArea ta(tile, p1);
01473 TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01474 for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01475 TileType tt = GetTileType(tile);
01476
01477
01478 switch (tt) {
01479 case MP_RAILWAY:
01480 break;
01481 case MP_STATION:
01482 if (!HasStationRail(tile)) continue;
01483 break;
01484 case MP_ROAD:
01485 if (!IsLevelCrossing(tile)) continue;
01486 if (RailNoLevelCrossings(totype)) {
01487 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01488 continue;
01489 }
01490 break;
01491 case MP_TUNNELBRIDGE:
01492 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01493 break;
01494 default: continue;
01495 }
01496
01497
01498 RailType type = GetRailType(tile);
01499
01500
01501 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01502
01503
01504 CommandCost ret = CheckTileOwnership(tile);
01505 if (ret.Failed()) {
01506 error = ret;
01507 continue;
01508 }
01509
01510 SmallVector<Train *, 2> vehicles_affected;
01511
01512
01513
01514 if (tt != MP_TUNNELBRIDGE) {
01515 if (!IsCompatibleRail(type, totype)) {
01516 CommandCost ret = EnsureNoVehicleOnGround(tile);
01517 if (ret.Failed()) {
01518 error = ret;
01519 continue;
01520 }
01521 }
01522 if (flags & DC_EXEC) {
01523 TrackBits reserved = GetReservedTrackbits(tile);
01524 Track track;
01525 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01526 Train *v = GetTrainForReservation(tile, track);
01527 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01528
01529 FreeTrainTrackReservation(v);
01530 *vehicles_affected.Append() = v;
01531 }
01532 }
01533
01534
01535 if (IsRailStationTile(tile) && !IsStationTileBlocked(tile)) {
01536 Company *c = Company::Get(GetTileOwner(tile));
01537 uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01538 if (IsPlainRailTile(tile)) {
01539 TrackBits bits = GetTrackBits(tile);
01540 num_pieces = CountBits(bits);
01541 if (TracksOverlap(bits)) num_pieces *= num_pieces;
01542 }
01543 c->infrastructure.rail[type] -= num_pieces;
01544 c->infrastructure.rail[totype] += num_pieces;
01545 DirtyCompanyInfrastructureWindows(c->index);
01546 }
01547
01548 SetRailType(tile, totype);
01549 MarkTileDirtyByTile(tile);
01550
01551 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01552 }
01553 }
01554
01555 switch (tt) {
01556 case MP_RAILWAY:
01557 switch (GetRailTileType(tile)) {
01558 case RAIL_TILE_DEPOT:
01559 if (flags & DC_EXEC) {
01560
01561 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01562
01563
01564 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01565 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01566 }
01567 cost.AddCost(RailConvertCost(type, totype));
01568 break;
01569
01570 default:
01571 if (flags & DC_EXEC) {
01572
01573 TrackBits tracks = GetTrackBits(tile);
01574 while (tracks != TRACK_BIT_NONE) {
01575 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01576 }
01577 }
01578 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01579 break;
01580 }
01581 break;
01582
01583 case MP_TUNNELBRIDGE: {
01584 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01585
01586
01587
01588 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01589 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01590
01591
01592 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01593 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01594 if (ret.Failed()) {
01595 error = ret;
01596 continue;
01597 }
01598 }
01599
01600 if (flags & DC_EXEC) {
01601 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01602 if (HasTunnelBridgeReservation(tile)) {
01603 Train *v = GetTrainForReservation(tile, track);
01604 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01605
01606 FreeTrainTrackReservation(v);
01607 *vehicles_affected.Append() = v;
01608 }
01609 }
01610
01611
01612 uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01613 Company *c = Company::Get(GetTileOwner(tile));
01614 c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01615 c->infrastructure.rail[totype] += num_pieces;
01616 DirtyCompanyInfrastructureWindows(c->index);
01617
01618 SetRailType(tile, totype);
01619 SetRailType(endtile, totype);
01620
01621 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01622 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01623
01624 YapfNotifyTrackLayoutChange(tile, track);
01625 YapfNotifyTrackLayoutChange(endtile, track);
01626
01627 MarkTileDirtyByTile(tile);
01628 MarkTileDirtyByTile(endtile);
01629
01630 if (IsBridge(tile)) {
01631 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01632 TileIndex t = tile + delta;
01633 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01634 }
01635 }
01636
01637 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01638 break;
01639 }
01640
01641 default:
01642 if (flags & DC_EXEC) {
01643 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01644 YapfNotifyTrackLayoutChange(tile, track);
01645 }
01646
01647 cost.AddCost(RailConvertCost(type, totype));
01648 break;
01649 }
01650
01651 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01652 TryPathReserve(vehicles_affected[i], true);
01653 }
01654 }
01655
01656 if (flags & DC_EXEC) {
01657
01658 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01659 (*v)->RailtypeChanged();
01660 }
01661 }
01662
01663 delete iter;
01664 return (cost.GetCost() == 0) ? error : cost;
01665 }
01666
01667 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01668 {
01669 if (_current_company != OWNER_WATER) {
01670 CommandCost ret = CheckTileOwnership(tile);
01671 if (ret.Failed()) return ret;
01672 }
01673
01674 CommandCost ret = EnsureNoVehicleOnGround(tile);
01675 if (ret.Failed()) return ret;
01676
01677 if (flags & DC_EXEC) {
01678
01679 DiagDirection dir = GetRailDepotDirection(tile);
01680 Owner owner = GetTileOwner(tile);
01681 Train *v = NULL;
01682
01683 if (HasDepotReservation(tile)) {
01684 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01685 if (v != NULL) FreeTrainTrackReservation(v);
01686 }
01687
01688 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01689 DirtyCompanyInfrastructureWindows(owner);
01690
01691 delete Depot::GetByTile(tile);
01692 DoClearSquare(tile);
01693 AddSideToSignalBuffer(tile, dir, owner);
01694 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01695 if (v != NULL) TryPathReserve(v, true);
01696 }
01697
01698 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01699 }
01700
01701 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01702 {
01703 CommandCost cost(EXPENSES_CONSTRUCTION);
01704
01705 if (flags & DC_AUTO) {
01706 if (!IsTileOwner(tile, _current_company)) {
01707 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01708 }
01709
01710 if (IsPlainRail(tile)) {
01711 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01712 } else {
01713 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01714 }
01715 }
01716
01717 switch (GetRailTileType(tile)) {
01718 case RAIL_TILE_SIGNALS:
01719 case RAIL_TILE_NORMAL: {
01720 Slope tileh = GetTileSlope(tile);
01721
01722 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01723
01724 TrackBits tracks = GetTrackBits(tile);
01725 while (tracks != TRACK_BIT_NONE) {
01726 Track track = RemoveFirstTrack(&tracks);
01727 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01728 if (ret.Failed()) return ret;
01729 cost.AddCost(ret);
01730 }
01731
01732
01733 if (water_ground && !(flags & DC_BANKRUPT)) {
01734 CommandCost ret = EnsureNoVehicleOnGround(tile);
01735 if (ret.Failed()) return ret;
01736
01737
01738 if (flags & DC_EXEC) DoClearSquare(tile);
01739 cost.AddCost(_price[PR_CLEAR_WATER]);
01740 }
01741
01742 return cost;
01743 }
01744
01745 case RAIL_TILE_DEPOT:
01746 return RemoveTrainDepot(tile, flags);
01747
01748 default:
01749 return CMD_ERROR;
01750 }
01751 }
01752
01757 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01758 {
01759 switch (track) {
01760 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01761 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01762 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01763 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01764 default: break;
01765 }
01766 return GetSlopePixelZ(x, y);
01767 }
01768
01769 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01770 {
01771 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01772 static const Point SignalPositions[2][12] = {
01773 {
01774
01775 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01776
01777 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01778 }, {
01779
01780 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01781
01782 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01783 }
01784 };
01785
01786 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01787 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01788
01789 SpriteID sprite;
01790
01791 SignalType type = GetSignalType(tile, track);
01792 SignalVariant variant = GetSignalVariant(tile, track);
01793
01794 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01795
01796 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01797 } else {
01798
01799 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01800 }
01801
01802 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01803 }
01804
01805 static uint32 _drawtile_track_palette;
01806
01807
01808 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01809 {
01810 RailFenceOffset rfo = RFO_FLAT_X;
01811 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01812 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01813 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01814 }
01815
01816 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01817 {
01818 RailFenceOffset rfo = RFO_FLAT_X;
01819 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01820 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01821 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01822 }
01823
01824 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01825 {
01826 DrawTrackFence_NW(ti, base_image);
01827 DrawTrackFence_SE(ti, base_image);
01828 }
01829
01830 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01831 {
01832 RailFenceOffset rfo = RFO_FLAT_Y;
01833 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01834 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01835 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01836 }
01837
01838 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01839 {
01840 RailFenceOffset rfo = RFO_FLAT_Y;
01841 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01842 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01843 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01844 }
01845
01846 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01847 {
01848 DrawTrackFence_NE(ti, base_image);
01849 DrawTrackFence_SW(ti, base_image);
01850 }
01851
01855 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01856 {
01857 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01858 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01859 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01860 }
01861
01865 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01866 {
01867 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01868 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01869 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01870 }
01871
01875 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01876 {
01877 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01878 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01879 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01880 }
01881
01885 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01886 {
01887 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01888 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01889 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01890 }
01891
01892
01893 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01894 {
01895
01896
01897 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01898 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01899
01900 switch (GetRailGroundType(ti->tile)) {
01901 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01902 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01903 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01904 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01905 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01906 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01907 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01908 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01909 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01910 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01911 case RAIL_GROUND_WATER: {
01912 Corner track_corner;
01913 if (IsHalftileSlope(ti->tileh)) {
01914
01915 track_corner = GetHalftileSlopeCorner(ti->tileh);
01916 } else {
01917
01918 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01919 }
01920 switch (track_corner) {
01921 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01922 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01923 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01924 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01925 default: NOT_REACHED();
01926 }
01927 break;
01928 }
01929 default: break;
01930 }
01931 }
01932
01933
01934 static const int INF = 1000;
01935 static const SubSprite _halftile_sub_sprite[4] = {
01936 { -INF , -INF , 32 - 33, INF },
01937 { -INF , 0 + 7, INF , INF },
01938 { -31 + 33, -INF , INF , INF },
01939 { -INF , -INF , INF , 30 - 23 }
01940 };
01941
01942 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01943 {
01944 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01945 }
01946
01947 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01948 {
01949 RailGroundType rgt = GetRailGroundType(ti->tile);
01950 Foundation f = GetRailFoundation(ti->tileh, track);
01951 Corner halftile_corner = CORNER_INVALID;
01952
01953 if (IsNonContinuousFoundation(f)) {
01954
01955 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01956
01957 track &= ~CornerToTrackBits(halftile_corner);
01958 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01959 }
01960
01961 DrawFoundation(ti, f);
01962
01963
01964
01965 if (rgt == RAIL_GROUND_WATER) {
01966 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
01967
01968 DrawShoreTile(ti->tileh);
01969 } else {
01970
01971 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01972 }
01973 } else {
01974 SpriteID image;
01975
01976 switch (rgt) {
01977 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01978 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01979 default: image = SPR_FLAT_GRASS_TILE; break;
01980 }
01981
01982 image += SlopeToSpriteOffset(ti->tileh);
01983
01984 DrawGroundSprite(image, PAL_NONE);
01985 }
01986
01987 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01988 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01989 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01990
01991 if (track == TRACK_BIT_NONE) {
01992
01993 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01994 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01995 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01996 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01997 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01998 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01999 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02000 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02001 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02002 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02003 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02004 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02005 } else {
02006 switch (track) {
02007
02008
02009 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02010 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02011 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02012 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02013 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02014 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02015 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02016 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02017 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02018 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02019 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02020
02021 default:
02022
02023 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02024 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02025 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02026 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02027 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02028 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02029 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02030 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02031 } else {
02032 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02033 }
02034
02035
02036 track &= ~pbs;
02037
02038
02039 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02040 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02041 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02042 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02043 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02044 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02045 }
02046
02047
02048 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02049 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02050 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02051 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02052 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02053 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02054 }
02055
02056 if (IsValidCorner(halftile_corner)) {
02057 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02058 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02059 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02060
02061
02062 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02063
02064 SpriteID image;
02065 switch (rgt) {
02066 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02067 case RAIL_GROUND_ICE_DESERT:
02068 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02069 default: image = SPR_FLAT_GRASS_TILE; break;
02070 }
02071
02072 image += SlopeToSpriteOffset(fake_slope);
02073
02074 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02075
02076 track = CornerToTrackBits(halftile_corner);
02077
02078 int offset;
02079 switch (track) {
02080 default: NOT_REACHED();
02081 case TRACK_BIT_UPPER: offset = RTO_N; break;
02082 case TRACK_BIT_LOWER: offset = RTO_S; break;
02083 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02084 case TRACK_BIT_LEFT: offset = RTO_W; break;
02085 }
02086
02087 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02088 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02089 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02090 }
02091 }
02092 }
02093
02099 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02100 {
02101 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02102
02103 if (rti->UsesOverlay()) {
02104 DrawTrackBitsOverlay(ti, track, rti);
02105 return;
02106 }
02107
02108 RailGroundType rgt = GetRailGroundType(ti->tile);
02109 Foundation f = GetRailFoundation(ti->tileh, track);
02110 Corner halftile_corner = CORNER_INVALID;
02111
02112 if (IsNonContinuousFoundation(f)) {
02113
02114 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02115
02116 track &= ~CornerToTrackBits(halftile_corner);
02117 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02118 }
02119
02120 DrawFoundation(ti, f);
02121
02122
02123 SpriteID image;
02124 PaletteID pal = PAL_NONE;
02125 const SubSprite *sub = NULL;
02126 bool junction = false;
02127
02128
02129 if (track == 0) {
02130
02131 if (rgt == RAIL_GROUND_WATER) {
02132 if (IsSteepSlope(ti->tileh)) {
02133 DrawShoreTile(ti->tileh);
02134 image = 0;
02135 } else {
02136 image = SPR_FLAT_WATER_TILE;
02137 }
02138 } else {
02139 switch (rgt) {
02140 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02141 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02142 default: image = SPR_FLAT_GRASS_TILE; break;
02143 }
02144 image += SlopeToSpriteOffset(ti->tileh);
02145 }
02146 } else {
02147 if (ti->tileh != SLOPE_FLAT) {
02148
02149 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02150 } else {
02151
02152 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02153 (image++, track == TRACK_BIT_X) ||
02154 (image++, track == TRACK_BIT_UPPER) ||
02155 (image++, track == TRACK_BIT_LOWER) ||
02156 (image++, track == TRACK_BIT_RIGHT) ||
02157 (image++, track == TRACK_BIT_LEFT) ||
02158 (image++, track == TRACK_BIT_CROSS) ||
02159
02160 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02161 (image++, track == TRACK_BIT_VERT) ||
02162
02163 (junction = true, false) ||
02164 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02165 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02166 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02167 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02168 (image++, true);
02169 }
02170
02171 switch (rgt) {
02172 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02173 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02174 case RAIL_GROUND_WATER: {
02175
02176 DrawShoreTile(ti->tileh);
02177 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02178 sub = &(_halftile_sub_sprite[track_corner]);
02179 break;
02180 }
02181 default: break;
02182 }
02183 }
02184
02185 if (image != 0) DrawGroundSprite(image, pal, sub);
02186
02187
02188 if (junction) {
02189 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02190 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02191 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02192 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02193 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02194 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02195 }
02196
02197
02198 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02199
02200 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02201 if (pbs & TRACK_BIT_X) {
02202 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02203 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02204 } else {
02205 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02206 }
02207 }
02208 if (pbs & TRACK_BIT_Y) {
02209 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02210 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02211 } else {
02212 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02213 }
02214 }
02215 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02216 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02217 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02218 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02219 }
02220
02221 if (IsValidCorner(halftile_corner)) {
02222 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02223
02224
02225 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02226 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02227 pal = PAL_NONE;
02228 switch (rgt) {
02229 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02230 case RAIL_GROUND_ICE_DESERT:
02231 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02232 default: break;
02233 }
02234 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02235
02236 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02237 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02238 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02239 }
02240 }
02241 }
02242
02250 enum SignalOffsets {
02251 SIGNAL_TO_SOUTHWEST = 0,
02252 SIGNAL_TO_NORTHEAST = 2,
02253 SIGNAL_TO_SOUTHEAST = 4,
02254 SIGNAL_TO_NORTHWEST = 6,
02255 SIGNAL_TO_EAST = 8,
02256 SIGNAL_TO_WEST = 10,
02257 SIGNAL_TO_SOUTH = 12,
02258 SIGNAL_TO_NORTH = 14,
02259 };
02260
02261 static void DrawSignals(TileIndex tile, TrackBits rails)
02262 {
02263 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02264
02265 if (!(rails & TRACK_BIT_Y)) {
02266 if (!(rails & TRACK_BIT_X)) {
02267 if (rails & TRACK_BIT_LEFT) {
02268 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02269 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02270 }
02271 if (rails & TRACK_BIT_RIGHT) {
02272 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02273 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02274 }
02275 if (rails & TRACK_BIT_UPPER) {
02276 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02277 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02278 }
02279 if (rails & TRACK_BIT_LOWER) {
02280 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02281 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02282 }
02283 } else {
02284 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02285 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02286 }
02287 } else {
02288 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02289 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02290 }
02291 }
02292
02293 static void DrawTile_Track(TileInfo *ti)
02294 {
02295 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02296
02297 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02298
02299 if (IsPlainRail(ti->tile)) {
02300 TrackBits rails = GetTrackBits(ti->tile);
02301
02302 DrawTrackBits(ti, rails);
02303
02304 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02305
02306 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02307
02308 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02309 } else {
02310
02311 const DrawTileSprites *dts;
02312 PaletteID pal = PAL_NONE;
02313 SpriteID relocation;
02314
02315 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02316
02317 if (IsInvisibilitySet(TO_BUILDINGS)) {
02318
02319 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02320 } else {
02321 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02322 }
02323
02324 SpriteID image;
02325 if (rti->UsesOverlay()) {
02326 image = SPR_FLAT_GRASS_TILE;
02327 } else {
02328 image = dts->ground.sprite;
02329 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02330 }
02331
02332
02333
02334 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02335 if (image != SPR_FLAT_GRASS_TILE) {
02336 image += rti->snow_offset;
02337 } else {
02338 image = SPR_FLAT_SNOW_DESERT_TILE;
02339 }
02340 }
02341
02342 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02343
02344 if (rti->UsesOverlay()) {
02345 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02346
02347 switch (GetRailDepotDirection(ti->tile)) {
02348 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02349 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02350 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02351 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02352 default: break;
02353 }
02354
02355 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02356 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02357
02358 switch (GetRailDepotDirection(ti->tile)) {
02359 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02360 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02361 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02362 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02363 default: break;
02364 }
02365 }
02366 } else {
02367
02368 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02369 switch (GetRailDepotDirection(ti->tile)) {
02370 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02371 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02372 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02373 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02374 default: break;
02375 }
02376 }
02377 }
02378 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02379 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02380
02381 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02382
02383 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02384 }
02385 DrawBridgeMiddle(ti);
02386 }
02387
02388 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02389 {
02390 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02391 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02392 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02393 uint32 offset = rti->GetRailtypeSpriteOffset();
02394
02395 x += 33;
02396 y += 17;
02397
02398 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02399 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02400
02401 DrawSprite(image, PAL_NONE, x, y);
02402
02403 if (rti->UsesOverlay()) {
02404 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02405
02406 switch (dir) {
02407 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02408 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02409 default: break;
02410 }
02411 }
02412 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02413 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02414
02415 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02416 }
02417
02418 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02419 {
02420 if (IsPlainRail(tile)) {
02421 int z;
02422 Slope tileh = GetTilePixelSlope(tile, &z);
02423 if (tileh == SLOPE_FLAT) return z;
02424
02425 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02426 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02427 } else {
02428 return GetTileMaxPixelZ(tile);
02429 }
02430 }
02431
02432 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02433 {
02434 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02435 }
02436
02437 static void TileLoop_Track(TileIndex tile)
02438 {
02439 RailGroundType old_ground = GetRailGroundType(tile);
02440 RailGroundType new_ground;
02441
02442 if (old_ground == RAIL_GROUND_WATER) {
02443 TileLoop_Water(tile);
02444 return;
02445 }
02446
02447 switch (_settings_game.game_creation.landscape) {
02448 case LT_ARCTIC: {
02449 int z;
02450 Slope slope = GetTileSlope(tile, &z);
02451 bool half = false;
02452
02453
02454
02455 if (IsPlainRail(tile)) {
02456 TrackBits track = GetTrackBits(tile);
02457 Foundation f = GetRailFoundation(slope, track);
02458
02459 switch (f) {
02460 case FOUNDATION_NONE:
02461
02462 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02463 break;
02464
02465 case FOUNDATION_INCLINED_X:
02466 case FOUNDATION_INCLINED_Y:
02467
02468 if (IsSteepSlope(slope)) z++;
02469 break;
02470
02471 case FOUNDATION_STEEP_LOWER:
02472
02473 z++;
02474 break;
02475
02476 default:
02477
02478 if (IsSteepSlope(slope)) z++;
02479 z++;
02480 break;
02481 }
02482
02483 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02484 } else {
02485
02486 if (slope != SLOPE_FLAT) z++;
02487 }
02488
02489
02490
02491
02492
02493 if (z > GetSnowLine()) {
02494 if (half && z - GetSnowLine() == 1) {
02495
02496 new_ground = RAIL_GROUND_HALF_SNOW;
02497 } else {
02498 new_ground = RAIL_GROUND_ICE_DESERT;
02499 }
02500 goto set_ground;
02501 }
02502 break;
02503 }
02504
02505 case LT_TROPIC:
02506 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02507 new_ground = RAIL_GROUND_ICE_DESERT;
02508 goto set_ground;
02509 }
02510 break;
02511 }
02512
02513 new_ground = RAIL_GROUND_GRASS;
02514
02515 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02516
02517 TrackBits rail = GetTrackBits(tile);
02518
02519 switch (rail) {
02520 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02521 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02522 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02523 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02524
02525 default: {
02526 Owner owner = GetTileOwner(tile);
02527
02528 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02529 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02530 (rail & TRACK_BIT_X)
02531 )) {
02532 TileIndex n = tile + TileDiffXY(0, -1);
02533 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02534
02535 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02536 !IsTileOwner(n, owner) ||
02537 nrail == TRACK_BIT_UPPER ||
02538 nrail == TRACK_BIT_LEFT) {
02539 new_ground = RAIL_GROUND_FENCE_NW;
02540 }
02541 }
02542
02543 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02544 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02545 (rail & TRACK_BIT_X)
02546 )) {
02547 TileIndex n = tile + TileDiffXY(0, 1);
02548 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02549
02550 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02551 !IsTileOwner(n, owner) ||
02552 nrail == TRACK_BIT_LOWER ||
02553 nrail == TRACK_BIT_RIGHT) {
02554 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02555 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02556 }
02557 }
02558
02559 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02560 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02561 (rail & TRACK_BIT_Y)
02562 )) {
02563 TileIndex n = tile + TileDiffXY(-1, 0);
02564 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02565
02566 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02567 !IsTileOwner(n, owner) ||
02568 nrail == TRACK_BIT_UPPER ||
02569 nrail == TRACK_BIT_RIGHT) {
02570 new_ground = RAIL_GROUND_FENCE_NE;
02571 }
02572 }
02573
02574 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02575 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02576 (rail & TRACK_BIT_Y)
02577 )) {
02578 TileIndex n = tile + TileDiffXY(1, 0);
02579 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02580
02581 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02582 !IsTileOwner(n, owner) ||
02583 nrail == TRACK_BIT_LOWER ||
02584 nrail == TRACK_BIT_LEFT) {
02585 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02586 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02587 }
02588 }
02589 break;
02590 }
02591 }
02592 }
02593
02594 set_ground:
02595 if (old_ground != new_ground) {
02596 SetRailGroundType(tile, new_ground);
02597 MarkTileDirtyByTile(tile);
02598 }
02599 }
02600
02601
02602 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02603 {
02604
02605 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02606 TrackBits tb = GetTrackBits(tile);
02607 switch (tb) {
02608 default: NOT_REACHED();
02609 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02610 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02611 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02612 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02613 }
02614 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02615 }
02616
02617 if (mode != TRANSPORT_RAIL) return 0;
02618
02619 TrackBits trackbits = TRACK_BIT_NONE;
02620 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02621
02622 switch (GetRailTileType(tile)) {
02623 default: NOT_REACHED();
02624 case RAIL_TILE_NORMAL:
02625 trackbits = GetTrackBits(tile);
02626 break;
02627
02628 case RAIL_TILE_SIGNALS: {
02629 trackbits = GetTrackBits(tile);
02630 byte a = GetPresentSignals(tile);
02631 uint b = GetSignalStates(tile);
02632
02633 b &= a;
02634
02635
02636
02637
02638
02639
02640 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02641 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02642
02643 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02644 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02645 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02646 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02647
02648 break;
02649 }
02650
02651 case RAIL_TILE_DEPOT: {
02652 DiagDirection dir = GetRailDepotDirection(tile);
02653
02654 if (side != INVALID_DIAGDIR && side != dir) break;
02655
02656 trackbits = DiagDirToDiagTrackBits(dir);
02657 break;
02658 }
02659 }
02660
02661 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02662 }
02663
02664 static bool ClickTile_Track(TileIndex tile)
02665 {
02666 if (!IsRailDepot(tile)) return false;
02667
02668 ShowDepotWindow(tile, VEH_TRAIN);
02669 return true;
02670 }
02671
02672 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02673 {
02674 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02675 td->rail_speed = rti->max_speed;
02676 td->owner[0] = GetTileOwner(tile);
02677 SetDParamX(td->dparam, 0, rti->strings.name);
02678 switch (GetRailTileType(tile)) {
02679 case RAIL_TILE_NORMAL:
02680 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02681 break;
02682
02683 case RAIL_TILE_SIGNALS: {
02684 static const StringID signal_type[6][6] = {
02685 {
02686 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02687 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02688 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02689 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02690 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02691 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02692 },
02693 {
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02696 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02697 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02699 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02700 },
02701 {
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02704 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02705 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02707 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02708 },
02709 {
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02712 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02713 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02715 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02716 },
02717 {
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02720 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02721 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02723 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02724 },
02725 {
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02728 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02729 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02730 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02731 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02732 }
02733 };
02734
02735 SignalType primary_signal;
02736 SignalType secondary_signal;
02737 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02738 primary_signal = GetSignalType(tile, TRACK_UPPER);
02739 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02740 } else {
02741 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02742 }
02743
02744 td->str = signal_type[secondary_signal][primary_signal];
02745 break;
02746 }
02747
02748 case RAIL_TILE_DEPOT:
02749 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02750 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02751 if (td->rail_speed > 0) {
02752 td->rail_speed = min(td->rail_speed, 61);
02753 } else {
02754 td->rail_speed = 61;
02755 }
02756 }
02757 td->build_date = Depot::GetByTile(tile)->build_date;
02758 break;
02759
02760 default:
02761 NOT_REACHED();
02762 }
02763 }
02764
02765 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02766 {
02767 if (!IsTileOwner(tile, old_owner)) return;
02768
02769 if (new_owner != INVALID_OWNER) {
02770
02771 uint num_pieces = 1;
02772 if (IsPlainRail(tile)) {
02773 TrackBits bits = GetTrackBits(tile);
02774 num_pieces = CountBits(bits);
02775 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02776 }
02777 RailType rt = GetRailType(tile);
02778 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02779 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02780
02781 if (HasSignals(tile)) {
02782 uint num_sigs = CountBits(GetPresentSignals(tile));
02783 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02784 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02785 }
02786
02787 SetTileOwner(tile, new_owner);
02788 } else {
02789 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02790 }
02791 }
02792
02793 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02794 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02795 static const int8 _deltacoord_leaveoffset[8] = {
02796 -1, 0, 1, 0,
02797 0, 1, 0, -1
02798 };
02799
02800
02807 int TicksToLeaveDepot(const Train *v)
02808 {
02809 DiagDirection dir = GetRailDepotDirection(v->tile);
02810 int length = v->CalcNextVehicleOffset();
02811
02812 switch (dir) {
02813 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02814 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02815 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02816 default:
02817 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02818 }
02819
02820 return 0;
02821 }
02822
02827 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02828 {
02829
02830 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02831
02832 Train *v = Train::From(u);
02833
02834
02835 DiagDirection dir = GetRailDepotDirection(tile);
02836
02837
02838 int length = v->CalcNextVehicleOffset();
02839
02840 byte fract_coord_leave =
02841 ((_fractcoords_enter[dir] & 0x0F) +
02842 (length + 1) * _deltacoord_leaveoffset[dir]) +
02843 (((_fractcoords_enter[dir] >> 4) +
02844 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02845
02846 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02847
02848 if (_fractcoords_behind[dir] == fract_coord) {
02849
02850 return VETSB_CANNOT_ENTER;
02851 } else if (_fractcoords_enter[dir] == fract_coord) {
02852 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02853
02854 v->track = TRACK_BIT_DEPOT,
02855 v->vehstatus |= VS_HIDDEN;
02856 v->direction = ReverseDir(v->direction);
02857 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02858 v->tile = tile;
02859
02860 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02861 return VETSB_ENTERED_WORMHOLE;
02862 }
02863 } else if (fract_coord_leave == fract_coord) {
02864 if (DiagDirToDir(dir) == v->direction) {
02865
02866 if ((v = v->Next()) != NULL) {
02867 v->vehstatus &= ~VS_HIDDEN;
02868 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02869 }
02870 }
02871 }
02872
02873 return VETSB_CONTINUE;
02874 }
02875
02887 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02888 {
02889 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02890
02891
02892 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02893
02894
02895 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02896 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02897
02898 Corner track_corner;
02899 switch (rail_bits) {
02900 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02901 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02902 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02903 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02904
02905
02906 default:
02907 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02908 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02909 }
02910
02911
02912 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02913 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02914 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02915
02916 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02917
02918 if (tileh_old != tileh_new) {
02919
02920 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02921 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02922 }
02923 return cost;
02924 }
02925
02926 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02927 {
02928 int z_old;
02929 Slope tileh_old = GetTileSlope(tile, &z_old);
02930 if (IsPlainRail(tile)) {
02931 TrackBits rail_bits = GetTrackBits(tile);
02932
02933 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02934
02935
02936 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02937
02938
02939 Corner allowed_corner;
02940 switch (rail_bits) {
02941 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02942 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02943 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02944 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02945 default: return autoslope_result;
02946 }
02947
02948 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02949
02950
02951 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02952
02953
02954 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02955 if (allowed_corner == corner) continue;
02956 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02957 }
02958
02959
02960 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02961
02962
02963 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02964 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02965 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02966 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02967 }
02968 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02969 }
02970
02971
02972 extern const TileTypeProcs _tile_type_rail_procs = {
02973 DrawTile_Track,
02974 GetSlopePixelZ_Track,
02975 ClearTile_Track,
02976 NULL,
02977 GetTileDesc_Track,
02978 GetTileTrackStatus_Track,
02979 ClickTile_Track,
02980 NULL,
02981 TileLoop_Track,
02982 ChangeTileOwner_Track,
02983 NULL,
02984 VehicleEnter_Track,
02985 GetFoundation_Track,
02986 TerraformTile_Track,
02987 };