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) 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) ? 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 = 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 if (water_ground && !(flags & DC_BANKRUPT)) {
01796 CommandCost ret = EnsureNoVehicleOnGround(tile);
01797 if (ret.Failed()) return ret;
01798
01799
01800 if (flags & DC_EXEC) DoClearSquare(tile);
01801 cost.AddCost(_price[PR_CLEAR_WATER]);
01802 }
01803
01804 return cost;
01805 }
01806
01807 case RAIL_TILE_DEPOT:
01808 return RemoveTrainDepot(tile, flags);
01809
01810 default:
01811 return CMD_ERROR;
01812 }
01813 }
01814
01819 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01820 {
01821 switch (track) {
01822 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01823 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01824 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01825 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01826 default: break;
01827 }
01828 return GetSlopePixelZ(x, y);
01829 }
01830
01831 static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
01832 {
01833 bool side;
01834 switch (_settings_game.construction.train_signal_side) {
01835 case 0: side = false; break;
01836 case 2: side = true; break;
01837 default: side = _settings_game.vehicle.road_side != 0; break;
01838 }
01839 static const Point SignalPositions[2][12] = {
01840 {
01841
01842 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01843
01844 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01845 }, {
01846
01847 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01848
01849 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01850 }
01851 };
01852
01853 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01854 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01855
01856 SignalType type = GetSignalType(tile, track);
01857 SignalVariant variant = GetSignalVariant(tile, track);
01858
01859 SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition);
01860 if (sprite != 0) {
01861 sprite += image;
01862 } else {
01863
01864 sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16;
01865 sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01866 }
01867
01868 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01869 }
01870
01871 static uint32 _drawtile_track_palette;
01872
01873
01874 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01875 {
01876 RailFenceOffset rfo = RFO_FLAT_X;
01877 if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01878 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01879 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01880 }
01881
01882 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01883 {
01884 RailFenceOffset rfo = RFO_FLAT_X;
01885 if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01886 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01887 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01888 }
01889
01890 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01891 {
01892 DrawTrackFence_NW(ti, base_image);
01893 DrawTrackFence_SE(ti, base_image);
01894 }
01895
01896 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01897 {
01898 RailFenceOffset rfo = RFO_FLAT_Y;
01899 if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01900 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01901 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01902 }
01903
01904 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01905 {
01906 RailFenceOffset rfo = RFO_FLAT_Y;
01907 if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01908 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01909 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01910 }
01911
01912 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01913 {
01914 DrawTrackFence_NE(ti, base_image);
01915 DrawTrackFence_SW(ti, base_image);
01916 }
01917
01921 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01922 {
01923 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01924 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01925 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01926 }
01927
01931 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01932 {
01933 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01934 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01935 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01936 }
01937
01941 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01942 {
01943 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01944 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01945 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01946 }
01947
01951 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01952 {
01953 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01954 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01955 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01956 }
01957
01958
01959 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01960 {
01961
01962
01963 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01964 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01965
01966 switch (GetRailGroundType(ti->tile)) {
01967 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01968 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01969 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01970 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01971 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01972 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01973 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01974 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01975 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01976 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01977 case RAIL_GROUND_WATER: {
01978 Corner track_corner;
01979 if (IsHalftileSlope(ti->tileh)) {
01980
01981 track_corner = GetHalftileSlopeCorner(ti->tileh);
01982 } else {
01983
01984 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01985 }
01986 switch (track_corner) {
01987 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01988 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01989 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01990 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01991 default: NOT_REACHED();
01992 }
01993 break;
01994 }
01995 default: break;
01996 }
01997 }
01998
01999
02000 static const int INF = 1000;
02001 static const SubSprite _halftile_sub_sprite[4] = {
02002 { -INF , -INF , 32 - 33, INF },
02003 { -INF , 0 + 7, INF , INF },
02004 { -31 + 33, -INF , INF , INF },
02005 { -INF , -INF , INF , 30 - 23 }
02006 };
02007
02008 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
02009 {
02010 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
02011 }
02012
02013 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
02014 {
02015 RailGroundType rgt = GetRailGroundType(ti->tile);
02016 Foundation f = GetRailFoundation(ti->tileh, track);
02017 Corner halftile_corner = CORNER_INVALID;
02018
02019 if (IsNonContinuousFoundation(f)) {
02020
02021 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02022
02023 track &= ~CornerToTrackBits(halftile_corner);
02024 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02025 }
02026
02027 DrawFoundation(ti, f);
02028
02029
02030
02031 if (rgt == RAIL_GROUND_WATER) {
02032 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
02033
02034 DrawShoreTile(ti->tileh);
02035 } else {
02036
02037 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
02038 }
02039 } else {
02040 SpriteID image;
02041
02042 switch (rgt) {
02043 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02044 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02045 default: image = SPR_FLAT_GRASS_TILE; break;
02046 }
02047
02048 image += SlopeToSpriteOffset(ti->tileh);
02049
02050 DrawGroundSprite(image, PAL_NONE);
02051 }
02052
02053 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02054 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02055 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
02056
02057 if (track == TRACK_BIT_NONE) {
02058
02059 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
02060 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
02061 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
02062 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
02063 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02064 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02065 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02066 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02067 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02068 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02069 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02070 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02071 } else {
02072 switch (track) {
02073
02074
02075 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02076 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02077 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02078 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02079 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02080 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02081 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02082 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02083 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02084 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02085 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02086
02087 default:
02088
02089 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02090 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02091 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02092 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02093 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02094 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02095 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02096 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02097 } else {
02098 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02099 }
02100
02101
02102 track &= ~pbs;
02103
02104
02105 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02106 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02107 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02108 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02109 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02110 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02111 }
02112
02113
02114 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02115 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02116 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02117 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02118 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02119 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02120 }
02121
02122 if (IsValidCorner(halftile_corner)) {
02123 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02124 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02125 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02126
02127
02128 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02129
02130 SpriteID image;
02131 switch (rgt) {
02132 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02133 case RAIL_GROUND_ICE_DESERT:
02134 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02135 default: image = SPR_FLAT_GRASS_TILE; break;
02136 }
02137
02138 image += SlopeToSpriteOffset(fake_slope);
02139
02140 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02141
02142 track = CornerToTrackBits(halftile_corner);
02143
02144 int offset;
02145 switch (track) {
02146 default: NOT_REACHED();
02147 case TRACK_BIT_UPPER: offset = RTO_N; break;
02148 case TRACK_BIT_LOWER: offset = RTO_S; break;
02149 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02150 case TRACK_BIT_LEFT: offset = RTO_W; break;
02151 }
02152
02153 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02154 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02155 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02156 }
02157 }
02158 }
02159
02165 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02166 {
02167 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02168
02169 if (rti->UsesOverlay()) {
02170 DrawTrackBitsOverlay(ti, track, rti);
02171 return;
02172 }
02173
02174 RailGroundType rgt = GetRailGroundType(ti->tile);
02175 Foundation f = GetRailFoundation(ti->tileh, track);
02176 Corner halftile_corner = CORNER_INVALID;
02177
02178 if (IsNonContinuousFoundation(f)) {
02179
02180 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02181
02182 track &= ~CornerToTrackBits(halftile_corner);
02183 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02184 }
02185
02186 DrawFoundation(ti, f);
02187
02188
02189 SpriteID image;
02190 PaletteID pal = PAL_NONE;
02191 const SubSprite *sub = NULL;
02192 bool junction = false;
02193
02194
02195 if (track == 0) {
02196
02197 if (rgt == RAIL_GROUND_WATER) {
02198 if (IsSteepSlope(ti->tileh)) {
02199 DrawShoreTile(ti->tileh);
02200 image = 0;
02201 } else {
02202 image = SPR_FLAT_WATER_TILE;
02203 }
02204 } else {
02205 switch (rgt) {
02206 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02207 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02208 default: image = SPR_FLAT_GRASS_TILE; break;
02209 }
02210 image += SlopeToSpriteOffset(ti->tileh);
02211 }
02212 } else {
02213 if (ti->tileh != SLOPE_FLAT) {
02214
02215 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02216 } else {
02217
02218 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02219 (image++, track == TRACK_BIT_X) ||
02220 (image++, track == TRACK_BIT_UPPER) ||
02221 (image++, track == TRACK_BIT_LOWER) ||
02222 (image++, track == TRACK_BIT_RIGHT) ||
02223 (image++, track == TRACK_BIT_LEFT) ||
02224 (image++, track == TRACK_BIT_CROSS) ||
02225
02226 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02227 (image++, track == TRACK_BIT_VERT) ||
02228
02229 (junction = true, false) ||
02230 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02231 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02232 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02233 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02234 (image++, true);
02235 }
02236
02237 switch (rgt) {
02238 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02239 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02240 case RAIL_GROUND_WATER: {
02241
02242 DrawShoreTile(ti->tileh);
02243 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02244 sub = &(_halftile_sub_sprite[track_corner]);
02245 break;
02246 }
02247 default: break;
02248 }
02249 }
02250
02251 if (image != 0) DrawGroundSprite(image, pal, sub);
02252
02253
02254 if (junction) {
02255 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02256 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02257 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02258 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02259 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02260 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02261 }
02262
02263
02264 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02265
02266 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02267 if (pbs & TRACK_BIT_X) {
02268 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02269 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02270 } else {
02271 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02272 }
02273 }
02274 if (pbs & TRACK_BIT_Y) {
02275 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02276 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02277 } else {
02278 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02279 }
02280 }
02281 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02282 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02283 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02284 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02285 }
02286
02287 if (IsValidCorner(halftile_corner)) {
02288 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02289
02290
02291 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02292 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02293 pal = PAL_NONE;
02294 switch (rgt) {
02295 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02296 case RAIL_GROUND_ICE_DESERT:
02297 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02298 default: break;
02299 }
02300 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02301
02302 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02303 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02304 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02305 }
02306 }
02307 }
02308
02309 static void DrawSignals(TileIndex tile, TrackBits rails, const RailtypeInfo *rti)
02310 {
02311 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, rti, t, GetSingleSignalState(tile, x), y, z)
02312
02313 if (!(rails & TRACK_BIT_Y)) {
02314 if (!(rails & TRACK_BIT_X)) {
02315 if (rails & TRACK_BIT_LEFT) {
02316 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02317 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02318 }
02319 if (rails & TRACK_BIT_RIGHT) {
02320 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02321 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02322 }
02323 if (rails & TRACK_BIT_UPPER) {
02324 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02325 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02326 }
02327 if (rails & TRACK_BIT_LOWER) {
02328 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02329 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02330 }
02331 } else {
02332 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02333 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02334 }
02335 } else {
02336 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02337 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02338 }
02339 }
02340
02341 static void DrawTile_Track(TileInfo *ti)
02342 {
02343 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02344
02345 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02346
02347 if (IsPlainRail(ti->tile)) {
02348 TrackBits rails = GetTrackBits(ti->tile);
02349
02350 DrawTrackBits(ti, rails);
02351
02352 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02353
02354 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02355
02356 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti);
02357 } else {
02358
02359 const DrawTileSprites *dts;
02360 PaletteID pal = PAL_NONE;
02361 SpriteID relocation;
02362
02363 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02364
02365 if (IsInvisibilitySet(TO_BUILDINGS)) {
02366
02367 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02368 } else {
02369 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02370 }
02371
02372 SpriteID image;
02373 if (rti->UsesOverlay()) {
02374 image = SPR_FLAT_GRASS_TILE;
02375 } else {
02376 image = dts->ground.sprite;
02377 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02378 }
02379
02380
02381
02382 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02383 if (image != SPR_FLAT_GRASS_TILE) {
02384 image += rti->snow_offset;
02385 } else {
02386 image = SPR_FLAT_SNOW_DESERT_TILE;
02387 }
02388 }
02389
02390 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02391
02392 if (rti->UsesOverlay()) {
02393 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02394
02395 switch (GetRailDepotDirection(ti->tile)) {
02396 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02397 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02398 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02399 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02400 default: break;
02401 }
02402
02403 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02404 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02405
02406 switch (GetRailDepotDirection(ti->tile)) {
02407 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02408 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02409 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02410 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02411 default: break;
02412 }
02413 }
02414 } else {
02415
02416 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02417 switch (GetRailDepotDirection(ti->tile)) {
02418 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02419 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02420 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02421 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02422 default: break;
02423 }
02424 }
02425 }
02426 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02427 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02428
02429 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02430
02431 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02432 }
02433 DrawBridgeMiddle(ti);
02434 }
02435
02436 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02437 {
02438 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02439 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02440 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02441 uint32 offset = rti->GetRailtypeSpriteOffset();
02442
02443 x += 33;
02444 y += 17;
02445
02446 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02447 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02448
02449 DrawSprite(image, PAL_NONE, x, y);
02450
02451 if (rti->UsesOverlay()) {
02452 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02453
02454 switch (dir) {
02455 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02456 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02457 default: break;
02458 }
02459 }
02460 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02461 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02462
02463 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02464 }
02465
02466 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02467 {
02468 if (IsPlainRail(tile)) {
02469 int z;
02470 Slope tileh = GetTilePixelSlope(tile, &z);
02471 if (tileh == SLOPE_FLAT) return z;
02472
02473 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02474 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02475 } else {
02476 return GetTileMaxPixelZ(tile);
02477 }
02478 }
02479
02480 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02481 {
02482 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02483 }
02484
02485 static void TileLoop_Track(TileIndex tile)
02486 {
02487 RailGroundType old_ground = GetRailGroundType(tile);
02488 RailGroundType new_ground;
02489
02490 if (old_ground == RAIL_GROUND_WATER) {
02491 TileLoop_Water(tile);
02492 return;
02493 }
02494
02495 switch (_settings_game.game_creation.landscape) {
02496 case LT_ARCTIC: {
02497 int z;
02498 Slope slope = GetTileSlope(tile, &z);
02499 bool half = false;
02500
02501
02502
02503 if (IsPlainRail(tile)) {
02504 TrackBits track = GetTrackBits(tile);
02505 Foundation f = GetRailFoundation(slope, track);
02506
02507 switch (f) {
02508 case FOUNDATION_NONE:
02509
02510 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02511 break;
02512
02513 case FOUNDATION_INCLINED_X:
02514 case FOUNDATION_INCLINED_Y:
02515
02516 if (IsSteepSlope(slope)) z++;
02517 break;
02518
02519 case FOUNDATION_STEEP_LOWER:
02520
02521 z++;
02522 break;
02523
02524 default:
02525
02526 if (IsSteepSlope(slope)) z++;
02527 z++;
02528 break;
02529 }
02530
02531 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02532 } else {
02533
02534 if (slope != SLOPE_FLAT) z++;
02535 }
02536
02537
02538
02539
02540
02541 if (z > GetSnowLine()) {
02542 if (half && z - GetSnowLine() == 1) {
02543
02544 new_ground = RAIL_GROUND_HALF_SNOW;
02545 } else {
02546 new_ground = RAIL_GROUND_ICE_DESERT;
02547 }
02548 goto set_ground;
02549 }
02550 break;
02551 }
02552
02553 case LT_TROPIC:
02554 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02555 new_ground = RAIL_GROUND_ICE_DESERT;
02556 goto set_ground;
02557 }
02558 break;
02559 }
02560
02561 new_ground = RAIL_GROUND_GRASS;
02562
02563 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02564
02565 TrackBits rail = GetTrackBits(tile);
02566
02567 Owner owner = GetTileOwner(tile);
02568 byte fences = 0;
02569
02570 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
02571 static const TrackBits dir_to_trackbits[DIAGDIR_END] = {TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW};
02572
02573
02574 if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
02575
02576 TileIndex tile2 = tile + TileOffsByDiagDir(d);
02577
02578
02579 if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
02580 IsTileType(tile2, MP_ROAD) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
02581 fences |= 1 << d;
02582 }
02583 }
02584
02585 switch (fences) {
02586 case 0: break;
02587 case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
02588 case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
02589 case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
02590 case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
02591 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
02592 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
02593 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
02594 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02595 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02596 case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
02597 default: NOT_REACHED();
02598 }
02599 }
02600
02601 set_ground:
02602 if (old_ground != new_ground) {
02603 SetRailGroundType(tile, new_ground);
02604 MarkTileDirtyByTile(tile);
02605 }
02606 }
02607
02608
02609 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02610 {
02611
02612 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02613 TrackBits tb = GetTrackBits(tile);
02614 switch (tb) {
02615 default: NOT_REACHED();
02616 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02617 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02618 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02619 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02620 }
02621 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02622 }
02623
02624 if (mode != TRANSPORT_RAIL) return 0;
02625
02626 TrackBits trackbits = TRACK_BIT_NONE;
02627 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02628
02629 switch (GetRailTileType(tile)) {
02630 default: NOT_REACHED();
02631 case RAIL_TILE_NORMAL:
02632 trackbits = GetTrackBits(tile);
02633 break;
02634
02635 case RAIL_TILE_SIGNALS: {
02636 trackbits = GetTrackBits(tile);
02637 byte a = GetPresentSignals(tile);
02638 uint b = GetSignalStates(tile);
02639
02640 b &= a;
02641
02642
02643
02644
02645
02646
02647 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02648 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02649
02650 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02651 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02652 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02653 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02654
02655 break;
02656 }
02657
02658 case RAIL_TILE_DEPOT: {
02659 DiagDirection dir = GetRailDepotDirection(tile);
02660
02661 if (side != INVALID_DIAGDIR && side != dir) break;
02662
02663 trackbits = DiagDirToDiagTrackBits(dir);
02664 break;
02665 }
02666 }
02667
02668 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02669 }
02670
02671 static bool ClickTile_Track(TileIndex tile)
02672 {
02673 if (!IsRailDepot(tile)) return false;
02674
02675 ShowDepotWindow(tile, VEH_TRAIN);
02676 return true;
02677 }
02678
02679 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02680 {
02681 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02682 td->rail_speed = rti->max_speed;
02683 td->owner[0] = GetTileOwner(tile);
02684 SetDParamX(td->dparam, 0, rti->strings.name);
02685 switch (GetRailTileType(tile)) {
02686 case RAIL_TILE_NORMAL:
02687 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02688 break;
02689
02690 case RAIL_TILE_SIGNALS: {
02691 static const StringID signal_type[6][6] = {
02692 {
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02696 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02697 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02699 },
02700 {
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02704 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02705 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02707 },
02708 {
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02712 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02713 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02715 },
02716 {
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02720 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02721 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02723 },
02724 {
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02728 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02729 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02730 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02731 },
02732 {
02733 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02734 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02735 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02736 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02737 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02738 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02739 }
02740 };
02741
02742 SignalType primary_signal;
02743 SignalType secondary_signal;
02744 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02745 primary_signal = GetSignalType(tile, TRACK_UPPER);
02746 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02747 } else {
02748 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02749 }
02750
02751 td->str = signal_type[secondary_signal][primary_signal];
02752 break;
02753 }
02754
02755 case RAIL_TILE_DEPOT:
02756 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02757 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02758 if (td->rail_speed > 0) {
02759 td->rail_speed = min(td->rail_speed, 61);
02760 } else {
02761 td->rail_speed = 61;
02762 }
02763 }
02764 td->build_date = Depot::GetByTile(tile)->build_date;
02765 break;
02766
02767 default:
02768 NOT_REACHED();
02769 }
02770 }
02771
02772 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02773 {
02774 if (!IsTileOwner(tile, old_owner)) return;
02775
02776 if (new_owner != INVALID_OWNER) {
02777
02778 uint num_pieces = 1;
02779 if (IsPlainRail(tile)) {
02780 TrackBits bits = GetTrackBits(tile);
02781 num_pieces = CountBits(bits);
02782 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02783 }
02784 RailType rt = GetRailType(tile);
02785 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02786 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02787
02788 if (HasSignals(tile)) {
02789 uint num_sigs = CountBits(GetPresentSignals(tile));
02790 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02791 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02792 }
02793
02794 SetTileOwner(tile, new_owner);
02795 } else {
02796 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02797 }
02798 }
02799
02800 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02801 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02802 static const int8 _deltacoord_leaveoffset[8] = {
02803 -1, 0, 1, 0,
02804 0, 1, 0, -1
02805 };
02806
02807
02814 int TicksToLeaveDepot(const Train *v)
02815 {
02816 DiagDirection dir = GetRailDepotDirection(v->tile);
02817 int length = v->CalcNextVehicleOffset();
02818
02819 switch (dir) {
02820 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02821 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02822 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02823 default:
02824 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02825 }
02826
02827 return 0;
02828 }
02829
02834 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02835 {
02836
02837 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02838
02839 Train *v = Train::From(u);
02840
02841
02842 DiagDirection dir = GetRailDepotDirection(tile);
02843
02844
02845 int length = v->CalcNextVehicleOffset();
02846
02847 byte fract_coord_leave =
02848 ((_fractcoords_enter[dir] & 0x0F) +
02849 (length + 1) * _deltacoord_leaveoffset[dir]) +
02850 (((_fractcoords_enter[dir] >> 4) +
02851 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02852
02853 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02854
02855 if (_fractcoords_behind[dir] == fract_coord) {
02856
02857 return VETSB_CANNOT_ENTER;
02858 } else if (_fractcoords_enter[dir] == fract_coord) {
02859 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02860
02861 v->track = TRACK_BIT_DEPOT,
02862 v->vehstatus |= VS_HIDDEN;
02863 v->direction = ReverseDir(v->direction);
02864 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02865 v->tile = tile;
02866
02867 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02868 return VETSB_ENTERED_WORMHOLE;
02869 }
02870 } else if (fract_coord_leave == fract_coord) {
02871 if (DiagDirToDir(dir) == v->direction) {
02872
02873 if ((v = v->Next()) != NULL) {
02874 v->vehstatus &= ~VS_HIDDEN;
02875 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02876 }
02877 }
02878 }
02879
02880 return VETSB_CONTINUE;
02881 }
02882
02894 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02895 {
02896 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02897
02898
02899 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02900
02901
02902 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02903 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02904
02905 Corner track_corner;
02906 switch (rail_bits) {
02907 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02908 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02909 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02910 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02911
02912
02913 default:
02914 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02915 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02916 }
02917
02918
02919 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02920 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02921 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02922
02923 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02924
02925 if (tileh_old != tileh_new) {
02926
02927 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02928 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02929 }
02930 return cost;
02931 }
02932
02933 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02934 {
02935 int z_old;
02936 Slope tileh_old = GetTileSlope(tile, &z_old);
02937 if (IsPlainRail(tile)) {
02938 TrackBits rail_bits = GetTrackBits(tile);
02939
02940 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02941
02942
02943 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02944
02945
02946 Corner allowed_corner;
02947 switch (rail_bits) {
02948 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02949 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02950 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02951 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02952 default: return autoslope_result;
02953 }
02954
02955 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02956
02957
02958 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02959
02960
02961 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02962 if (allowed_corner == corner) continue;
02963 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02964 }
02965
02966
02967 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02968
02969
02970 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02971 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02972 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02973 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02974 }
02975 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02976 }
02977
02978
02979 extern const TileTypeProcs _tile_type_rail_procs = {
02980 DrawTile_Track,
02981 GetSlopePixelZ_Track,
02982 ClearTile_Track,
02983 NULL,
02984 GetTileDesc_Track,
02985 GetTileTrackStatus_Track,
02986 ClickTile_Track,
02987 NULL,
02988 TileLoop_Track,
02989 ChangeTileOwner_Track,
02990 NULL,
02991 VehicleEnter_Track,
02992 GetFoundation_Track,
02993 TerraformTile_Track,
02994 };