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