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
01026 TrackBits trackbits = GetTrackBits(tile);
01027 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
01028 trackbits != TRACK_BIT_HORZ &&
01029 trackbits != TRACK_BIT_VERT) {
01030 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01031 }
01032 }
01033
01034
01035 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01036
01037
01038 if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01039
01040 CommandCost cost;
01041 if (!HasSignalOnTrack(tile, track)) {
01042
01043 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01044 } else {
01045 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01046
01047 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01048
01049 } else if (convert_signal) {
01050
01051 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01052
01053 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01054 } else {
01055
01056 cost = CommandCost();
01057 }
01058
01059 } else {
01060
01061 cost = CommandCost();
01062 }
01063 }
01064
01065 if (flags & DC_EXEC) {
01066 Train *v = NULL;
01067
01068
01069
01070 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01071 v = GetTrainForReservation(tile, track);
01072 if (v != NULL) FreeTrainTrackReservation(v);
01073 }
01074
01075 if (!HasSignals(tile)) {
01076
01077 SetHasSignals(tile, true);
01078 SetSignalStates(tile, 0xF);
01079 SetPresentSignals(tile, 0);
01080 SetSignalType(tile, track, sigtype);
01081 SetSignalVariant(tile, track, sigvar);
01082 }
01083
01084
01085 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01086
01087 if (p2 == 0) {
01088 if (!HasSignalOnTrack(tile, track)) {
01089
01090 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01091 SetSignalType(tile, track, sigtype);
01092 SetSignalVariant(tile, track, sigvar);
01093 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01094 } else {
01095 if (convert_signal) {
01096
01097 if (ctrl_pressed) {
01098
01099 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01100
01101 sigtype = GetSignalType(tile, track);
01102 } else {
01103
01104 SetSignalType(tile, track, sigtype);
01105 SetSignalVariant(tile, track, sigvar);
01106 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01107 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01108 }
01109 }
01110
01111 } else if (ctrl_pressed) {
01112
01113 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01114
01115 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01116
01117 SetSignalType(tile, track, sigtype);
01118 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01119 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01120 }
01121 } else {
01122
01123 CycleSignalSide(tile, track);
01124
01125 sigtype = GetSignalType(tile, track);
01126 }
01127 }
01128 } else {
01129
01130
01131 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01132 SetSignalVariant(tile, track, sigvar);
01133 SetSignalType(tile, track, sigtype);
01134 }
01135
01136
01137 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01138 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01139
01140 if (IsPbsSignal(sigtype)) {
01141
01142 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01143 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) && EnsureNoVehicleOnGround(tile).Succeeded() ? UINT_MAX : 0) & mask));
01144 }
01145 MarkTileDirtyByTile(tile);
01146 AddTrackToSignalBuffer(tile, track, _current_company);
01147 YapfNotifyTrackLayoutChange(tile, track);
01148 if (v != NULL) {
01149
01150 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01151 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01152 TryPathReserve(v, true);
01153 }
01154 }
01155 }
01156
01157 return cost;
01158 }
01159
01160 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01161 {
01162 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01163 if (tile == INVALID_TILE) return false;
01164
01165
01166 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01167
01168 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01169 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01170
01171
01172 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01173
01174
01175 trackdir = RemoveFirstTrackdir(&trackdirbits);
01176
01177
01178 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01179
01180 switch (GetTileType(tile)) {
01181 case MP_RAILWAY:
01182 if (IsRailDepot(tile)) return false;
01183 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01184 signal_ctr++;
01185 if (IsDiagonalTrackdir(trackdir)) {
01186 signal_ctr++;
01187
01188 ClrBit(signal_ctr, 0);
01189 }
01190 return true;
01191
01192 case MP_ROAD:
01193 if (!IsLevelCrossing(tile)) return false;
01194 signal_ctr += 2;
01195 return true;
01196
01197 case MP_TUNNELBRIDGE: {
01198 TileIndex orig_tile = tile;
01199
01200 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01201 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01202
01203
01204
01205 tile = GetOtherTunnelBridgeEnd(tile);
01206
01207 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01208 return true;
01209 }
01210
01211 default: return false;
01212 }
01213 }
01214
01232 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01233 {
01234 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01235 TileIndex start_tile = tile;
01236
01237 Track track = Extract<Track, 0, 3>(p2);
01238 bool mode = HasBit(p2, 3);
01239 bool semaphores = HasBit(p2, 4);
01240 bool remove = HasBit(p2, 5);
01241 bool autofill = HasBit(p2, 6);
01242 bool minimise_gaps = HasBit(p2, 10);
01243 byte signal_density = GB(p2, 24, 8);
01244
01245 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01246 TileIndex end_tile = p1;
01247 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01248
01249 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01250
01251
01252
01253 signal_density *= 2;
01254
01255 Trackdir trackdir = TrackToTrackdir(track);
01256 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01257 if (ret.Failed()) return ret;
01258
01259 track = TrackdirToTrack(trackdir);
01260 Trackdir start_trackdir = trackdir;
01261
01262
01263 if (!HasTrack(tile, track)) return CMD_ERROR;
01264
01265 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01266 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01267
01268 byte signals;
01269
01270 if (HasSignalOnTrack(tile, track)) {
01271 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01272 assert(signals != 0);
01273
01274
01275 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01276
01277 sigtype = GetSignalType(tile, track);
01278
01279 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01280 } else {
01281 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01282 }
01283
01284 byte signal_dir = 0;
01285 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01286 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300 int signal_ctr = 0;
01301 int last_used_ctr = INT_MIN;
01302 int last_suitable_ctr = 0;
01303 TileIndex last_suitable_tile = INVALID_TILE;
01304 Trackdir last_suitable_trackdir = INVALID_TRACKDIR;
01305 CommandCost last_error = CMD_ERROR;
01306 bool had_success = false;
01307 for (;;) {
01308
01309 if (remove || minimise_gaps || signal_ctr % signal_density == 0) {
01310 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01311 SB(p1, 3, 1, mode);
01312 SB(p1, 4, 1, semaphores);
01313 SB(p1, 5, 3, sigtype);
01314 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01315
01316
01317 signals = 0;
01318 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01319 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01320
01321
01322 bool test_only = !remove && minimise_gaps && signal_ctr < (last_used_ctr + signal_density);
01323 CommandCost ret = DoCommand(tile, p1, signals, test_only ? flags & ~DC_EXEC : flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01324
01325 if (ret.Succeeded()) {
01326
01327 last_suitable_ctr = signal_ctr;
01328 last_suitable_tile = tile;
01329 last_suitable_trackdir = trackdir;
01330 } else if (!test_only && last_suitable_tile != INVALID_TILE) {
01331
01332 SB(p1, 0, 3, TrackdirToTrack(last_suitable_trackdir));
01333 ClrBit(p1, 17);
01334
01335
01336 signals = 0;
01337 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(last_suitable_trackdir);
01338 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(last_suitable_trackdir);
01339
01340 ret = DoCommand(last_suitable_tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01341 }
01342
01343
01344 if (!test_only) {
01345
01346 if (ret.Succeeded()) {
01347 had_success = true;
01348 total_cost.AddCost(ret);
01349 last_used_ctr = last_suitable_ctr;
01350 last_suitable_tile = INVALID_TILE;
01351 } else {
01352
01353 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01354 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01355 last_error = ret;
01356 }
01357 }
01358 }
01359 }
01360
01361 if (autofill) {
01362 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01363
01364
01365 if (tile == start_tile && trackdir == start_trackdir) break;
01366 } else {
01367 if (tile == end_tile) break;
01368
01369 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01370 signal_ctr++;
01371
01372
01373 if (IsDiagonalTrackdir(trackdir)) {
01374 signal_ctr++;
01375 } else {
01376 ToggleBit(trackdir, 0);
01377 }
01378 }
01379 }
01380
01381 return had_success ? total_cost : last_error;
01382 }
01383
01402 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01403 {
01404 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01405 }
01406
01419 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01420 {
01421 Track track = Extract<Track, 0, 3>(p1);
01422
01423 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01424 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01425 }
01426 if (!HasSignalOnTrack(tile, track)) {
01427 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01428 }
01429
01430
01431 if (_current_company != OWNER_WATER) {
01432 CommandCost ret = CheckTileOwnership(tile);
01433 if (ret.Failed()) return ret;
01434 }
01435
01436
01437 if (flags & DC_EXEC) {
01438 Train *v = NULL;
01439 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01440 v = GetTrainForReservation(tile, track);
01441 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01442
01443 Trackdir td = TrackToTrackdir(track);
01444 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01445
01446 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01447 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01448 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01449 if (HasReservedTracks(next, tracks)) {
01450 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01451 }
01452 }
01453 }
01454 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01455 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01456 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01457 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01458
01459
01460 if (GetPresentSignals(tile) == 0) {
01461 SetSignalStates(tile, 0);
01462 SetHasSignals(tile, false);
01463 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01464 }
01465
01466 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01467 YapfNotifyTrackLayoutChange(tile, track);
01468 if (v != NULL) TryPathReserve(v, false);
01469
01470 MarkTileDirtyByTile(tile);
01471 }
01472
01473 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01474 }
01475
01494 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01495 {
01496 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01497 }
01498
01500 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01501 {
01502 if (v->type != VEH_TRAIN) return NULL;
01503
01504 TrainList *affected_trains = static_cast<TrainList*>(data);
01505 affected_trains->Include(Train::From(v)->First());
01506
01507 return NULL;
01508 }
01509
01522 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01523 {
01524 RailType totype = Extract<RailType, 0, 4>(p2);
01525
01526 if (!ValParamRailtype(totype)) return CMD_ERROR;
01527 if (p1 >= MapSize()) return CMD_ERROR;
01528
01529 TrainList affected_trains;
01530
01531 CommandCost cost(EXPENSES_CONSTRUCTION);
01532 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01533 TileArea ta(tile, p1);
01534 TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01535 for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01536 TileType tt = GetTileType(tile);
01537
01538
01539 switch (tt) {
01540 case MP_RAILWAY:
01541 break;
01542 case MP_STATION:
01543 if (!HasStationRail(tile)) continue;
01544 break;
01545 case MP_ROAD:
01546 if (!IsLevelCrossing(tile)) continue;
01547 if (RailNoLevelCrossings(totype)) {
01548 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01549 continue;
01550 }
01551 break;
01552 case MP_TUNNELBRIDGE:
01553 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01554 break;
01555 default: continue;
01556 }
01557
01558
01559 RailType type = GetRailType(tile);
01560
01561
01562 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01563
01564
01565 CommandCost ret = CheckTileOwnership(tile);
01566 if (ret.Failed()) {
01567 error = ret;
01568 continue;
01569 }
01570
01571 SmallVector<Train *, 2> vehicles_affected;
01572
01573
01574
01575 if (tt != MP_TUNNELBRIDGE) {
01576 if (!IsCompatibleRail(type, totype)) {
01577 CommandCost ret = EnsureNoVehicleOnGround(tile);
01578 if (ret.Failed()) {
01579 error = ret;
01580 continue;
01581 }
01582 }
01583 if (flags & DC_EXEC) {
01584 TrackBits reserved = GetReservedTrackbits(tile);
01585 Track track;
01586 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01587 Train *v = GetTrainForReservation(tile, track);
01588 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01589
01590 FreeTrainTrackReservation(v);
01591 *vehicles_affected.Append() = v;
01592 }
01593 }
01594
01595
01596 if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
01597 Company *c = Company::Get(GetTileOwner(tile));
01598 uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01599 if (IsPlainRailTile(tile)) {
01600 TrackBits bits = GetTrackBits(tile);
01601 num_pieces = CountBits(bits);
01602 if (TracksOverlap(bits)) num_pieces *= num_pieces;
01603 }
01604 c->infrastructure.rail[type] -= num_pieces;
01605 c->infrastructure.rail[totype] += num_pieces;
01606 DirtyCompanyInfrastructureWindows(c->index);
01607 }
01608
01609 SetRailType(tile, totype);
01610 MarkTileDirtyByTile(tile);
01611
01612 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01613 }
01614 }
01615
01616 switch (tt) {
01617 case MP_RAILWAY:
01618 switch (GetRailTileType(tile)) {
01619 case RAIL_TILE_DEPOT:
01620 if (flags & DC_EXEC) {
01621
01622 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01623
01624
01625 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01626 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01627 }
01628 cost.AddCost(RailConvertCost(type, totype));
01629 break;
01630
01631 default:
01632 if (flags & DC_EXEC) {
01633
01634 TrackBits tracks = GetTrackBits(tile);
01635 while (tracks != TRACK_BIT_NONE) {
01636 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01637 }
01638 }
01639 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01640 break;
01641 }
01642 break;
01643
01644 case MP_TUNNELBRIDGE: {
01645 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01646
01647
01648
01649 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01650 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01651
01652
01653 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01654 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01655 if (ret.Failed()) {
01656 error = ret;
01657 continue;
01658 }
01659 }
01660
01661 if (flags & DC_EXEC) {
01662 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01663 if (HasTunnelBridgeReservation(tile)) {
01664 Train *v = GetTrainForReservation(tile, track);
01665 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01666
01667 FreeTrainTrackReservation(v);
01668 *vehicles_affected.Append() = v;
01669 }
01670 }
01671
01672
01673 uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01674 Company *c = Company::Get(GetTileOwner(tile));
01675 c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01676 c->infrastructure.rail[totype] += num_pieces;
01677 DirtyCompanyInfrastructureWindows(c->index);
01678
01679 SetRailType(tile, totype);
01680 SetRailType(endtile, totype);
01681
01682 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01683 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01684
01685 YapfNotifyTrackLayoutChange(tile, track);
01686 YapfNotifyTrackLayoutChange(endtile, track);
01687
01688 MarkTileDirtyByTile(tile);
01689 MarkTileDirtyByTile(endtile);
01690
01691 if (IsBridge(tile)) {
01692 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01693 TileIndex t = tile + delta;
01694 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01695 }
01696 }
01697
01698 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01699 break;
01700 }
01701
01702 default:
01703 if (flags & DC_EXEC) {
01704 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01705 YapfNotifyTrackLayoutChange(tile, track);
01706 }
01707
01708 cost.AddCost(RailConvertCost(type, totype));
01709 break;
01710 }
01711
01712 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01713 TryPathReserve(vehicles_affected[i], true);
01714 }
01715 }
01716
01717 if (flags & DC_EXEC) {
01718
01719 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01720 (*v)->ConsistChanged(true);
01721 }
01722 }
01723
01724 delete iter;
01725 return (cost.GetCost() == 0) ? error : cost;
01726 }
01727
01728 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01729 {
01730 if (_current_company != OWNER_WATER) {
01731 CommandCost ret = CheckTileOwnership(tile);
01732 if (ret.Failed()) return ret;
01733 }
01734
01735 CommandCost ret = EnsureNoVehicleOnGround(tile);
01736 if (ret.Failed()) return ret;
01737
01738 if (flags & DC_EXEC) {
01739
01740 DiagDirection dir = GetRailDepotDirection(tile);
01741 Owner owner = GetTileOwner(tile);
01742 Train *v = NULL;
01743
01744 if (HasDepotReservation(tile)) {
01745 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01746 if (v != NULL) FreeTrainTrackReservation(v);
01747 }
01748
01749 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01750 DirtyCompanyInfrastructureWindows(owner);
01751
01752 delete Depot::GetByTile(tile);
01753 DoClearSquare(tile);
01754 AddSideToSignalBuffer(tile, dir, owner);
01755 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01756 if (v != NULL) TryPathReserve(v, true);
01757 }
01758
01759 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01760 }
01761
01762 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01763 {
01764 CommandCost cost(EXPENSES_CONSTRUCTION);
01765
01766 if (flags & DC_AUTO) {
01767 if (!IsTileOwner(tile, _current_company)) {
01768 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01769 }
01770
01771 if (IsPlainRail(tile)) {
01772 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01773 } else {
01774 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01775 }
01776 }
01777
01778 switch (GetRailTileType(tile)) {
01779 case RAIL_TILE_SIGNALS:
01780 case RAIL_TILE_NORMAL: {
01781 Slope tileh = GetTileSlope(tile);
01782
01783 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01784
01785 TrackBits tracks = GetTrackBits(tile);
01786 while (tracks != TRACK_BIT_NONE) {
01787 Track track = RemoveFirstTrack(&tracks);
01788 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01789 if (ret.Failed()) return ret;
01790 cost.AddCost(ret);
01791 }
01792
01793
01794
01795 if (water_ground && !(flags & DC_BANKRUPT) && Company::IsValidID(_current_company)) {
01796 CommandCost ret = EnsureNoVehicleOnGround(tile);
01797 if (ret.Failed()) return ret;
01798
01799
01800 if (flags & DC_EXEC) DoClearSquare(tile);
01801 cost.AddCost(_price[PR_CLEAR_WATER]);
01802 }
01803
01804 return cost;
01805 }
01806
01807 case RAIL_TILE_DEPOT:
01808 return RemoveTrainDepot(tile, flags);
01809
01810 default:
01811 return CMD_ERROR;
01812 }
01813 }
01814
01819 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01820 {
01821 switch (track) {
01822 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01823 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01824 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01825 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01826 default: break;
01827 }
01828 return GetSlopePixelZ(x, y);
01829 }
01830
01831 static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
01832 {
01833 bool side;
01834 switch (_settings_game.construction.train_signal_side) {
01835 case 0: side = false; break;
01836 case 2: side = true; break;
01837 default: side = _settings_game.vehicle.road_side != 0; break;
01838 }
01839 static const Point SignalPositions[2][12] = {
01840 {
01841
01842 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01843
01844 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01845 }, {
01846
01847 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01848
01849 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01850 }
01851 };
01852
01853 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01854 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01855
01856 SignalType type = GetSignalType(tile, track);
01857 SignalVariant variant = GetSignalVariant(tile, track);
01858
01859 SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition);
01860 if (sprite != 0) {
01861 sprite += image;
01862 } else {
01863
01864 sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16;
01865 sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01866 }
01867
01868 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01869 }
01870
01871 static uint32 _drawtile_track_palette;
01872
01873
01874 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01875 {
01876 RailFenceOffset rfo = RFO_FLAT_X;
01877 if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01878 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01879 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01880 }
01881
01882 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01883 {
01884 RailFenceOffset rfo = RFO_FLAT_X;
01885 if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01886 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01887 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01888 }
01889
01890 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01891 {
01892 DrawTrackFence_NW(ti, base_image);
01893 DrawTrackFence_SE(ti, base_image);
01894 }
01895
01896 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01897 {
01898 RailFenceOffset rfo = RFO_FLAT_Y;
01899 if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01900 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01901 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01902 }
01903
01904 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01905 {
01906 RailFenceOffset rfo = RFO_FLAT_Y;
01907 if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01908 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01909 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01910 }
01911
01912 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01913 {
01914 DrawTrackFence_NE(ti, base_image);
01915 DrawTrackFence_SW(ti, base_image);
01916 }
01917
01921 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01922 {
01923 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01924 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01925 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01926 }
01927
01931 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01932 {
01933 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01934 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01935 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01936 }
01937
01941 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01942 {
01943 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01944 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01945 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01946 }
01947
01951 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01952 {
01953 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01954 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01955 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01956 }
01957
01958
01959 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01960 {
01961
01962
01963 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01964 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01965
01966 switch (GetRailGroundType(ti->tile)) {
01967 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01968 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01969 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01970 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01971 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01972 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01973 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01974 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01975 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01976 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01977 case RAIL_GROUND_WATER: {
01978 Corner track_corner;
01979 if (IsHalftileSlope(ti->tileh)) {
01980
01981 track_corner = GetHalftileSlopeCorner(ti->tileh);
01982 } else {
01983
01984 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01985 }
01986 switch (track_corner) {
01987 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01988 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01989 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01990 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01991 default: NOT_REACHED();
01992 }
01993 break;
01994 }
01995 default: break;
01996 }
01997 }
01998
01999
02000 static const int INF = 1000;
02001 static const SubSprite _halftile_sub_sprite[4] = {
02002 { -INF , -INF , 32 - 33, INF },
02003 { -INF , 0 + 7, INF , INF },
02004 { -31 + 33, -INF , INF , INF },
02005 { -INF , -INF , INF , 30 - 23 }
02006 };
02007
02008 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
02009 {
02010 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
02011 }
02012
02013 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
02014 {
02015 RailGroundType rgt = GetRailGroundType(ti->tile);
02016 Foundation f = GetRailFoundation(ti->tileh, track);
02017 Corner halftile_corner = CORNER_INVALID;
02018
02019 if (IsNonContinuousFoundation(f)) {
02020
02021 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02022
02023 track &= ~CornerToTrackBits(halftile_corner);
02024 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02025 }
02026
02027 DrawFoundation(ti, f);
02028
02029
02030
02031 if (rgt == RAIL_GROUND_WATER) {
02032 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
02033
02034 DrawShoreTile(ti->tileh);
02035 } else {
02036
02037 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
02038 }
02039 } else {
02040 SpriteID image;
02041
02042 switch (rgt) {
02043 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02044 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02045 default: image = SPR_FLAT_GRASS_TILE; break;
02046 }
02047
02048 image += SlopeToSpriteOffset(ti->tileh);
02049
02050 DrawGroundSprite(image, PAL_NONE);
02051 }
02052
02053 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02054 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02055 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
02056
02057 if (track == TRACK_BIT_NONE) {
02058
02059 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
02060 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
02061 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
02062 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
02063 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02064 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02065 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02066 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02067 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02068 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02069 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02070 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02071 } else {
02072 switch (track) {
02073
02074
02075 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02076 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02077 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02078 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02079 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02080 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02081 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02082 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02083 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02084 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02085 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02086
02087 default:
02088
02089 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02090 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02091 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02092 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02093 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02094 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02095 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02096 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02097 } else {
02098 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02099 }
02100
02101
02102 track &= ~pbs;
02103
02104
02105 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02106 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02107 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02108 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02109 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02110 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02111 }
02112
02113
02114 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02115 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02116 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02117 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02118 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02119 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02120 }
02121
02122 if (IsValidCorner(halftile_corner)) {
02123 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02124 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02125 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02126
02127
02128 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02129
02130 SpriteID image;
02131 switch (rgt) {
02132 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02133 case RAIL_GROUND_ICE_DESERT:
02134 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02135 default: image = SPR_FLAT_GRASS_TILE; break;
02136 }
02137
02138 image += SlopeToSpriteOffset(fake_slope);
02139
02140 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02141
02142 track = CornerToTrackBits(halftile_corner);
02143
02144 int offset;
02145 switch (track) {
02146 default: NOT_REACHED();
02147 case TRACK_BIT_UPPER: offset = RTO_N; break;
02148 case TRACK_BIT_LOWER: offset = RTO_S; break;
02149 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02150 case TRACK_BIT_LEFT: offset = RTO_W; break;
02151 }
02152
02153 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02154 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02155 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02156 }
02157 }
02158 }
02159
02165 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02166 {
02167 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02168
02169 if (rti->UsesOverlay()) {
02170 DrawTrackBitsOverlay(ti, track, rti);
02171 return;
02172 }
02173
02174 RailGroundType rgt = GetRailGroundType(ti->tile);
02175 Foundation f = GetRailFoundation(ti->tileh, track);
02176 Corner halftile_corner = CORNER_INVALID;
02177
02178 if (IsNonContinuousFoundation(f)) {
02179
02180 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02181
02182 track &= ~CornerToTrackBits(halftile_corner);
02183 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02184 }
02185
02186 DrawFoundation(ti, f);
02187
02188
02189 SpriteID image;
02190 PaletteID pal = PAL_NONE;
02191 const SubSprite *sub = NULL;
02192 bool junction = false;
02193
02194
02195 if (track == 0) {
02196
02197 if (rgt == RAIL_GROUND_WATER) {
02198 if (IsSteepSlope(ti->tileh)) {
02199 DrawShoreTile(ti->tileh);
02200 image = 0;
02201 } else {
02202 image = SPR_FLAT_WATER_TILE;
02203 }
02204 } else {
02205 switch (rgt) {
02206 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02207 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02208 default: image = SPR_FLAT_GRASS_TILE; break;
02209 }
02210 image += SlopeToSpriteOffset(ti->tileh);
02211 }
02212 } else {
02213 if (ti->tileh != SLOPE_FLAT) {
02214
02215 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02216 } else {
02217
02218 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02219 (image++, track == TRACK_BIT_X) ||
02220 (image++, track == TRACK_BIT_UPPER) ||
02221 (image++, track == TRACK_BIT_LOWER) ||
02222 (image++, track == TRACK_BIT_RIGHT) ||
02223 (image++, track == TRACK_BIT_LEFT) ||
02224 (image++, track == TRACK_BIT_CROSS) ||
02225
02226 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02227 (image++, track == TRACK_BIT_VERT) ||
02228
02229 (junction = true, false) ||
02230 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02231 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02232 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02233 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02234 (image++, true);
02235 }
02236
02237 switch (rgt) {
02238 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02239 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02240 case RAIL_GROUND_WATER: {
02241
02242 DrawShoreTile(ti->tileh);
02243 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02244 sub = &(_halftile_sub_sprite[track_corner]);
02245 break;
02246 }
02247 default: break;
02248 }
02249 }
02250
02251 if (image != 0) DrawGroundSprite(image, pal, sub);
02252
02253
02254 if (junction) {
02255 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02256 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02257 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02258 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02259 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02260 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02261 }
02262
02263
02264 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02265
02266 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02267 if (pbs & TRACK_BIT_X) {
02268 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02269 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02270 } else {
02271 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02272 }
02273 }
02274 if (pbs & TRACK_BIT_Y) {
02275 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02276 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02277 } else {
02278 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02279 }
02280 }
02281 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02282 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02283 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02284 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02285 }
02286
02287 if (IsValidCorner(halftile_corner)) {
02288 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02289
02290
02291 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02292 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02293 pal = PAL_NONE;
02294 switch (rgt) {
02295 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02296 case RAIL_GROUND_ICE_DESERT:
02297 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02298 default: break;
02299 }
02300 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02301
02302 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02303 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02304 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02305 }
02306 }
02307 }
02308
02309 static void DrawSignals(TileIndex tile, TrackBits rails, const RailtypeInfo *rti)
02310 {
02311 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, rti, t, GetSingleSignalState(tile, x), y, z)
02312
02313 if (!(rails & TRACK_BIT_Y)) {
02314 if (!(rails & TRACK_BIT_X)) {
02315 if (rails & TRACK_BIT_LEFT) {
02316 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02317 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02318 }
02319 if (rails & TRACK_BIT_RIGHT) {
02320 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02321 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02322 }
02323 if (rails & TRACK_BIT_UPPER) {
02324 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02325 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02326 }
02327 if (rails & TRACK_BIT_LOWER) {
02328 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02329 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02330 }
02331 } else {
02332 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02333 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02334 }
02335 } else {
02336 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02337 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02338 }
02339 }
02340
02341 static void DrawTile_Track(TileInfo *ti)
02342 {
02343 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02344
02345 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02346
02347 if (IsPlainRail(ti->tile)) {
02348 TrackBits rails = GetTrackBits(ti->tile);
02349
02350 DrawTrackBits(ti, rails);
02351
02352 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02353
02354 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02355
02356 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti);
02357 } else {
02358
02359 const DrawTileSprites *dts;
02360 PaletteID pal = PAL_NONE;
02361 SpriteID relocation;
02362
02363 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02364
02365 if (IsInvisibilitySet(TO_BUILDINGS)) {
02366
02367 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02368 } else {
02369 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02370 }
02371
02372 SpriteID image;
02373 if (rti->UsesOverlay()) {
02374 image = SPR_FLAT_GRASS_TILE;
02375 } else {
02376 image = dts->ground.sprite;
02377 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02378 }
02379
02380
02381
02382 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02383 if (image != SPR_FLAT_GRASS_TILE) {
02384 image += rti->snow_offset;
02385 } else {
02386 image = SPR_FLAT_SNOW_DESERT_TILE;
02387 }
02388 }
02389
02390 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02391
02392 if (rti->UsesOverlay()) {
02393 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02394
02395 switch (GetRailDepotDirection(ti->tile)) {
02396 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02397 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02398 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02399 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02400 default: break;
02401 }
02402
02403 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02404 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02405
02406 switch (GetRailDepotDirection(ti->tile)) {
02407 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02408 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02409 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02410 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02411 default: break;
02412 }
02413 }
02414 } else {
02415
02416 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02417 switch (GetRailDepotDirection(ti->tile)) {
02418 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02419 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02420 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02421 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02422 default: break;
02423 }
02424 }
02425 }
02426 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02427 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02428
02429 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02430
02431 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02432 }
02433 DrawBridgeMiddle(ti);
02434 }
02435
02436 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02437 {
02438 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02439 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02440 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02441 uint32 offset = rti->GetRailtypeSpriteOffset();
02442
02443 x += 33;
02444 y += 17;
02445
02446 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02447 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02448
02449 DrawSprite(image, PAL_NONE, x, y);
02450
02451 if (rti->UsesOverlay()) {
02452 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02453
02454 switch (dir) {
02455 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02456 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02457 default: break;
02458 }
02459 }
02460 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02461 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02462
02463 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02464 }
02465
02466 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02467 {
02468 if (IsPlainRail(tile)) {
02469 int z;
02470 Slope tileh = GetTilePixelSlope(tile, &z);
02471 if (tileh == SLOPE_FLAT) return z;
02472
02473 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02474 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02475 } else {
02476 return GetTileMaxPixelZ(tile);
02477 }
02478 }
02479
02480 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02481 {
02482 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02483 }
02484
02485 static void TileLoop_Track(TileIndex tile)
02486 {
02487 RailGroundType old_ground = GetRailGroundType(tile);
02488 RailGroundType new_ground;
02489
02490 if (old_ground == RAIL_GROUND_WATER) {
02491 TileLoop_Water(tile);
02492 return;
02493 }
02494
02495 switch (_settings_game.game_creation.landscape) {
02496 case LT_ARCTIC: {
02497 int z;
02498 Slope slope = GetTileSlope(tile, &z);
02499 bool half = false;
02500
02501
02502
02503 if (IsPlainRail(tile)) {
02504 TrackBits track = GetTrackBits(tile);
02505 Foundation f = GetRailFoundation(slope, track);
02506
02507 switch (f) {
02508 case FOUNDATION_NONE:
02509
02510 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02511 break;
02512
02513 case FOUNDATION_INCLINED_X:
02514 case FOUNDATION_INCLINED_Y:
02515
02516 if (IsSteepSlope(slope)) z++;
02517 break;
02518
02519 case FOUNDATION_STEEP_LOWER:
02520
02521 z++;
02522 break;
02523
02524 default:
02525
02526 if (IsSteepSlope(slope)) z++;
02527 z++;
02528 break;
02529 }
02530
02531 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02532 } else {
02533
02534 if (slope != SLOPE_FLAT) z++;
02535 }
02536
02537
02538
02539
02540
02541 if (z > GetSnowLine()) {
02542 if (half && z - GetSnowLine() == 1) {
02543
02544 new_ground = RAIL_GROUND_HALF_SNOW;
02545 } else {
02546 new_ground = RAIL_GROUND_ICE_DESERT;
02547 }
02548 goto set_ground;
02549 }
02550 break;
02551 }
02552
02553 case LT_TROPIC:
02554 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02555 new_ground = RAIL_GROUND_ICE_DESERT;
02556 goto set_ground;
02557 }
02558 break;
02559 }
02560
02561 new_ground = RAIL_GROUND_GRASS;
02562
02563 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02564
02565 TrackBits rail = GetTrackBits(tile);
02566
02567 Owner owner = GetTileOwner(tile);
02568 byte fences = 0;
02569
02570 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
02571 static const TrackBits dir_to_trackbits[DIAGDIR_END] = {TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW};
02572
02573
02574 if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
02575
02576 TileIndex tile2 = tile + TileOffsByDiagDir(d);
02577
02578
02579 if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
02580 IsTileType(tile2, MP_ROAD) || (IsTileType(tile2, MP_OBJECT) && !IsOwnedLand(tile2)) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
02581 fences |= 1 << d;
02582 }
02583 }
02584
02585 switch (fences) {
02586 case 0: break;
02587 case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
02588 case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
02589 case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
02590 case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
02591 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
02592 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
02593 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
02594 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02595 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02596 case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
02597 default: NOT_REACHED();
02598 }
02599 }
02600
02601 set_ground:
02602 if (old_ground != new_ground) {
02603 SetRailGroundType(tile, new_ground);
02604 MarkTileDirtyByTile(tile);
02605 }
02606 }
02607
02608
02609 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02610 {
02611
02612 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(GetTileSlope(tile))) {
02613 TrackBits tb = GetTrackBits(tile);
02614 switch (tb) {
02615 default: NOT_REACHED();
02616 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02617 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02618 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02619 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02620 }
02621 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02622 }
02623
02624 if (mode != TRANSPORT_RAIL) return 0;
02625
02626 TrackBits trackbits = TRACK_BIT_NONE;
02627 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02628
02629 switch (GetRailTileType(tile)) {
02630 default: NOT_REACHED();
02631 case RAIL_TILE_NORMAL:
02632 trackbits = GetTrackBits(tile);
02633 break;
02634
02635 case RAIL_TILE_SIGNALS: {
02636 trackbits = GetTrackBits(tile);
02637 byte a = GetPresentSignals(tile);
02638 uint b = GetSignalStates(tile);
02639
02640 b &= a;
02641
02642
02643
02644
02645
02646
02647 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02648 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02649
02650 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02651 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02652 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02653 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02654
02655 break;
02656 }
02657
02658 case RAIL_TILE_DEPOT: {
02659 DiagDirection dir = GetRailDepotDirection(tile);
02660
02661 if (side != INVALID_DIAGDIR && side != dir) break;
02662
02663 trackbits = DiagDirToDiagTrackBits(dir);
02664 break;
02665 }
02666 }
02667
02668 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02669 }
02670
02671 static bool ClickTile_Track(TileIndex tile)
02672 {
02673 if (!IsRailDepot(tile)) return false;
02674
02675 ShowDepotWindow(tile, VEH_TRAIN);
02676 return true;
02677 }
02678
02679 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02680 {
02681 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02682 td->rail_speed = rti->max_speed;
02683 td->owner[0] = GetTileOwner(tile);
02684 SetDParamX(td->dparam, 0, rti->strings.name);
02685 switch (GetRailTileType(tile)) {
02686 case RAIL_TILE_NORMAL:
02687 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02688 break;
02689
02690 case RAIL_TILE_SIGNALS: {
02691 static const StringID signal_type[6][6] = {
02692 {
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02696 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02697 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02699 },
02700 {
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02704 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02705 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02707 },
02708 {
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02712 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02713 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02715 },
02716 {
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02720 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02721 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02723 },
02724 {
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02728 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02729 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02730 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02731 },
02732 {
02733 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02734 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02735 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02736 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02737 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02738 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02739 }
02740 };
02741
02742 SignalType primary_signal;
02743 SignalType secondary_signal;
02744 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02745 primary_signal = GetSignalType(tile, TRACK_UPPER);
02746 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02747 } else {
02748 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02749 }
02750
02751 td->str = signal_type[secondary_signal][primary_signal];
02752 break;
02753 }
02754
02755 case RAIL_TILE_DEPOT:
02756 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02757 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02758 if (td->rail_speed > 0) {
02759 td->rail_speed = min(td->rail_speed, 61);
02760 } else {
02761 td->rail_speed = 61;
02762 }
02763 }
02764 td->build_date = Depot::GetByTile(tile)->build_date;
02765 break;
02766
02767 default:
02768 NOT_REACHED();
02769 }
02770 }
02771
02772 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02773 {
02774 if (!IsTileOwner(tile, old_owner)) return;
02775
02776 if (new_owner != INVALID_OWNER) {
02777
02778 uint num_pieces = 1;
02779 if (IsPlainRail(tile)) {
02780 TrackBits bits = GetTrackBits(tile);
02781 num_pieces = CountBits(bits);
02782 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02783 }
02784 RailType rt = GetRailType(tile);
02785 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02786 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02787
02788 if (HasSignals(tile)) {
02789 uint num_sigs = CountBits(GetPresentSignals(tile));
02790 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02791 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02792 }
02793
02794 SetTileOwner(tile, new_owner);
02795 } else {
02796 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02797 }
02798 }
02799
02800 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02801 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02802 static const int8 _deltacoord_leaveoffset[8] = {
02803 -1, 0, 1, 0,
02804 0, 1, 0, -1
02805 };
02806
02807
02814 int TicksToLeaveDepot(const Train *v)
02815 {
02816 DiagDirection dir = GetRailDepotDirection(v->tile);
02817 int length = v->CalcNextVehicleOffset();
02818
02819 switch (dir) {
02820 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02821 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02822 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02823 default:
02824 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02825 }
02826
02827 return 0;
02828 }
02829
02834 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02835 {
02836
02837 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02838
02839 Train *v = Train::From(u);
02840
02841
02842 DiagDirection dir = GetRailDepotDirection(tile);
02843
02844
02845 int length = v->CalcNextVehicleOffset();
02846
02847 byte fract_coord_leave =
02848 ((_fractcoords_enter[dir] & 0x0F) +
02849 (length + 1) * _deltacoord_leaveoffset[dir]) +
02850 (((_fractcoords_enter[dir] >> 4) +
02851 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02852
02853 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02854
02855 if (_fractcoords_behind[dir] == fract_coord) {
02856
02857 return VETSB_CANNOT_ENTER;
02858 } else if (_fractcoords_enter[dir] == fract_coord) {
02859 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02860
02861 v->track = TRACK_BIT_DEPOT,
02862 v->vehstatus |= VS_HIDDEN;
02863 v->direction = ReverseDir(v->direction);
02864 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02865 v->tile = tile;
02866
02867 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02868 return VETSB_ENTERED_WORMHOLE;
02869 }
02870 } else if (fract_coord_leave == fract_coord) {
02871 if (DiagDirToDir(dir) == v->direction) {
02872
02873 if ((v = v->Next()) != NULL) {
02874 v->vehstatus &= ~VS_HIDDEN;
02875 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02876 }
02877 }
02878 }
02879
02880 return VETSB_CONTINUE;
02881 }
02882
02894 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02895 {
02896 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02897
02898
02899 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02900
02901
02902 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02903 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02904
02905 Corner track_corner;
02906 switch (rail_bits) {
02907 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02908 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02909 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02910 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02911
02912
02913 default:
02914 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02915 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02916 }
02917
02918
02919 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02920 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02921 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02922
02923 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02924
02925 if (tileh_old != tileh_new) {
02926
02927 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02928 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02929 }
02930 return cost;
02931 }
02932
02936 static Vehicle *EnsureNoShipProc(Vehicle *v, void *data)
02937 {
02938 return v->type == VEH_SHIP ? v : NULL;
02939 }
02940
02941 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02942 {
02943 int z_old;
02944 Slope tileh_old = GetTileSlope(tile, &z_old);
02945 if (IsPlainRail(tile)) {
02946 TrackBits rail_bits = GetTrackBits(tile);
02947
02948 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02949
02950
02951 if (was_water && HasVehicleOnPos(tile, NULL, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY);
02952
02953
02954 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02955
02956
02957 Corner allowed_corner;
02958 switch (rail_bits) {
02959 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02960 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02961 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02962 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02963 default: return autoslope_result;
02964 }
02965
02966 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02967
02968
02969 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02970
02971
02972 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02973 if (allowed_corner == corner) continue;
02974 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02975 }
02976
02977
02978 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02979
02980
02981 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02982 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02983 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02984 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02985 }
02986 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02987 }
02988
02989
02990 extern const TileTypeProcs _tile_type_rail_procs = {
02991 DrawTile_Track,
02992 GetSlopePixelZ_Track,
02993 ClearTile_Track,
02994 NULL,
02995 GetTileDesc_Track,
02996 GetTileTrackStatus_Track,
02997 ClickTile_Track,
02998 NULL,
02999 TileLoop_Track,
03000 ChangeTileOwner_Track,
03001 NULL,
03002 VehicleEnter_Track,
03003 GetFoundation_Track,
03004 TerraformTile_Track,
03005 };