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