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