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