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