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