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