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