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) || !HasTrack(tile, track)) {
00954 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00955 }
00956 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00957 if (ret.Failed()) return ret;
00958
00959
00960 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00961
00962 ret = CheckTileOwnership(tile);
00963
00964 if (ret.Failed()) return ret;
00965
00966 CommandCost cost;
00967
00968 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00969 TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile);
00970 cost = CommandCost();
00971 if (!HasWormholeSignals(tile)) {
00972 if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2));
00973 }
00974 if (flags & DC_EXEC) {
00975 if (p2 == 0 && HasWormholeSignals(tile)){
00976 if (IsTunnelBridgeEntrance (tile)) {
00977 ClrBitTunnelBridgeSignal(tile);
00978 ClrBitTunnelBridgeExit(tile_exit);
00979 SetBitTunnelBridgeExit(tile);
00980 SetBitTunnelBridgeSignal(tile_exit);
00981 } else {
00982 ClrBitTunnelBridgeSignal(tile_exit);
00983 ClrBitTunnelBridgeExit(tile);
00984 SetBitTunnelBridgeExit(tile_exit);
00985 SetBitTunnelBridgeSignal(tile);
00986 }
00987 } else{
00988
00989 if (p2 == 0) {
00990 SetBitTunnelBridgeSignal(tile);
00991 SetBitTunnelBridgeExit(tile_exit);
00992 } else if (p2 == 4 || p2 == 8) {
00993 DiagDirection tbdir = GetTunnelBridgeDirection(tile);
00994
00995 if ((p2 == 8 && (tbdir == DIAGDIR_NE || tbdir == DIAGDIR_SE)) ||
00996 (p2 == 4 && (tbdir == DIAGDIR_SW || tbdir == DIAGDIR_NW))) {
00997 SetBitTunnelBridgeSignal(tile);
00998 SetBitTunnelBridgeExit(tile_exit);
00999 } else {
01000 SetBitTunnelBridgeSignal(tile_exit);
01001 SetBitTunnelBridgeExit(tile);
01002 }
01003 }
01004 }
01005 MarkTileDirtyByTile(tile);
01006 MarkTileDirtyByTile(tile_exit);
01007 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
01008 YapfNotifyTrackLayoutChange(tile, track);
01009 }
01010 return cost;
01011 }
01012
01013 {
01014
01015 TrackBits trackbits = GetTrackBits(tile);
01016 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
01017 trackbits != TRACK_BIT_HORZ &&
01018 trackbits != TRACK_BIT_VERT) {
01019 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01020 }
01021 }
01022
01023
01024 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01025
01026
01027 if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01028
01029 if (!HasSignalOnTrack(tile, track)) {
01030
01031 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01032 } else {
01033 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01034
01035 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01036
01037 } else if (convert_signal) {
01038
01039 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01040
01041 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01042 } else {
01043
01044 cost = CommandCost();
01045 }
01046
01047 } else {
01048
01049 cost = CommandCost();
01050 }
01051 }
01052
01053 if (flags & DC_EXEC) {
01054 Train *v = NULL;
01055
01056
01057
01058 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01059 v = GetTrainForReservation(tile, track);
01060 if (v != NULL) FreeTrainTrackReservation(v);
01061 }
01062
01063 if (!HasSignals(tile)) {
01064
01065 SetHasSignals(tile, true);
01066 SetSignalStates(tile, 0xF);
01067 SetPresentSignals(tile, 0);
01068 SetSignalType(tile, track, sigtype);
01069 SetSignalVariant(tile, track, sigvar);
01070 }
01071
01072 if (p2 == 0) {
01073 if (!HasSignalOnTrack(tile, track)) {
01074
01075 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01076 SetSignalType(tile, track, sigtype);
01077 SetSignalVariant(tile, track, sigvar);
01078 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01079 } else {
01080 if (convert_signal) {
01081
01082 if (ctrl_pressed) {
01083
01084 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01085
01086 sigtype = GetSignalType(tile, track);
01087 } else {
01088
01089 if (IsPresignalProgrammable(tile, track)) {
01090 FreeSignalProgram(SignalReference(tile, track));
01091 } else if(IsSpeedSignal(tile, track)) {
01092 FreeSignalSpeed(SignalReference(tile, track));
01093 }
01094 SetSignalType(tile, track, sigtype);
01095 SetSignalVariant(tile, track, sigvar);
01096 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01097 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01098 }
01099 }
01100
01101 } else if (ctrl_pressed) {
01102
01103 sigtype = (SignalType)(GetSignalType(tile, track));
01104 if(IsProgrammableSignal(sigtype)) {
01105 FreeSignalProgram(SignalReference(tile, track));
01106 } else if(IsSpeedSignal(sigtype)) {
01107 FreeSignalSpeed(SignalReference(tile, track));
01108 }
01109 sigtype = NextSignalType(sigtype, which_signals);
01110 SetSignalType(tile, track, sigtype);
01111 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01112 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01113 }
01114 } else {
01115
01116 CycleSignalSide(tile, track);
01117
01118 sigtype = GetSignalType(tile, track);
01119 }
01120 }
01121 } else {
01122
01123
01124 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01125 SetSignalVariant(tile, track, sigvar);
01126 if(IsPresignalProgrammable(tile, track)) {
01127 FreeSignalProgram(SignalReference(tile, track));
01128 } else if(IsSpeedSignal(tile, track)) {
01129 FreeSignalSpeed(SignalReference(tile, track));
01130 }
01131 SetSignalType(tile, track, sigtype);
01132 }
01133
01134 if (IsPbsSignal(sigtype)) {
01135
01136 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01137 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01138 }
01139 MarkTileDirtyByTile(tile);
01140 AddTrackToSignalBuffer(tile, track, _current_company);
01141 YapfNotifyTrackLayoutChange(tile, track);
01142 if (v != NULL) {
01143
01144 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01145 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01146 TryPathReserve(v, true);
01147 }
01148 }
01149 }
01150
01151 return cost;
01152 }
01153
01154 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01155 {
01156 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01157 if (tile == INVALID_TILE) return false;
01158
01159
01160 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01161
01162 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01163 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01164
01165
01166 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01167
01168
01169 trackdir = RemoveFirstTrackdir(&trackdirbits);
01170
01171
01172 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01173
01174 switch (GetTileType(tile)) {
01175 case MP_RAILWAY:
01176 if (IsRailDepot(tile)) return false;
01177 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01178 signal_ctr++;
01179 if (IsDiagonalTrackdir(trackdir)) {
01180 signal_ctr++;
01181
01182 ClrBit(signal_ctr, 0);
01183 }
01184 return true;
01185
01186 case MP_ROAD:
01187 if (!IsLevelCrossing(tile)) return false;
01188 signal_ctr += 2;
01189 return true;
01190
01191 case MP_TUNNELBRIDGE: {
01192 if (!remove && HasWormholeSignals(tile)) return false;
01193 TileIndex orig_tile = tile;
01194
01195 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01196 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01197
01198
01199
01200 tile = GetOtherTunnelBridgeEnd(tile);
01201
01202 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01203 return true;
01204 }
01205
01206 default: return false;
01207 }
01208 }
01209
01226 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01227 {
01228 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01229 TileIndex start_tile = tile;
01230
01231 Track track = Extract<Track, 0, 3>(p2);
01232 bool mode = HasBit(p2, 3);
01233 bool semaphores = HasBit(p2, 4);
01234 bool remove = HasBit(p2, 5);
01235 bool autofill = HasBit(p2, 6);
01236 byte signal_density = GB(p2, 24, 8);
01237
01238 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01239 TileIndex end_tile = p1;
01240 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01241
01242 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01243
01244
01245
01246 signal_density *= 2;
01247
01248 Trackdir trackdir = TrackToTrackdir(track);
01249 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01250 if (ret.Failed()) return ret;
01251
01252 track = TrackdirToTrack(trackdir);
01253 Trackdir start_trackdir = trackdir;
01254
01255
01256 if (!HasTrack(tile, track)) return CMD_ERROR;
01257
01258 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01259 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01260
01261 byte signals;
01262
01263 if (HasSignalOnTrack(tile, track)) {
01264 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01265 assert(signals != 0);
01266
01267
01268 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01269
01270 sigtype = GetSignalType(tile, track);
01271
01272 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01273 } else {
01274 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01275 }
01276
01277 byte signal_dir = 0;
01278 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01279 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289 int signal_ctr = 0;
01290 CommandCost last_error = CMD_ERROR;
01291 bool had_success = false;
01292 for (;;) {
01293
01294 if ((remove && autofill) || signal_ctr % signal_density == 0 || IsTileType(tile, MP_TUNNELBRIDGE)) {
01295 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01296 SB(p1, 3, 1, mode);
01297 SB(p1, 4, 1, semaphores);
01298 SB(p1, 5, 3, sigtype);
01299 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01300
01301
01302 signals = 0;
01303 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01304 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01305
01306 CommandCost ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01307
01308
01309 if (ret.Succeeded()) {
01310 had_success = true;
01311 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01312 if ((!autofill && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) ||
01313 (autofill && GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir))) {
01314 total_cost.AddCost(ret);
01315 }
01316 } else {
01317 total_cost.AddCost(ret);
01318 }
01319 } else {
01320
01321 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01322 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01323 last_error = ret;
01324 }
01325 }
01326 }
01327
01328 if (autofill) {
01329 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01330
01331
01332 if (tile == start_tile && trackdir == start_trackdir) break;
01333 } else {
01334 if (tile == end_tile) break;
01335
01336 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01337 signal_ctr++;
01338
01339
01340 if (IsDiagonalTrackdir(trackdir)) {
01341 signal_ctr++;
01342 } else {
01343 ToggleBit(trackdir, 0);
01344 }
01345 }
01346 }
01347
01348 return had_success ? total_cost : last_error;
01349 }
01350
01369 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01370 {
01371 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01372 }
01373
01386 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01387 {
01388 Track track = Extract<Track, 0, 3>(p1);
01389 Money cost = _price[PR_CLEAR_SIGNALS];
01390
01391 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01392 TileIndex end = GetOtherTunnelBridgeEnd(tile);
01393 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01394 if (!HasWormholeSignals(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01395
01396 cost *= ((GetTunnelBridgeLength(tile, end) + 4) >> 2);
01397
01398 CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track);
01399 if (ret.Failed()) return ret;
01400 } else {
01401 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01402 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01403 }
01404 if (!HasSignalOnTrack(tile, track)) {
01405 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01406 }
01407 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
01408 if (ret.Failed()) return ret;
01409 }
01410
01411
01412 if (_current_company != OWNER_WATER) {
01413 CommandCost ret = CheckTileOwnership(tile);
01414 if (ret.Failed()) return ret;
01415 }
01416
01417
01418 if (flags & DC_EXEC) {
01419
01420 if (HasWormholeSignals(tile)) {
01421 TileIndex end = GetOtherTunnelBridgeEnd(tile);
01422 ClrBitTunnelBridgeExit(tile);
01423 ClrBitTunnelBridgeExit(end);
01424 ClrBitTunnelBridgeSignal(tile);
01425 ClrBitTunnelBridgeSignal(end);
01426 _m[tile].m2 = 0;
01427 _m[end].m2 = 0;
01428 MarkTileDirtyByTile(tile);
01429 MarkTileDirtyByTile(end);
01430 return CommandCost(EXPENSES_CONSTRUCTION, cost);
01431 }
01432
01433 Train *v = NULL;
01434 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01435 v = GetTrainForReservation(tile, track);
01436 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01437
01438 Trackdir td = TrackToTrackdir(track);
01439 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01440
01441 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01442 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01443 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01444 if (HasReservedTracks(next, tracks)) {
01445 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01446 }
01447 }
01448 }
01449
01450 CheckRemoveSignal(tile, track);
01451 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01452
01453
01454 if (GetPresentSignals(tile) == 0) {
01455 SetSignalStates(tile, 0);
01456 SetHasSignals(tile, false);
01457 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01458 }
01459
01460 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01461 YapfNotifyTrackLayoutChange(tile, track);
01462 if (v != NULL) TryPathReserve(v, false);
01463
01464 MarkTileDirtyByTile(tile);
01465 }
01466
01467 return CommandCost(EXPENSES_CONSTRUCTION, cost);
01468 }
01469
01488 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01489 {
01490 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01491 }
01492
01494 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01495 {
01496 if (v->type != VEH_TRAIN) return NULL;
01497
01498 TrainList *affected_trains = static_cast<TrainList*>(data);
01499 affected_trains->Include(Train::From(v)->First());
01500
01501 return NULL;
01502 }
01503
01514 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01515 {
01516 RailType totype = Extract<RailType, 0, 4>(p2);
01517
01518 if (!ValParamRailtype(totype)) return CMD_ERROR;
01519 if (p1 >= MapSize()) return CMD_ERROR;
01520
01521 TrainList affected_trains;
01522
01523 CommandCost cost(EXPENSES_CONSTRUCTION);
01524 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01525 TileArea ta(tile, p1);
01526 TILE_AREA_LOOP(tile, ta) {
01527 TileType tt = GetTileType(tile);
01528
01529
01530 switch (tt) {
01531 case MP_RAILWAY:
01532 break;
01533 case MP_STATION:
01534 if (!HasStationRail(tile)) continue;
01535 break;
01536 case MP_ROAD:
01537 if (!IsLevelCrossing(tile)) continue;
01538 if (RailNoLevelCrossings(totype)) {
01539 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01540 continue;
01541 }
01542 break;
01543 case MP_TUNNELBRIDGE:
01544 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01545 break;
01546 default: continue;
01547 }
01548
01549
01550 RailType type = GetRailType(tile);
01551
01552
01553 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01554
01555
01556 CommandCost ret = CheckTileOwnership(tile);
01557 if (ret.Failed()) {
01558 error = ret;
01559 continue;
01560 }
01561
01562 SmallVector<Train *, 2> vehicles_affected;
01563
01564
01565
01566 if (tt != MP_TUNNELBRIDGE) {
01567 if (!IsCompatibleRail(type, totype)) {
01568 CommandCost ret = EnsureNoVehicleOnGround(tile);
01569 if (ret.Failed()) {
01570 error = ret;
01571 continue;
01572 }
01573 }
01574 if (flags & DC_EXEC) {
01575 TrackBits reserved = GetReservedTrackbits(tile);
01576 Track track;
01577 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01578 Train *v = GetTrainForReservation(tile, track);
01579 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01580
01581 FreeTrainTrackReservation(v);
01582 *vehicles_affected.Append() = v;
01583 }
01584 }
01585
01586 SetRailType(tile, totype);
01587 MarkTileDirtyByTile(tile);
01588
01589 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01590 }
01591 }
01592
01593 switch (tt) {
01594 case MP_RAILWAY:
01595 switch (GetRailTileType(tile)) {
01596 case RAIL_TILE_DEPOT:
01597 if (flags & DC_EXEC) {
01598
01599 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01600
01601
01602 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01603 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01604 }
01605 cost.AddCost(RailConvertCost(type, totype));
01606 break;
01607
01608 default:
01609 if (flags & DC_EXEC) {
01610
01611 TrackBits tracks = GetTrackBits(tile);
01612 while (tracks != TRACK_BIT_NONE) {
01613 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01614 }
01615 }
01616 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01617 break;
01618 }
01619 break;
01620
01621 case MP_TUNNELBRIDGE: {
01622 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01623
01624
01625
01626 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01627 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01628
01629
01630 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01631 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01632 if (ret.Failed()) {
01633 error = ret;
01634 continue;
01635 }
01636 }
01637
01638 if (flags & DC_EXEC) {
01639 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01640 if (HasTunnelBridgeReservation(tile)) {
01641 Train *v = GetTrainForReservation(tile, track);
01642 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01643
01644 FreeTrainTrackReservation(v);
01645 *vehicles_affected.Append() = v;
01646 }
01647 }
01648 SetRailType(tile, totype);
01649 SetRailType(endtile, totype);
01650
01651 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01652 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01653
01654 YapfNotifyTrackLayoutChange(tile, track);
01655 YapfNotifyTrackLayoutChange(endtile, track);
01656
01657 MarkTileDirtyByTile(tile);
01658 MarkTileDirtyByTile(endtile);
01659
01660 if (IsBridge(tile)) {
01661 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01662 TileIndex t = tile + delta;
01663 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01664 }
01665 }
01666
01667 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01668 break;
01669 }
01670
01671 default:
01672 if (flags & DC_EXEC) {
01673 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01674 YapfNotifyTrackLayoutChange(tile, track);
01675 }
01676
01677 cost.AddCost(RailConvertCost(type, totype));
01678 break;
01679 }
01680
01681 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01682 TryPathReserve(vehicles_affected[i], true);
01683 }
01684 }
01685
01686 if (flags & DC_EXEC) {
01687
01688 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01689 (*v)->RailtypeChanged();
01690 }
01691 }
01692
01693 return (cost.GetCost() == 0) ? error : cost;
01694 }
01695
01696 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01697 {
01698 if (_current_company != OWNER_WATER) {
01699 CommandCost ret = CheckTileOwnership(tile);
01700 if (ret.Failed()) return ret;
01701 }
01702
01703 CommandCost ret = EnsureNoVehicleOnGround(tile);
01704 if (ret.Failed()) return ret;
01705
01706 if (flags & DC_EXEC) {
01707
01708 DiagDirection dir = GetRailDepotDirection(tile);
01709 Owner owner = GetTileOwner(tile);
01710 Train *v = NULL;
01711
01712 if (HasDepotReservation(tile)) {
01713 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01714 if (v != NULL) FreeTrainTrackReservation(v);
01715 }
01716
01717 delete Depot::GetByTile(tile);
01718 DoClearSquare(tile);
01719 AddSideToSignalBuffer(tile, dir, owner);
01720 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01721 if (v != NULL) TryPathReserve(v, true);
01722 }
01723
01724 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01725 }
01726
01727 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01728 {
01729 CommandCost cost(EXPENSES_CONSTRUCTION);
01730
01731 if (flags & DC_AUTO) {
01732 if (!IsTileOwner(tile, _current_company)) {
01733 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01734 }
01735
01736 if (IsPlainRail(tile)) {
01737 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01738 } else {
01739 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01740 }
01741 }
01742
01743 switch (GetRailTileType(tile)) {
01744 case RAIL_TILE_SIGNALS:
01745 if (flags & DC_EXEC) CheckRemoveSignalsFromTile(tile);
01746
01747 case RAIL_TILE_NORMAL: {
01748 Slope tileh = GetTileSlope(tile, NULL);
01749
01750 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01751
01752 TrackBits tracks = GetTrackBits(tile);
01753 while (tracks != TRACK_BIT_NONE) {
01754 Track track = RemoveFirstTrack(&tracks);
01755 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01756 if (ret.Failed()) return ret;
01757 cost.AddCost(ret);
01758 }
01759
01760
01761 if (water_ground && !(flags & DC_BANKRUPT)) {
01762 CommandCost ret = EnsureNoVehicleOnGround(tile);
01763 if (ret.Failed()) return ret;
01764
01765
01766 if (flags & DC_EXEC) DoClearSquare(tile);
01767 cost.AddCost(_price[PR_CLEAR_WATER]);
01768 }
01769
01770 return cost;
01771 }
01772
01773 case RAIL_TILE_DEPOT:
01774 return RemoveTrainDepot(tile, flags);
01775
01776 default:
01777 return CMD_ERROR;
01778 }
01779 }
01780
01785 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01786 {
01787 switch (track) {
01788 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01789 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01790 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01791 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01792 default: break;
01793 }
01794 return GetSlopeZ(x, y);
01795 }
01796
01797 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01798 {
01799 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01800 static const Point SignalPositions[2][12] = {
01801 {
01802
01803 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01804
01805 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01806 }, {
01807
01808 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01809
01810 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01811 }
01812 };
01813
01814 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01815 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01816
01817 SpriteID sprite;
01818
01819 SignalType type = GetSignalType(tile, track);
01820 SignalVariant variant = GetSignalVariant(tile, track);
01821
01822 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01823
01824 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01825
01826 } else if (type == SIGTYPE_PROG && variant == SIG_ELECTRIC) {
01827
01828 sprite = (SPR_PROGSIGNAL_BASE + 16) + image + condition;
01829 } else if (type == SIGTYPE_PROG && variant == SIG_SEMAPHORE) {
01830
01831 sprite = SPR_PROGSIGNAL_BASE + image + condition;
01832 } else if (type == SIGTYPE_SPEED && variant == SIG_ELECTRIC) {
01833
01834 sprite = (SPR_SPEEDSIGNAL_BASE + 16) + image + condition;
01835 } else if (type == SIGTYPE_SPEED && variant == SIG_SEMAPHORE) {
01836
01837 sprite = SPR_SPEEDSIGNAL_BASE + image + condition;
01838 } else {
01839
01840 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (IsSignalSpritePBS(type) ? 64 : 0);
01841 }
01842
01843 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01844 }
01845
01846 static uint32 _drawtile_track_palette;
01847
01848
01849 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01850 {
01851 RailFenceOffset rfo = RFO_FLAT_X;
01852 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01853 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01854 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01855 }
01856
01857 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01858 {
01859 RailFenceOffset rfo = RFO_FLAT_X;
01860 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01861 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01862 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01863 }
01864
01865 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01866 {
01867 DrawTrackFence_NW(ti, base_image);
01868 DrawTrackFence_SE(ti, base_image);
01869 }
01870
01871 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01872 {
01873 RailFenceOffset rfo = RFO_FLAT_Y;
01874 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01875 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01876 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01877 }
01878
01879 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01880 {
01881 RailFenceOffset rfo = RFO_FLAT_Y;
01882 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01883 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01884 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01885 }
01886
01887 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01888 {
01889 DrawTrackFence_NE(ti, base_image);
01890 DrawTrackFence_SW(ti, base_image);
01891 }
01892
01896 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01897 {
01898 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01899 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01900 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01901 }
01902
01906 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01907 {
01908 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01909 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01910 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01911 }
01912
01916 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01917 {
01918 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01919 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01920 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01921 }
01922
01926 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01927 {
01928 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01929 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01930 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01931 }
01932
01933
01934 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01935 {
01936
01937
01938 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01939 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01940
01941 switch (GetRailGroundType(ti->tile)) {
01942 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01943 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01944 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01945 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01946 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01947 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01948 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01949 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01950 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01951 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01952 case RAIL_GROUND_WATER: {
01953 Corner track_corner;
01954 if (IsHalftileSlope(ti->tileh)) {
01955
01956 track_corner = GetHalftileSlopeCorner(ti->tileh);
01957 } else {
01958
01959 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01960 }
01961 switch (track_corner) {
01962 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01963 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01964 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01965 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01966 default: NOT_REACHED();
01967 }
01968 break;
01969 }
01970 default: break;
01971 }
01972 }
01973
01974
01975 static const int INF = 1000;
01976 static const SubSprite _halftile_sub_sprite[4] = {
01977 { -INF , -INF , 32 - 33, INF },
01978 { -INF , 0 + 7, INF , INF },
01979 { -31 + 33, -INF , INF , INF },
01980 { -INF , -INF , INF , 30 - 23 }
01981 };
01982
01983 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01984 {
01985 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01986 }
01987
01988 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01989 {
01990 RailGroundType rgt = GetRailGroundType(ti->tile);
01991 Foundation f = GetRailFoundation(ti->tileh, track);
01992 Corner halftile_corner = CORNER_INVALID;
01993
01994 if (IsNonContinuousFoundation(f)) {
01995
01996 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01997
01998 track &= ~CornerToTrackBits(halftile_corner);
01999 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02000 }
02001
02002 DrawFoundation(ti, f);
02003
02004
02005
02006 if (rgt == RAIL_GROUND_WATER) {
02007 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
02008
02009 DrawShoreTile(ti->tileh);
02010 } else {
02011
02012 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
02013 }
02014 } else {
02015 SpriteID image;
02016
02017 switch (rgt) {
02018 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02019 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02020 default: image = SPR_FLAT_GRASS_TILE; break;
02021 }
02022
02023 image += SlopeToSpriteOffset(ti->tileh);
02024
02025 DrawGroundSprite(image, PAL_NONE);
02026 }
02027
02028 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02029 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02030 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
02031
02032 if (track == TRACK_BIT_NONE) {
02033
02034 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
02035 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
02036 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
02037 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
02038 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02039 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02040 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02041 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02042 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02043 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02044 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02045 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02046 } else {
02047 switch (track) {
02048
02049
02050 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02051 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02052 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02053 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02054 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02055 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02056 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02057 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02058 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02059 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02060 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02061
02062 default:
02063
02064 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02065 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02066 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02067 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02068 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02069 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02070 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02071 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02072 } else {
02073 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02074 }
02075
02076
02077 track &= ~pbs;
02078
02079
02080 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02081 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02082 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02083 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02084 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02085 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02086 }
02087
02088
02089 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02090 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02091 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02092 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02093 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02094 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02095 }
02096
02097 if (IsValidCorner(halftile_corner)) {
02098 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02099 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02100 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02101
02102
02103 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02104
02105 SpriteID image;
02106 switch (rgt) {
02107 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02108 case RAIL_GROUND_ICE_DESERT:
02109 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02110 default: image = SPR_FLAT_GRASS_TILE; break;
02111 }
02112
02113 image += SlopeToSpriteOffset(fake_slope);
02114
02115 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02116
02117 track = CornerToTrackBits(halftile_corner);
02118
02119 int offset;
02120 switch (track) {
02121 default: NOT_REACHED();
02122 case TRACK_BIT_UPPER: offset = RTO_N; break;
02123 case TRACK_BIT_LOWER: offset = RTO_S; break;
02124 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02125 case TRACK_BIT_LEFT: offset = RTO_W; break;
02126 }
02127
02128 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02129 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02130 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02131 }
02132 }
02133 }
02134
02140 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02141 {
02142 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02143
02144 if (rti->UsesOverlay()) {
02145 DrawTrackBitsOverlay(ti, track, rti);
02146 return;
02147 }
02148
02149 RailGroundType rgt = GetRailGroundType(ti->tile);
02150 Foundation f = GetRailFoundation(ti->tileh, track);
02151 Corner halftile_corner = CORNER_INVALID;
02152
02153 if (IsNonContinuousFoundation(f)) {
02154
02155 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02156
02157 track &= ~CornerToTrackBits(halftile_corner);
02158 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02159 }
02160
02161 DrawFoundation(ti, f);
02162
02163
02164 SpriteID image;
02165 PaletteID pal = PAL_NONE;
02166 const SubSprite *sub = NULL;
02167 bool junction = false;
02168
02169
02170 if (track == 0) {
02171
02172 if (rgt == RAIL_GROUND_WATER) {
02173 if (IsSteepSlope(ti->tileh)) {
02174 DrawShoreTile(ti->tileh);
02175 image = 0;
02176 } else {
02177 image = SPR_FLAT_WATER_TILE;
02178 }
02179 } else {
02180 switch (rgt) {
02181 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02182 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02183 default: image = SPR_FLAT_GRASS_TILE; break;
02184 }
02185 image += SlopeToSpriteOffset(ti->tileh);
02186 }
02187 } else {
02188 if (ti->tileh != SLOPE_FLAT) {
02189
02190 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02191 } else {
02192
02193 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02194 (image++, track == TRACK_BIT_X) ||
02195 (image++, track == TRACK_BIT_UPPER) ||
02196 (image++, track == TRACK_BIT_LOWER) ||
02197 (image++, track == TRACK_BIT_RIGHT) ||
02198 (image++, track == TRACK_BIT_LEFT) ||
02199 (image++, track == TRACK_BIT_CROSS) ||
02200
02201 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02202 (image++, track == TRACK_BIT_VERT) ||
02203
02204 (junction = true, false) ||
02205 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02206 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02207 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02208 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02209 (image++, true);
02210 }
02211
02212 switch (rgt) {
02213 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02214 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02215 case RAIL_GROUND_WATER: {
02216
02217 DrawShoreTile(ti->tileh);
02218 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02219 sub = &(_halftile_sub_sprite[track_corner]);
02220 break;
02221 }
02222 default: break;
02223 }
02224 }
02225
02226 if (image != 0) DrawGroundSprite(image, pal, sub);
02227
02228
02229 if (junction) {
02230 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02231 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02232 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02233 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02234 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02235 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02236 }
02237
02238
02239 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02240
02241 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02242 if (pbs & TRACK_BIT_X) {
02243 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02244 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02245 } else {
02246 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02247 }
02248 }
02249 if (pbs & TRACK_BIT_Y) {
02250 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02251 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02252 } else {
02253 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02254 }
02255 }
02256 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02257 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02258 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02259 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02260 }
02261
02262 if (IsValidCorner(halftile_corner)) {
02263 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02264
02265
02266 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02267 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02268 pal = PAL_NONE;
02269 switch (rgt) {
02270 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02271 case RAIL_GROUND_ICE_DESERT:
02272 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02273 default: break;
02274 }
02275 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02276
02277 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02278 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02279 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02280 }
02281 }
02282 }
02283
02291 enum SignalOffsets {
02292 SIGNAL_TO_SOUTHWEST = 0,
02293 SIGNAL_TO_NORTHEAST = 2,
02294 SIGNAL_TO_SOUTHEAST = 4,
02295 SIGNAL_TO_NORTHWEST = 6,
02296 SIGNAL_TO_EAST = 8,
02297 SIGNAL_TO_WEST = 10,
02298 SIGNAL_TO_SOUTH = 12,
02299 SIGNAL_TO_NORTH = 14,
02300 };
02301
02302 static void DrawSignals(TileIndex tile, TrackBits rails)
02303 {
02304 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02305
02306 if (!(rails & TRACK_BIT_Y)) {
02307 if (!(rails & TRACK_BIT_X)) {
02308 if (rails & TRACK_BIT_LEFT) {
02309 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02310 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02311 }
02312 if (rails & TRACK_BIT_RIGHT) {
02313 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02314 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02315 }
02316 if (rails & TRACK_BIT_UPPER) {
02317 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02318 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02319 }
02320 if (rails & TRACK_BIT_LOWER) {
02321 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02322 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02323 }
02324 } else {
02325 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02326 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02327 }
02328 } else {
02329 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02330 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02331 }
02332 }
02333
02334 static void DrawTile_Track(TileInfo *ti)
02335 {
02336 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02337
02338 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02339
02340 if (IsPlainRail(ti->tile)) {
02341 TrackBits rails = GetTrackBits(ti->tile);
02342
02343 DrawTrackBits(ti, rails);
02344
02345 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02346
02347 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02348
02349 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02350 } else {
02351
02352 const DrawTileSprites *dts;
02353 PaletteID pal = PAL_NONE;
02354 SpriteID relocation;
02355
02356 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02357
02358 if (IsInvisibilitySet(TO_BUILDINGS)) {
02359
02360 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02361 } else {
02362 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02363 }
02364
02365 SpriteID image;
02366 if (rti->UsesOverlay()) {
02367 image = SPR_FLAT_GRASS_TILE;
02368 } else {
02369 image = dts->ground.sprite;
02370 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02371 }
02372
02373
02374
02375 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02376 if (image != SPR_FLAT_GRASS_TILE) {
02377 image += rti->snow_offset;
02378 } else {
02379 image = SPR_FLAT_SNOW_DESERT_TILE;
02380 }
02381 }
02382
02383 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02384
02385 if (rti->UsesOverlay()) {
02386 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02387
02388 switch (GetRailDepotDirection(ti->tile)) {
02389 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02390 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02391 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02392 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02393 default: break;
02394 }
02395
02396 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02397 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02398
02399 switch (GetRailDepotDirection(ti->tile)) {
02400 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02401 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02402 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02403 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02404 default: break;
02405 }
02406 }
02407
02408 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02409 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02410 } else {
02411
02412 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02413 switch (GetRailDepotDirection(ti->tile)) {
02414 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02415 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02416 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02417 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02418 default: break;
02419 }
02420 }
02421
02422 relocation = rti->GetRailtypeSpriteOffset();
02423 }
02424
02425 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02426
02427 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02428 }
02429 DrawBridgeMiddle(ti);
02430 }
02431
02432 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02433 {
02434 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02435 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02436 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02437 uint32 offset = rti->GetRailtypeSpriteOffset();
02438
02439 x += 33;
02440 y += 17;
02441
02442 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02443 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02444
02445 DrawSprite(image, PAL_NONE, x, y);
02446
02447 if (rti->UsesOverlay()) {
02448 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02449
02450 switch (dir) {
02451 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02452 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02453 default: break;
02454 }
02455
02456 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02457 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02458 }
02459
02460 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02461 }
02462
02463 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02464 {
02465 uint z;
02466 Slope tileh = GetTileSlope(tile, &z);
02467
02468 if (tileh == SLOPE_FLAT) return z;
02469 if (IsPlainRail(tile)) {
02470 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02471 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02472 } else {
02473 return z + TILE_HEIGHT;
02474 }
02475 }
02476
02477 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02478 {
02479 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02480 }
02481
02482 static void TileLoop_Track(TileIndex tile)
02483 {
02484 RailGroundType old_ground = GetRailGroundType(tile);
02485 RailGroundType new_ground;
02486
02487 ReduceStuckCounter(tile);
02488
02489 if (old_ground == RAIL_GROUND_WATER) {
02490 TileLoop_Water(tile);
02491 return;
02492 }
02493
02494 switch (_settings_game.game_creation.landscape) {
02495 case LT_ARCTIC: {
02496 uint z;
02497 Slope slope = GetTileSlope(tile, &z);
02498 bool half = false;
02499
02500
02501
02502 if (IsPlainRail(tile)) {
02503 TrackBits track = GetTrackBits(tile);
02504 Foundation f = GetRailFoundation(slope, track);
02505
02506 switch (f) {
02507 case FOUNDATION_NONE:
02508
02509 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02510 break;
02511
02512 case FOUNDATION_INCLINED_X:
02513 case FOUNDATION_INCLINED_Y:
02514
02515 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02516 break;
02517
02518 case FOUNDATION_STEEP_LOWER:
02519
02520 z += TILE_HEIGHT;
02521 break;
02522
02523 default:
02524
02525 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02526 z += TILE_HEIGHT;
02527 break;
02528 }
02529
02530 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02531 } else {
02532
02533 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02534 }
02535
02536
02537
02538
02539
02540 if (z > GetSnowLine()) {
02541 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02542
02543 new_ground = RAIL_GROUND_HALF_SNOW;
02544 } else {
02545 new_ground = RAIL_GROUND_ICE_DESERT;
02546 }
02547 goto set_ground;
02548 }
02549 break;
02550 }
02551
02552 case LT_TROPIC:
02553 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02554 new_ground = RAIL_GROUND_ICE_DESERT;
02555 goto set_ground;
02556 }
02557 break;
02558 }
02559
02560 new_ground = RAIL_GROUND_GRASS;
02561
02562 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02563
02564 TrackBits rail = GetTrackBits(tile);
02565
02566 switch (rail) {
02567 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02568 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02569 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02570 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02571
02572 default: {
02573 Owner owner = GetTileOwner(tile);
02574
02575 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02576 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02577 (rail & TRACK_BIT_X)
02578 )) {
02579 TileIndex n = tile + TileDiffXY(0, -1);
02580 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02581
02582 if (!IsTileType(n, MP_RAILWAY) ||
02583 !IsTileOwner(n, owner) ||
02584 nrail == TRACK_BIT_UPPER ||
02585 nrail == TRACK_BIT_LEFT) {
02586 new_ground = RAIL_GROUND_FENCE_NW;
02587 }
02588 }
02589
02590 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02591 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02592 (rail & TRACK_BIT_X)
02593 )) {
02594 TileIndex n = tile + TileDiffXY(0, 1);
02595 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02596
02597 if (!IsTileType(n, MP_RAILWAY) ||
02598 !IsTileOwner(n, owner) ||
02599 nrail == TRACK_BIT_LOWER ||
02600 nrail == TRACK_BIT_RIGHT) {
02601 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02602 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02603 }
02604 }
02605
02606 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02607 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02608 (rail & TRACK_BIT_Y)
02609 )) {
02610 TileIndex n = tile + TileDiffXY(-1, 0);
02611 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02612
02613 if (!IsTileType(n, MP_RAILWAY) ||
02614 !IsTileOwner(n, owner) ||
02615 nrail == TRACK_BIT_UPPER ||
02616 nrail == TRACK_BIT_RIGHT) {
02617 new_ground = RAIL_GROUND_FENCE_NE;
02618 }
02619 }
02620
02621 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02622 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02623 (rail & TRACK_BIT_Y)
02624 )) {
02625 TileIndex n = tile + TileDiffXY(1, 0);
02626 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02627
02628 if (!IsTileType(n, MP_RAILWAY) ||
02629 !IsTileOwner(n, owner) ||
02630 nrail == TRACK_BIT_LOWER ||
02631 nrail == TRACK_BIT_LEFT) {
02632 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02633 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02634 }
02635 }
02636 break;
02637 }
02638 }
02639 }
02640
02641 set_ground:
02642 if (old_ground != new_ground) {
02643 SetRailGroundType(tile, new_ground);
02644 MarkTileDirtyByTile(tile);
02645 }
02646 }
02647
02648
02649 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02650 {
02651
02652 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02653 TrackBits tb = GetTrackBits(tile);
02654 switch (tb) {
02655 default: NOT_REACHED();
02656 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02657 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02658 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02659 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02660 }
02661 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02662 }
02663
02664 if (mode != TRANSPORT_RAIL) return 0;
02665
02666 TrackBits trackbits = TRACK_BIT_NONE;
02667 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02668
02669 switch (GetRailTileType(tile)) {
02670 default: NOT_REACHED();
02671 case RAIL_TILE_NORMAL:
02672 trackbits = GetTrackBits(tile);
02673 break;
02674
02675 case RAIL_TILE_SIGNALS: {
02676 trackbits = GetTrackBits(tile);
02677 byte a = GetPresentSignals(tile);
02678 uint b = GetSignalStates(tile);
02679
02680 b &= a;
02681
02682
02683
02684
02685
02686
02687 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02688 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02689
02690 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02691 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02692 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02693 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02694
02695 break;
02696 }
02697
02698 case RAIL_TILE_DEPOT: {
02699 DiagDirection dir = GetRailDepotDirection(tile);
02700
02701 if (side != INVALID_DIAGDIR && side != dir) break;
02702
02703 trackbits = DiagDirToDiagTrackBits(dir);
02704 break;
02705 }
02706 }
02707
02708 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02709 }
02710
02711 static bool ClickTile_Track(TileIndex tile)
02712 {
02713 if (!IsRailDepot(tile)) return false;
02714
02715 ShowDepotWindow(tile, VEH_TRAIN);
02716 return true;
02717 }
02718
02719 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02720 {
02721 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02722 td->rail_speed = rti->max_speed;
02723 td->owner[0] = GetTileOwner(tile);
02724 switch (GetRailTileType(tile)) {
02725 case RAIL_TILE_NORMAL:
02726 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02727 break;
02728
02729 case RAIL_TILE_SIGNALS: {
02730 static const StringID signal_type[8][8] = {
02731 {
02732 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02733 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02734 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02735 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02736 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02737 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02738 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PROGSIGNALS,
02739 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SPEEDSIGNALS
02740 },
02741 {
02742 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02743 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02744 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02745 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02746 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02747 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02748 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PROGSIGNALS,
02749 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_SPEEDSIGNALS
02750 },
02751 {
02752 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02753 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02754 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02755 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02756 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02757 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02758 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PROGSIGNALS,
02759 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_SPEEDSIGNALS
02760 },
02761 {
02762 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02763 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02764 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02765 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02766 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02767 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02768 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PROGSIGNALS,
02769 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_SPEEDSIGNALS
02770 },
02771 {
02772 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02773 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02774 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02775 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02776 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02777 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02778 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_PROGSIGNALS,
02779 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_SPEEDSIGNALS
02780 },
02781 {
02782 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02783 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02784 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02785 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02786 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02787 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS,
02788 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_PROGSIGNALS,
02789 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_SPEEDSIGNALS
02790 },
02791 {
02792 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PROGSIGNALS,
02793 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PROGSIGNALS,
02794 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PROGSIGNALS,
02795 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PROGSIGNALS,
02796 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_PROGSIGNALS,
02797 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_PROGSIGNALS,
02798 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PROGSIGNALS,
02799 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PROG_SPEEDSIGNALS
02800 },
02801 {
02802 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SPEEDSIGNALS,
02803 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_SPEEDSIGNALS,
02804 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_SPEEDSIGNALS,
02805 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_SPEEDSIGNALS,
02806 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_SPEEDSIGNALS,
02807 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_SPEEDSIGNALS,
02808 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PROG_SPEEDSIGNALS,
02809 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_SPEEDSIGNALS
02810 }
02811 };
02812
02813 SignalType primary_signal;
02814 SignalType secondary_signal;
02815 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02816 primary_signal = GetSignalType(tile, TRACK_UPPER);
02817 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02818 } else {
02819 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02820 }
02821
02822 td->str = signal_type[secondary_signal][primary_signal];
02823 break;
02824 }
02825
02826 case RAIL_TILE_DEPOT:
02827 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02828 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02829 if (td->rail_speed > 0) {
02830 td->rail_speed = min(td->rail_speed, 61);
02831 } else {
02832 td->rail_speed = 61;
02833 }
02834 }
02835 td->build_date = Depot::GetByTile(tile)->build_date;
02836 break;
02837
02838 default:
02839 NOT_REACHED();
02840 }
02841 }
02842
02843 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02844 {
02845 if (!IsTileOwner(tile, old_owner)) return;
02846
02847 if (new_owner != INVALID_OWNER) {
02848 SetTileOwner(tile, new_owner);
02849 } else {
02850 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02851 }
02852 }
02853
02854 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02855 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02856 static const int8 _deltacoord_leaveoffset[8] = {
02857 -1, 0, 1, 0,
02858 0, 1, 0, -1
02859 };
02860
02861
02868 int TicksToLeaveDepot(const Train *v)
02869 {
02870 DiagDirection dir = GetRailDepotDirection(v->tile);
02871 int length = v->gcache.cached_veh_length;
02872
02873 switch (dir) {
02874 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02875 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02876 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02877 default:
02878 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02879 }
02880
02881 return 0;
02882 }
02883
02888 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02889 {
02890
02891 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02892
02893 Train *v = Train::From(u);
02894
02895
02896 DiagDirection dir = GetRailDepotDirection(tile);
02897
02898
02899
02900 int length = v->gcache.cached_veh_length;
02901
02902 byte fract_coord_leave =
02903 ((_fractcoords_enter[dir] & 0x0F) +
02904 (length + 1) * _deltacoord_leaveoffset[dir]) +
02905 (((_fractcoords_enter[dir] >> 4) +
02906 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02907
02908 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02909
02910 if (_fractcoords_behind[dir] == fract_coord) {
02911
02912 return VETSB_CANNOT_ENTER;
02913 } else if (_fractcoords_enter[dir] == fract_coord) {
02914 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02915
02916 v->track = TRACK_BIT_DEPOT,
02917 v->vehstatus |= VS_HIDDEN;
02918 v->direction = ReverseDir(v->direction);
02919 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02920 v->tile = tile;
02921
02922 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02923 return VETSB_ENTERED_WORMHOLE;
02924 }
02925 } else if (fract_coord_leave == fract_coord) {
02926 if (DiagDirToDir(dir) == v->direction) {
02927
02928 if ((v = v->Next()) != NULL) {
02929 v->vehstatus &= ~VS_HIDDEN;
02930 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02931 }
02932 }
02933 }
02934
02935 return VETSB_CONTINUE;
02936 }
02937
02949 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02950 {
02951 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02952
02953
02954 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02955
02956
02957 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02958 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02959
02960 Corner track_corner;
02961 switch (rail_bits) {
02962 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02963 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02964 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02965 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02966
02967
02968 default:
02969 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02970 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02971 }
02972
02973
02974 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02975 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02976 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02977
02978 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02979
02980 if (tileh_old != tileh_new) {
02981
02982 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02983 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02984 }
02985 return cost;
02986 }
02987
02988 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02989 {
02990 uint z_old;
02991 Slope tileh_old = GetTileSlope(tile, &z_old);
02992 if (IsPlainRail(tile)) {
02993 TrackBits rail_bits = GetTrackBits(tile);
02994
02995 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02996
02997
02998 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02999
03000
03001 Corner allowed_corner;
03002 switch (rail_bits) {
03003 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
03004 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
03005 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
03006 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
03007 default: return autoslope_result;
03008 }
03009
03010 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
03011
03012
03013 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
03014
03015
03016 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
03017 if (allowed_corner == corner) continue;
03018 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
03019 }
03020
03021
03022 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
03023
03024
03025 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
03026 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
03027 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
03028 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
03029 }
03030 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
03031 }
03032
03033
03034 extern const TileTypeProcs _tile_type_rail_procs = {
03035 DrawTile_Track,
03036 GetSlopeZ_Track,
03037 ClearTile_Track,
03038 NULL,
03039 GetTileDesc_Track,
03040 GetTileTrackStatus_Track,
03041 ClickTile_Track,
03042 NULL,
03043 TileLoop_Track,
03044 ChangeTileOwner_Track,
03045 NULL,
03046 VehicleEnter_Track,
03047 GetFoundation_Track,
03048 TerraformTile_Track,
03049 };