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