00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "cmd_helper.h"
00015 #include "landscape.h"
00016 #include "viewport_func.h"
00017 #include "command_func.h"
00018 #include "engine_base.h"
00019 #include "depot_base.h"
00020 #include "pathfinder/yapf/yapf_cache.h"
00021 #include "newgrf_engine.h"
00022 #include "landscape_type.h"
00023 #include "newgrf_commons.h"
00024 #include "train.h"
00025 #include "variables.h"
00026 #include "autoslope.h"
00027 #include "water.h"
00028 #include "tunnelbridge_map.h"
00029 #include "window_func.h"
00030 #include "vehicle_func.h"
00031 #include "sound_func.h"
00032 #include "tunnelbridge.h"
00033 #include "functions.h"
00034 #include "elrail_func.h"
00035 #include "town.h"
00036 #include "pbs.h"
00037
00038 #include "table/strings.h"
00039 #include "table/railtypes.h"
00040 #include "table/track_land.h"
00041
00042 RailtypeInfo _railtypes[RAILTYPE_END];
00043
00044 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
00045
00049 void ResetRailTypes()
00050 {
00051 memset(_railtypes, 0, sizeof(_railtypes));
00052 memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes));
00053 }
00054
00055 static const byte _track_sloped_sprites[14] = {
00056 14, 15, 22, 13,
00057 0, 21, 17, 12,
00058 23, 0, 18, 20,
00059 19, 16
00060 };
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00096 {
00097 TrackBits rail_bits = *(TrackBits *)data;
00098
00099 if (v->type != VEH_TRAIN) return NULL;
00100
00101 Train *t = Train::From(v);
00102 if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
00103
00104 _error_message = STR_ERROR_TRAIN_IN_THE_WAY + v->type;
00105 return v;
00106 }
00107
00115 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
00116 {
00117 TrackBits rail_bits = TrackToTrackBits(track);
00118
00119 return !HasVehicleOnPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc);
00120 }
00121
00122 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00123 {
00124 TrackBits current;
00125 TrackBits future;
00126 _error_message = STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION;
00127
00128 if (!IsPlainRail(tile)) return false;
00129
00130
00131
00132 current = GetTrackBits(tile);
00133 future = current | to_build;
00134
00135
00136 if (current == future) {
00137
00138 _error_message = STR_ERROR_ALREADY_BUILT;
00139 return false;
00140 }
00141
00142
00143 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00144
00145
00146 return future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT;
00147 } else {
00148
00149 return true;
00150 }
00151 }
00152
00153
00155 static const TrackBits _valid_tracks_without_foundation[15] = {
00156 TRACK_BIT_ALL,
00157 TRACK_BIT_RIGHT,
00158 TRACK_BIT_UPPER,
00159 TRACK_BIT_X,
00160
00161 TRACK_BIT_LEFT,
00162 TRACK_BIT_NONE,
00163 TRACK_BIT_Y,
00164 TRACK_BIT_LOWER,
00165
00166 TRACK_BIT_LOWER,
00167 TRACK_BIT_Y,
00168 TRACK_BIT_NONE,
00169 TRACK_BIT_LEFT,
00170
00171 TRACK_BIT_X,
00172 TRACK_BIT_UPPER,
00173 TRACK_BIT_RIGHT,
00174 };
00175
00177 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00178 TRACK_BIT_NONE,
00179 TRACK_BIT_LEFT,
00180 TRACK_BIT_LOWER,
00181 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00182
00183 TRACK_BIT_RIGHT,
00184 TRACK_BIT_ALL,
00185 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00186 TRACK_BIT_ALL,
00187
00188 TRACK_BIT_UPPER,
00189 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00190 TRACK_BIT_ALL,
00191 TRACK_BIT_ALL,
00192
00193 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00194 TRACK_BIT_ALL,
00195 TRACK_BIT_ALL
00196 };
00197
00205 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00206 {
00207 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00208
00209 if (IsSteepSlope(tileh)) {
00210
00211 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00212 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00213
00214
00215 Corner highest_corner = GetHighestSlopeCorner(tileh);
00216 TrackBits higher_track = CornerToTrackBits(highest_corner);
00217
00218
00219 if (bits == higher_track) return HalftileFoundation(highest_corner);
00220
00221
00222 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00223
00224
00225 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00226 } else {
00227 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00228
00229 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00230
00231 Corner track_corner;
00232 switch (bits) {
00233 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00234 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00235 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00236 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00237
00238 case TRACK_BIT_HORZ:
00239 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00240 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00241 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00242
00243 case TRACK_BIT_VERT:
00244 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00245 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00246 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00247
00248 case TRACK_BIT_X:
00249 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00250 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00251
00252 case TRACK_BIT_Y:
00253 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00254 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00255
00256 default:
00257 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00258 }
00259
00260
00261
00262 if (!valid_on_leveled) return FOUNDATION_INVALID;
00263
00264
00265 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00266
00267
00268 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00269
00270
00271 return SpecialRailFoundation(track_corner);
00272 }
00273 }
00274
00275
00285 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00286 {
00287
00288 if (IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_RAILWAY) && (GetRailGroundType(tile) == RAIL_GROUND_WATER))) {
00289 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00290 }
00291
00292 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00293
00294
00295 if ((f_new == FOUNDATION_INVALID) ||
00296 ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00297 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00298 }
00299
00300 Foundation f_old = GetRailFoundation(tileh, existing);
00301 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00302 }
00303
00304
00305 static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
00306
00315 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00316 {
00317 Slope tileh;
00318 RailType railtype = (RailType)p1;
00319 Track track = (Track)p2;
00320 TrackBits trackbit;
00321 CommandCost cost(EXPENSES_CONSTRUCTION);
00322 CommandCost ret;
00323
00324 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00325
00326 tileh = GetTileSlope(tile, NULL);
00327 trackbit = TrackToTrackBits(track);
00328
00329 switch (GetTileType(tile)) {
00330 case MP_RAILWAY:
00331 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00332
00333 if (!IsPlainRail(tile)) return CMD_ERROR;
00334
00335 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00336
00337 if (!CheckTrackCombination(tile, trackbit, flags) ||
00338 !EnsureNoTrainOnTrack(tile, track)) {
00339 return CMD_ERROR;
00340 }
00341
00342 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00343 if (CmdFailed(ret)) return ret;
00344 cost.AddCost(ret);
00345
00346
00347
00348
00349 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00350 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00351 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00352 if (CmdFailed(ret)) return ret;
00353 cost.AddCost(ret);
00354 } else {
00355 return CMD_ERROR;
00356 }
00357 }
00358
00359 if (flags & DC_EXEC) {
00360 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00361 SetTrackBits(tile, GetTrackBits(tile) | trackbit);
00362 }
00363 break;
00364
00365 case MP_ROAD:
00366 #define M(x) (1 << (x))
00367
00368 if (!HasBit(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
00369 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00370 }
00371 #undef M
00372
00373 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00374
00375 if (IsNormalRoad(tile)) {
00376 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00377
00378 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00379
00380 RoadTypes roadtypes = GetRoadTypes(tile);
00381 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00382 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00383 switch (roadtypes) {
00384 default: break;
00385 case ROADTYPES_TRAM:
00386
00387 if (flags & DC_EXEC) SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00388 roadtypes |= ROADTYPES_ROAD;
00389 break;
00390
00391 case ROADTYPES_ALL:
00392 if (road != tram) return CMD_ERROR;
00393 break;
00394 }
00395
00396 road |= tram;
00397
00398 if ((track == TRACK_X && road == ROAD_Y) ||
00399 (track == TRACK_Y && road == ROAD_X)) {
00400 if (flags & DC_EXEC) {
00401 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00402 UpdateLevelCrossing(tile, false);
00403 }
00404 break;
00405 }
00406 }
00407
00408 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00409 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00410 }
00411
00412
00413 default:
00414
00415 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00416
00417 ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00418 if (CmdFailed(ret)) return ret;
00419 cost.AddCost(ret);
00420
00421 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00422 if (CmdFailed(ret)) return ret;
00423 cost.AddCost(ret);
00424
00425 if (water_ground) {
00426 cost.AddCost(-_price[PR_CLEAR_WATER]);
00427 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00428 }
00429
00430 if (flags & DC_EXEC) {
00431 MakeRailNormal(tile, _current_company, trackbit, railtype);
00432 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00433 }
00434 break;
00435 }
00436
00437 if (flags & DC_EXEC) {
00438 MarkTileDirtyByTile(tile);
00439 AddTrackToSignalBuffer(tile, track, _current_company);
00440 YapfNotifyTrackLayoutChange(tile, track);
00441 }
00442
00443 return cost.AddCost(RailBuildCost(railtype));
00444 }
00445
00454 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00455 {
00456 Track track = (Track)p2;
00457 TrackBits trackbit;
00458 CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_RAIL] );
00459 bool crossing = false;
00460
00461 if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
00462 trackbit = TrackToTrackBits(track);
00463
00464
00465
00466
00467
00468 Owner owner = INVALID_OWNER;
00469
00470 Train *v = NULL;
00471
00472 switch (GetTileType(tile)) {
00473 case MP_ROAD: {
00474 if (!IsLevelCrossing(tile) ||
00475 GetCrossingRailBits(tile) != trackbit ||
00476 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00477 (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
00478 return CMD_ERROR;
00479 }
00480
00481 if (flags & DC_EXEC) {
00482 if (HasReservedTracks(tile, trackbit)) {
00483 v = GetTrainForReservation(tile, track);
00484 if (v != NULL) FreeTrainTrackReservation(v);
00485 }
00486 owner = GetTileOwner(tile);
00487 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00488 }
00489 break;
00490 }
00491
00492 case MP_RAILWAY: {
00493 TrackBits present;
00494
00495 if (!IsPlainRail(tile) ||
00496 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00497 !EnsureNoTrainOnTrack(tile, track)) {
00498 return CMD_ERROR;
00499 }
00500
00501 present = GetTrackBits(tile);
00502 if ((present & trackbit) == 0) return CMD_ERROR;
00503 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00504
00505
00506 if (HasSignalOnTrack(tile, track))
00507 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00508
00509 if (flags & DC_EXEC) {
00510 if (HasReservedTracks(tile, trackbit)) {
00511 v = GetTrainForReservation(tile, track);
00512 if (v != NULL) FreeTrainTrackReservation(v);
00513 }
00514 owner = GetTileOwner(tile);
00515 present ^= trackbit;
00516 if (present == 0) {
00517 Slope tileh = GetTileSlope(tile, NULL);
00518
00519 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00520 MakeShore(tile);
00521 } else {
00522 DoClearSquare(tile);
00523 }
00524 } else {
00525 SetTrackBits(tile, present);
00526 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00527 }
00528 }
00529 break;
00530 }
00531
00532 default: return CMD_ERROR;
00533 }
00534
00535 if (flags & DC_EXEC) {
00536
00537 assert(Company::IsValidID(owner));
00538
00539 MarkTileDirtyByTile(tile);
00540 if (crossing) {
00541
00542
00543
00544
00545 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00546 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00547 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00548 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00549 } else {
00550 AddTrackToSignalBuffer(tile, track, owner);
00551 YapfNotifyTrackLayoutChange(tile, track);
00552 }
00553
00554 if (v != NULL) TryPathReserve(v, true);
00555 }
00556
00557 return cost;
00558 }
00559
00560
00568 bool FloodHalftile(TileIndex t)
00569 {
00570 assert(IsPlainRailTile(t));
00571
00572 bool flooded = false;
00573 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00574
00575 Slope tileh = GetTileSlope(t, NULL);
00576 TrackBits rail_bits = GetTrackBits(t);
00577
00578 if (IsSlopeWithOneCornerRaised(tileh)) {
00579 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00580
00581 TrackBits to_remove = lower_track & rail_bits;
00582 if (to_remove != 0) {
00583 _current_company = OWNER_WATER;
00584 if (CmdFailed(DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL))) return flooded;
00585 flooded = true;
00586 rail_bits = rail_bits & ~to_remove;
00587 if (rail_bits == 0) {
00588 MakeShore(t);
00589 MarkTileDirtyByTile(t);
00590 return flooded;
00591 }
00592 }
00593
00594 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00595 flooded = true;
00596 SetRailGroundType(t, RAIL_GROUND_WATER);
00597 MarkTileDirtyByTile(t);
00598 }
00599 } else {
00600
00601 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00602 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00603 flooded = true;
00604 SetRailGroundType(t, RAIL_GROUND_WATER);
00605 MarkTileDirtyByTile(t);
00606 }
00607 }
00608 }
00609 return flooded;
00610 }
00611
00612 static const TileIndexDiffC _trackdelta[] = {
00613 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00614 { 0, 0 },
00615 { 0, 0 },
00616 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00617 { 0, 0 },
00618 { 0, 0 }
00619 };
00620
00621
00622 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00623 {
00624 int x = TileX(start);
00625 int y = TileY(start);
00626 int ex = TileX(end);
00627 int ey = TileY(end);
00628 int dx, dy, trdx, trdy;
00629
00630 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00631
00632
00633 dx = ex - x;
00634 dy = ey - y;
00635
00636
00637 trdx = _trackdelta[*trackdir].x;
00638 trdy = _trackdelta[*trackdir].y;
00639
00640 if (!IsDiagonalTrackdir(*trackdir)) {
00641 trdx += _trackdelta[*trackdir ^ 1].x;
00642 trdy += _trackdelta[*trackdir ^ 1].y;
00643 }
00644
00645
00646 while (
00647 (trdx <= 0 && dx > 0) ||
00648 (trdx >= 0 && dx < 0) ||
00649 (trdy <= 0 && dy > 0) ||
00650 (trdy >= 0 && dy < 0)
00651 ) {
00652 if (!HasBit(*trackdir, 3)) {
00653 SetBit(*trackdir, 3);
00654 trdx = -trdx;
00655 trdy = -trdy;
00656 } else {
00657 return CMD_ERROR;
00658 }
00659 }
00660
00661
00662
00663 if (!IsDiagonalTrackdir(*trackdir)) {
00664 trdx = _trackdelta[*trackdir].x;
00665 trdy = _trackdelta[*trackdir].y;
00666 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
00667 return CMD_ERROR;
00668 }
00669
00670 return CommandCost();
00671 }
00672
00684 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00685 {
00686 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00687 Track track = (Track)GB(p2, 4, 3);
00688 bool remove = HasBit(p2, 7);
00689 RailType railtype = (RailType)GB(p2, 0, 4);
00690
00691 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00692 if (p1 >= MapSize()) return CMD_ERROR;
00693 TileIndex end_tile = p1;
00694 Trackdir trackdir = TrackToTrackdir(track);
00695
00696 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
00697
00698 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00699
00700 for (;;) {
00701 ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00702
00703 if (CmdFailed(ret)) {
00704 if (_error_message != STR_ERROR_ALREADY_BUILT && !remove) break;
00705 _error_message = INVALID_STRING_ID;
00706 } else {
00707 total_cost.AddCost(ret);
00708 }
00709
00710 if (tile == end_tile) break;
00711
00712 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00713
00714
00715 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00716 }
00717
00718 return (total_cost.GetCost() == 0) ? CommandCost(remove ? INVALID_STRING_ID : (_error_message == INVALID_STRING_ID ? STR_ERROR_ALREADY_BUILT : _error_message)) : total_cost;
00719 }
00720
00734 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00735 {
00736 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00737 }
00738
00752 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00753 {
00754 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00755 }
00756
00768 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00769 {
00770 Slope tileh;
00771
00772
00773 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00774
00775 tileh = GetTileSlope(tile, NULL);
00776
00777 DiagDirection dir = Extract<DiagDirection, 0>(p2);
00778
00779
00780
00781
00782
00783
00784
00785
00786 if (tileh != SLOPE_FLAT && (
00787 !_settings_game.construction.build_on_slopes ||
00788 IsSteepSlope(tileh) ||
00789 !CanBuildDepotByTileh(dir, tileh)
00790 )) {
00791 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00792 }
00793
00794 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00795 if (CmdFailed(cost)) return CMD_ERROR;
00796
00797 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00798
00799 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00800
00801 if (flags & DC_EXEC) {
00802 Depot *d = new Depot(tile);
00803 d->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00804
00805 MakeRailDepot(tile, _current_company, d->index, dir, (RailType)p1);
00806 MarkTileDirtyByTile(tile);
00807
00808 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00809 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00810 }
00811
00812 return cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00813 }
00814
00835 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00836 {
00837 Track track = (Track)GB(p1, 0, 3);
00838 bool ctrl_pressed = HasBit(p1, 3);
00839 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00840 SignalType sigtype = (SignalType)GB(p1, 5, 3);
00841 bool convert_signal = HasBit(p1, 8);
00842 SignalType cycle_start = (SignalType)GB(p1, 9, 3);
00843 SignalType cycle_stop = (SignalType)GB(p1, 12, 3);
00844 CommandCost cost;
00845 uint num_dir_cycle = GB(p1, 15, 2);
00846
00847 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00848
00849
00850 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00851 !HasTrack(tile, track) || !EnsureNoTrainOnTrack(tile, track)) {
00852 return CMD_ERROR;
00853 }
00854
00855
00856 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00857
00858 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00859
00860 {
00861
00862 TrackBits trackbits = GetTrackBits(tile);
00863 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00864 trackbits != TRACK_BIT_HORZ &&
00865 trackbits != TRACK_BIT_VERT) {
00866 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
00867 }
00868 }
00869
00870
00871 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00872
00873
00874 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00875
00876 if (!HasSignalOnTrack(tile, track)) {
00877
00878 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00879 } else {
00880 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00881
00882 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00883
00884 } else if (convert_signal) {
00885
00886 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00887
00888 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00889 } else {
00890
00891 cost = CommandCost();
00892 }
00893
00894 } else {
00895
00896 cost = CommandCost();
00897 }
00898 }
00899
00900 if (flags & DC_EXEC) {
00901 Train *v = NULL;
00902
00903
00904
00905 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
00906 v = GetTrainForReservation(tile, track);
00907 if (v != NULL) FreeTrainTrackReservation(v);
00908 }
00909
00910 if (!HasSignals(tile)) {
00911
00912 SetHasSignals(tile, true);
00913 SetSignalStates(tile, 0xF);
00914 SetPresentSignals(tile, 0);
00915 SetSignalType(tile, track, sigtype);
00916 SetSignalVariant(tile, track, sigvar);
00917 }
00918
00919 if (p2 == 0) {
00920 if (!HasSignalOnTrack(tile, track)) {
00921
00922 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
00923 SetSignalType(tile, track, sigtype);
00924 SetSignalVariant(tile, track, sigvar);
00925 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
00926 } else {
00927 if (convert_signal) {
00928
00929 if (ctrl_pressed) {
00930
00931 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00932
00933 sigtype = GetSignalType(tile, track);
00934 } else {
00935
00936 SetSignalType(tile, track, sigtype);
00937 SetSignalVariant(tile, track, sigvar);
00938 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
00939 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
00940 }
00941 }
00942
00943 } else if (ctrl_pressed) {
00944
00945 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
00946
00947 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
00948
00949 SetSignalType(tile, track, sigtype);
00950 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
00951 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
00952 }
00953 } else {
00954
00955 CycleSignalSide(tile, track);
00956
00957 sigtype = GetSignalType(tile, track);
00958 }
00959 }
00960 } else {
00961
00962
00963 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
00964 SetSignalVariant(tile, track, sigvar);
00965 SetSignalType(tile, track, sigtype);
00966 }
00967
00968 if (IsPbsSignal(sigtype)) {
00969
00970 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
00971 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
00972 }
00973 MarkTileDirtyByTile(tile);
00974 AddTrackToSignalBuffer(tile, track, _current_company);
00975 YapfNotifyTrackLayoutChange(tile, track);
00976 if (v != NULL) {
00977
00978 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
00979 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
00980 TryPathReserve(v, true);
00981 }
00982 }
00983 }
00984
00985 return cost;
00986 }
00987
00988 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
00989 {
00990 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
00991 if (tile == INVALID_TILE) return false;
00992
00993
00994 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00995
00996 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
00997 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
00998
00999
01000 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01001
01002
01003 trackdir = RemoveFirstTrackdir(&trackdirbits);
01004
01005
01006 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01007
01008 switch (GetTileType(tile)) {
01009 case MP_RAILWAY:
01010 if (IsRailDepot(tile)) return false;
01011 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01012 signal_ctr++;
01013 if (IsDiagonalTrackdir(trackdir)) {
01014 signal_ctr++;
01015
01016 ClrBit(signal_ctr, 0);
01017 }
01018 return true;
01019
01020 case MP_ROAD:
01021 if (!IsLevelCrossing(tile)) return false;
01022 signal_ctr += 2;
01023 return true;
01024
01025 case MP_TUNNELBRIDGE: {
01026 TileIndex orig_tile = tile;
01027
01028 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01029 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01030
01031
01032
01033 tile = GetOtherTunnelBridgeEnd(tile);
01034
01035 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01036 return true;
01037 }
01038
01039 default: return false;
01040 }
01041 }
01042
01058 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01059 {
01060 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01061 int signal_ctr;
01062 byte signals;
01063 bool err = true;
01064 TileIndex end_tile;
01065 TileIndex start_tile = tile;
01066
01067 Track track = (Track)GB(p2, 0, 3);
01068 bool mode = HasBit(p2, 3);
01069 bool semaphores = HasBit(p2, 4);
01070 bool remove = HasBit(p2, 5);
01071 bool autofill = HasBit(p2, 6);
01072 Trackdir trackdir = TrackToTrackdir(track);
01073 byte signal_density = GB(p2, 24, 8);
01074
01075 if (p1 >= MapSize()) return CMD_ERROR;
01076 end_tile = p1;
01077 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01078
01079 if (!IsPlainRailTile(tile)) return CMD_ERROR;
01080
01081
01082
01083 signal_density *= 2;
01084
01085 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
01086
01087 track = TrackdirToTrack(trackdir);
01088 Trackdir start_trackdir = trackdir;
01089
01090
01091 if (!HasTrack(tile, track)) return CMD_ERROR;
01092
01093 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01094 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01095
01096
01097 if (HasSignalOnTrack(tile, track)) {
01098 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01099 assert(signals != 0);
01100
01101
01102 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01103
01104 sigtype = GetSignalType(tile, track);
01105
01106 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01107 } else {
01108 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01109 }
01110
01111 byte signal_dir = 0;
01112 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01113 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123 signal_ctr = 0;
01124 for (;;) {
01125
01126 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01127 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01128 SB(p1, 3, 1, mode);
01129 SB(p1, 4, 1, semaphores);
01130 SB(p1, 5, 3, sigtype);
01131 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01132
01133
01134 signals = 0;
01135 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01136 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01137
01138 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01139
01140
01141 if (CmdSucceeded(ret)) {
01142 err = false;
01143 total_cost.AddCost(ret);
01144 }
01145 }
01146
01147 if (autofill) {
01148 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01149
01150
01151 if (tile == start_tile && trackdir == start_trackdir) break;
01152 } else {
01153 if (tile == end_tile) break;
01154
01155 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01156 signal_ctr++;
01157
01158
01159 if (IsDiagonalTrackdir(trackdir)) {
01160 signal_ctr++;
01161 } else {
01162 ToggleBit(trackdir, 0);
01163 }
01164 }
01165 }
01166
01167 return err ? CMD_ERROR : total_cost;
01168 }
01169
01187 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01188 {
01189 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01190 }
01191
01203 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01204 {
01205 Track track = (Track)GB(p1, 0, 3);
01206
01207 if (!ValParamTrackOrientation(track) ||
01208 !IsPlainRailTile(tile) ||
01209 !HasTrack(tile, track) ||
01210 !EnsureNoTrainOnTrack(tile, track) ||
01211 !HasSignalOnTrack(tile, track)) {
01212 return CMD_ERROR;
01213 }
01214
01215
01216 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01217
01218
01219 if (flags & DC_EXEC) {
01220 Train *v = NULL;
01221 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01222 v = GetTrainForReservation(tile, track);
01223 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01224
01225 Trackdir td = TrackToTrackdir(track);
01226 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01227
01228 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01229 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01230 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01231 if (HasReservedTracks(next, tracks)) {
01232 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01233 }
01234 }
01235 }
01236 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01237
01238
01239 if (GetPresentSignals(tile) == 0) {
01240 SetSignalStates(tile, 0);
01241 SetHasSignals(tile, false);
01242 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01243 }
01244
01245 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01246 YapfNotifyTrackLayoutChange(tile, track);
01247 if (v != NULL) TryPathReserve(v, false);
01248
01249 MarkTileDirtyByTile(tile);
01250 }
01251
01252 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01253 }
01254
01272 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01273 {
01274 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01275 }
01276
01278 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01279 {
01280 if (v->type != VEH_TRAIN) return NULL;
01281
01282
01283
01284 Train *t = Train::From(v);
01285 if (t->IsArticulatedPart()) return NULL;
01286
01287 const RailVehicleInfo *rvi = RailVehInfo(t->engine_type);
01288 if (GetVehicleProperty(t, PROP_TRAIN_POWER, rvi->power) != 0) TrainPowerChanged(t->First());
01289
01290 return NULL;
01291 }
01292
01302 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01303 {
01304 CommandCost cost(EXPENSES_CONSTRUCTION);
01305 RailType totype = (RailType)p2;
01306
01307 if (!ValParamRailtype(totype)) return CMD_ERROR;
01308 if (p1 >= MapSize()) return CMD_ERROR;
01309
01310 uint ex = TileX(tile);
01311 uint ey = TileY(tile);
01312 uint sx = TileX(p1);
01313 uint sy = TileY(p1);
01314
01315
01316 if (ex < sx) Swap(ex, sx);
01317 if (ey < sy) Swap(ey, sy);
01318
01319 _error_message = STR_ERROR_NO_SUITABLE_RAILROAD_TRACK;
01320
01321 for (uint x = sx; x <= ex; ++x) {
01322 for (uint y = sy; y <= ey; ++y) {
01323 TileIndex tile = TileXY(x, y);
01324 TileType tt = GetTileType(tile);
01325
01326
01327 switch (tt) {
01328 case MP_RAILWAY:
01329 break;
01330 case MP_STATION:
01331 if (!HasStationRail(tile)) continue;
01332 break;
01333 case MP_ROAD:
01334 if (!IsLevelCrossing(tile)) continue;
01335 break;
01336 case MP_TUNNELBRIDGE:
01337 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01338 break;
01339 default: continue;
01340 }
01341
01342
01343 RailType type = GetRailType(tile);
01344
01345
01346 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01347
01348
01349 if (!CheckTileOwnership(tile)) continue;
01350
01351 SmallVector<Train *, 2> vehicles_affected;
01352
01353
01354
01355 if (tt != MP_TUNNELBRIDGE) {
01356 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01357 if (flags & DC_EXEC) {
01358 TrackBits reserved = GetReservedTrackbits(tile);
01359 Track track;
01360 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01361 Train *v = GetTrainForReservation(tile, track);
01362 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01363
01364 FreeTrainTrackReservation(v);
01365 *vehicles_affected.Append() = v;
01366 }
01367 }
01368
01369 SetRailType(tile, totype);
01370 MarkTileDirtyByTile(tile);
01371
01372 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01373 }
01374 }
01375
01376 switch (tt) {
01377 case MP_RAILWAY:
01378 switch (GetRailTileType(tile)) {
01379 case RAIL_TILE_DEPOT:
01380 if (flags & DC_EXEC) {
01381
01382 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01383
01384
01385 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01386 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01387 }
01388 cost.AddCost(RailConvertCost(type, totype));
01389 break;
01390
01391 default:
01392 if (flags & DC_EXEC) {
01393
01394 TrackBits tracks = GetTrackBits(tile);
01395 while (tracks != TRACK_BIT_NONE) {
01396 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01397 }
01398 }
01399 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01400 break;
01401 }
01402 break;
01403
01404 case MP_TUNNELBRIDGE: {
01405 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01406
01407
01408
01409 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01410 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01411
01412
01413 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01414 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01415
01416 if (flags & DC_EXEC) {
01417 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01418 if (HasTunnelBridgeReservation(tile)) {
01419 Train *v = GetTrainForReservation(tile, track);
01420 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01421
01422 FreeTrainTrackReservation(v);
01423 *vehicles_affected.Append() = v;
01424 }
01425 }
01426 SetRailType(tile, totype);
01427 SetRailType(endtile, totype);
01428
01429 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01430 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01431
01432 YapfNotifyTrackLayoutChange(tile, track);
01433 YapfNotifyTrackLayoutChange(endtile, track);
01434
01435 MarkTileDirtyByTile(tile);
01436 MarkTileDirtyByTile(endtile);
01437
01438 if (IsBridge(tile)) {
01439 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01440 TileIndex t = tile + delta;
01441 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01442 }
01443 }
01444
01445 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01446 } break;
01447
01448 default:
01449 if (flags & DC_EXEC) {
01450 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01451 YapfNotifyTrackLayoutChange(tile, track);
01452 }
01453
01454 cost.AddCost(RailConvertCost(type, totype));
01455 break;
01456 }
01457
01458 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01459 TryPathReserve(vehicles_affected[i], true);
01460 }
01461 }
01462 }
01463
01464 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01465 }
01466
01467 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01468 {
01469 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01470 return CMD_ERROR;
01471
01472 if (!EnsureNoVehicleOnGround(tile))
01473 return CMD_ERROR;
01474
01475 if (flags & DC_EXEC) {
01476
01477 DiagDirection dir = GetRailDepotDirection(tile);
01478 Owner owner = GetTileOwner(tile);
01479 Train *v = NULL;
01480
01481 if (HasDepotReservation(tile)) {
01482 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01483 if (v != NULL) FreeTrainTrackReservation(v);
01484 }
01485
01486 delete Depot::GetByTile(tile);
01487 DoClearSquare(tile);
01488 AddSideToSignalBuffer(tile, dir, owner);
01489 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01490 if (v != NULL) TryPathReserve(v, true);
01491 }
01492
01493 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01494 }
01495
01496 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01497 {
01498 CommandCost cost(EXPENSES_CONSTRUCTION);
01499 CommandCost ret;
01500
01501 if (flags & DC_AUTO) {
01502 if (!IsTileOwner(tile, _current_company)) {
01503 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01504 }
01505
01506 if (IsPlainRail(tile)) {
01507 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01508 } else {
01509 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01510 }
01511 }
01512
01513 switch (GetRailTileType(tile)) {
01514 case RAIL_TILE_SIGNALS:
01515 case RAIL_TILE_NORMAL: {
01516 Slope tileh = GetTileSlope(tile, NULL);
01517
01518 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01519
01520 TrackBits tracks = GetTrackBits(tile);
01521 while (tracks != TRACK_BIT_NONE) {
01522 Track track = RemoveFirstTrack(&tracks);
01523 ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01524 if (CmdFailed(ret)) return CMD_ERROR;
01525 cost.AddCost(ret);
01526 }
01527
01528
01529 if (water_ground && !(flags & DC_BANKRUPT)) {
01530 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01531
01532
01533 if (flags & DC_EXEC) DoClearSquare(tile);
01534 cost.AddCost(_price[PR_CLEAR_WATER]);
01535 }
01536
01537 return cost;
01538 }
01539
01540 case RAIL_TILE_DEPOT:
01541 return RemoveTrainDepot(tile, flags);
01542
01543 default:
01544 return CMD_ERROR;
01545 }
01546 }
01547
01552 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01553 {
01554 switch (track) {
01555 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01556 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01557 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01558 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01559 default: break;
01560 }
01561 return GetSlopeZ(x, y);
01562 }
01563
01564 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01565 {
01566 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01567 static const Point SignalPositions[2][12] = {
01568 {
01569
01570 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01571
01572 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01573 }, {
01574
01575 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01576
01577 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01578 }
01579 };
01580
01581 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01582 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01583
01584 SpriteID sprite;
01585
01586 SignalType type = GetSignalType(tile, track);
01587 SignalVariant variant = GetSignalVariant(tile, track);
01588
01589 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01590
01591 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01592 } else {
01593
01594 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01595 }
01596
01597 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01598 }
01599
01600 static uint32 _drawtile_track_palette;
01601
01602
01603 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01604 {
01605 RailFenceOffset rfo = RFO_FLAT_X;
01606 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01607 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01608 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01609 }
01610
01611 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01612 {
01613 RailFenceOffset rfo = RFO_FLAT_X;
01614 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01615 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01616 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01617 }
01618
01619 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01620 {
01621 DrawTrackFence_NW(ti, base_image);
01622 DrawTrackFence_SE(ti, base_image);
01623 }
01624
01625 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01626 {
01627 RailFenceOffset rfo = RFO_FLAT_Y;
01628 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01629 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01630 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01631 }
01632
01633 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01634 {
01635 RailFenceOffset rfo = RFO_FLAT_Y;
01636 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01637 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01638 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01639 }
01640
01641 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01642 {
01643 DrawTrackFence_NE(ti, base_image);
01644 DrawTrackFence_SW(ti, base_image);
01645 }
01646
01650 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01651 {
01652 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01653 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01654 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01655 }
01656
01660 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01661 {
01662 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01663 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01664 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01665 }
01666
01670 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01671 {
01672 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01673 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01674 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01675 }
01676
01680 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01681 {
01682 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01683 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01684 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01685 }
01686
01687
01688 static void DrawTrackDetails(const TileInfo *ti)
01689 {
01690
01691 SpriteID base_image = SPR_TRACK_FENCE_FLAT_X;
01692
01693 switch (GetRailGroundType(ti->tile)) {
01694 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01695 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01696 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01697 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01698 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01699 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01700 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01701 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01702 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01703 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01704 case RAIL_GROUND_WATER: {
01705 Corner track_corner;
01706 if (IsHalftileSlope(ti->tileh)) {
01707
01708 track_corner = GetHalftileSlopeCorner(ti->tileh);
01709 } else {
01710
01711 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01712 }
01713 switch (track_corner) {
01714 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01715 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01716 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01717 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01718 default: NOT_REACHED();
01719 }
01720 break;
01721 }
01722 default: break;
01723 }
01724 }
01725
01726
01732 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01733 {
01734
01735 static const int INF = 1000;
01736 static const SubSprite _halftile_sub_sprite[4] = {
01737 { -INF , -INF , 32 - 33, INF },
01738 { -INF , 0 + 7, INF , INF },
01739 { -31 + 33, -INF , INF , INF },
01740 { -INF , -INF , INF , 30 - 23 }
01741 };
01742
01743 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01744 RailGroundType rgt = GetRailGroundType(ti->tile);
01745 Foundation f = GetRailFoundation(ti->tileh, track);
01746 Corner halftile_corner = CORNER_INVALID;
01747
01748 if (IsNonContinuousFoundation(f)) {
01749
01750 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01751
01752 track &= ~CornerToTrackBits(halftile_corner);
01753 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01754 }
01755
01756 DrawFoundation(ti, f);
01757
01758
01759 SpriteID image;
01760 SpriteID pal = PAL_NONE;
01761 const SubSprite *sub = NULL;
01762 bool junction = false;
01763
01764
01765 if (track == 0) {
01766
01767 if (rgt == RAIL_GROUND_WATER) {
01768 if (IsSteepSlope(ti->tileh)) {
01769 DrawShoreTile(ti->tileh);
01770 image = 0;
01771 } else {
01772 image = SPR_FLAT_WATER_TILE;
01773 }
01774 } else {
01775 switch (rgt) {
01776 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01777 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01778 default: image = SPR_FLAT_GRASS_TILE; break;
01779 }
01780 image += _tileh_to_sprite[ti->tileh];
01781 }
01782 } else {
01783 if (ti->tileh != SLOPE_FLAT) {
01784
01785 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01786 } else {
01787
01788 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
01789 (image++, track == TRACK_BIT_X) ||
01790 (image++, track == TRACK_BIT_UPPER) ||
01791 (image++, track == TRACK_BIT_LOWER) ||
01792 (image++, track == TRACK_BIT_RIGHT) ||
01793 (image++, track == TRACK_BIT_LEFT) ||
01794 (image++, track == TRACK_BIT_CROSS) ||
01795
01796 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
01797 (image++, track == TRACK_BIT_VERT) ||
01798
01799 (junction = true, false) ||
01800 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
01801 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
01802 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
01803 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
01804 (image++, true);
01805 }
01806
01807 switch (rgt) {
01808 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01809 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
01810 case RAIL_GROUND_WATER: {
01811
01812 DrawShoreTile(ti->tileh);
01813 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01814 sub = &(_halftile_sub_sprite[track_corner]);
01815 break;
01816 }
01817 default: break;
01818 }
01819 }
01820
01821 if (image != 0) DrawGroundSprite(image, pal, sub);
01822
01823
01824 if (junction) {
01825 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
01826 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
01827 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
01828 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
01829 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
01830 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
01831 }
01832
01833
01834 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
01835
01836 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
01837 if (pbs & TRACK_BIT_X) {
01838 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01839 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
01840 } else {
01841 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01842 }
01843 }
01844 if (pbs & TRACK_BIT_Y) {
01845 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01846 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
01847 } else {
01848 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01849 }
01850 }
01851 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
01852 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
01853 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
01854 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
01855 }
01856
01857 if (IsValidCorner(halftile_corner)) {
01858 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01859
01860
01861 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01862 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
01863 pal = PAL_NONE;
01864 switch (rgt) {
01865 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01866 case RAIL_GROUND_ICE_DESERT:
01867 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
01868 default: break;
01869 }
01870 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
01871
01872 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
01873 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
01874 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
01875 }
01876 }
01877 }
01878
01884 enum {
01885 SIGNAL_TO_SOUTHWEST = 0,
01886 SIGNAL_TO_NORTHEAST = 2,
01887 SIGNAL_TO_SOUTHEAST = 4,
01888 SIGNAL_TO_NORTHWEST = 6,
01889 SIGNAL_TO_EAST = 8,
01890 SIGNAL_TO_WEST = 10,
01891 SIGNAL_TO_SOUTH = 12,
01892 SIGNAL_TO_NORTH = 14,
01893 };
01894
01895 static void DrawSignals(TileIndex tile, TrackBits rails)
01896 {
01897 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
01898
01899 if (!(rails & TRACK_BIT_Y)) {
01900 if (!(rails & TRACK_BIT_X)) {
01901 if (rails & TRACK_BIT_LEFT) {
01902 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
01903 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
01904 }
01905 if (rails & TRACK_BIT_RIGHT) {
01906 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
01907 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
01908 }
01909 if (rails & TRACK_BIT_UPPER) {
01910 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
01911 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
01912 }
01913 if (rails & TRACK_BIT_LOWER) {
01914 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
01915 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
01916 }
01917 } else {
01918 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
01919 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
01920 }
01921 } else {
01922 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
01923 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
01924 }
01925 }
01926
01927 static void DrawTile_Track(TileInfo *ti)
01928 {
01929 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01930 SpriteID image;
01931
01932 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
01933
01934 if (IsPlainRail(ti->tile)) {
01935 TrackBits rails = GetTrackBits(ti->tile);
01936
01937 DrawTrackBits(ti, rails);
01938
01939 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti);
01940
01941 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01942
01943 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
01944 } else {
01945
01946 const DrawTileSprites *dts;
01947 const DrawTileSeqStruct *dtss;
01948 uint32 relocation;
01949 SpriteID pal = PAL_NONE;
01950
01951 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01952
01953 if (IsInvisibilitySet(TO_BUILDINGS)) {
01954
01955 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
01956 } else {
01957 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01958 }
01959
01960 relocation = rti->total_offset;
01961
01962 image = dts->ground.sprite;
01963 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01964
01965
01966
01967 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
01968 if (image != SPR_FLAT_GRASS_TILE) {
01969 image += rti->snow_offset;
01970 } else {
01971 image = SPR_FLAT_SNOW_DESERT_TILE;
01972 }
01973 }
01974
01975 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
01976
01977
01978 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
01979 switch (GetRailDepotDirection(ti->tile)) {
01980 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
01981 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
01982 default: break;
01983 }
01984 }
01985
01986 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01987
01988 foreach_draw_tile_seq(dtss, dts->seq) {
01989 SpriteID image = dtss->image.sprite;
01990 SpriteID pal = dtss->image.pal;
01991
01992
01993 if (IsInvisibilitySet(TO_BUILDINGS) && !HasBit(image, SPRITE_MODIFIER_OPAQUE)) return;
01994
01995
01996
01997
01998 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01999 image += rti->total_offset;
02000 } else {
02001 image += relocation;
02002 }
02003
02004 pal = SpriteLayoutPaletteTransform(image, pal, _drawtile_track_palette);
02005
02006 if ((byte)dtss->delta_z != 0x80) {
02007 AddSortableSpriteToDraw(
02008 image, pal,
02009 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
02010 dtss->size_x, dtss->size_y,
02011 dtss->size_z, ti->z + dtss->delta_z,
02012 !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
02013 );
02014 } else {
02015
02016 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS));
02017 }
02018 }
02019 }
02020 DrawBridgeMiddle(ti);
02021 }
02022
02023
02024 static void DrawTileSequence(int x, int y, SpriteID ground, const DrawTileSeqStruct *dtss, uint32 offset)
02025 {
02026 SpriteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02027
02028 DrawSprite(ground, PAL_NONE, x, y);
02029 for (; dtss->image.sprite != 0; dtss++) {
02030 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
02031 SpriteID image = dtss->image.sprite + offset;
02032
02033 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOUR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
02034 }
02035 }
02036
02037 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02038 {
02039 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02040 SpriteID image = dts->ground.sprite;
02041 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02042
02043 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02044 DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
02045 }
02046
02047 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02048 {
02049 uint z;
02050 Slope tileh = GetTileSlope(tile, &z);
02051
02052 if (tileh == SLOPE_FLAT) return z;
02053 if (IsPlainRail(tile)) {
02054 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02055 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02056 } else {
02057 return z + TILE_HEIGHT;
02058 }
02059 }
02060
02061 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02062 {
02063 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02064 }
02065
02066 static void TileLoop_Track(TileIndex tile)
02067 {
02068 RailGroundType old_ground = GetRailGroundType(tile);
02069 RailGroundType new_ground;
02070
02071 if (old_ground == RAIL_GROUND_WATER) {
02072 TileLoop_Water(tile);
02073 return;
02074 }
02075
02076 switch (_settings_game.game_creation.landscape) {
02077 case LT_ARCTIC: {
02078 uint z;
02079 Slope slope = GetTileSlope(tile, &z);
02080 bool half = false;
02081
02082
02083
02084 if (IsPlainRail(tile)) {
02085 TrackBits track = GetTrackBits(tile);
02086 Foundation f = GetRailFoundation(slope, track);
02087
02088 switch (f) {
02089 case FOUNDATION_NONE:
02090
02091 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02092 break;
02093
02094 case FOUNDATION_INCLINED_X:
02095 case FOUNDATION_INCLINED_Y:
02096
02097 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02098 break;
02099
02100 case FOUNDATION_STEEP_LOWER:
02101
02102 z += TILE_HEIGHT;
02103 break;
02104
02105 default:
02106
02107 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02108 z += TILE_HEIGHT;
02109 break;
02110 }
02111
02112 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02113 } else {
02114
02115 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02116 }
02117
02118
02119
02120
02121
02122 if (z > GetSnowLine()) {
02123 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02124
02125 new_ground = RAIL_GROUND_HALF_SNOW;
02126 } else {
02127 new_ground = RAIL_GROUND_ICE_DESERT;
02128 }
02129 goto set_ground;
02130 }
02131 break;
02132 }
02133
02134 case LT_TROPIC:
02135 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02136 new_ground = RAIL_GROUND_ICE_DESERT;
02137 goto set_ground;
02138 }
02139 break;
02140 }
02141
02142 if (!IsPlainRail(tile)) return;
02143
02144 new_ground = RAIL_GROUND_GRASS;
02145
02146 if (old_ground != RAIL_GROUND_BARREN) {
02147
02148 TrackBits rail = GetTrackBits(tile);
02149
02150 switch (rail) {
02151 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02152 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02153 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02154 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02155
02156 default: {
02157 Owner owner = GetTileOwner(tile);
02158
02159 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02160 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02161 (rail & TRACK_BIT_X)
02162 )) {
02163 TileIndex n = tile + TileDiffXY(0, -1);
02164 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02165
02166 if (!IsTileType(n, MP_RAILWAY) ||
02167 !IsTileOwner(n, owner) ||
02168 nrail == TRACK_BIT_UPPER ||
02169 nrail == TRACK_BIT_LEFT) {
02170 new_ground = RAIL_GROUND_FENCE_NW;
02171 }
02172 }
02173
02174 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02175 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02176 (rail & TRACK_BIT_X)
02177 )) {
02178 TileIndex n = tile + TileDiffXY(0, 1);
02179 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02180
02181 if (!IsTileType(n, MP_RAILWAY) ||
02182 !IsTileOwner(n, owner) ||
02183 nrail == TRACK_BIT_LOWER ||
02184 nrail == TRACK_BIT_RIGHT) {
02185 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02186 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02187 }
02188 }
02189
02190 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02191 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02192 (rail & TRACK_BIT_Y)
02193 )) {
02194 TileIndex n = tile + TileDiffXY(-1, 0);
02195 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02196
02197 if (!IsTileType(n, MP_RAILWAY) ||
02198 !IsTileOwner(n, owner) ||
02199 nrail == TRACK_BIT_UPPER ||
02200 nrail == TRACK_BIT_RIGHT) {
02201 new_ground = RAIL_GROUND_FENCE_NE;
02202 }
02203 }
02204
02205 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02206 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02207 (rail & TRACK_BIT_Y)
02208 )) {
02209 TileIndex n = tile + TileDiffXY(1, 0);
02210 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02211
02212 if (!IsTileType(n, MP_RAILWAY) ||
02213 !IsTileOwner(n, owner) ||
02214 nrail == TRACK_BIT_LOWER ||
02215 nrail == TRACK_BIT_LEFT) {
02216 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02217 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02218 }
02219 }
02220 break;
02221 }
02222 }
02223 }
02224
02225 set_ground:
02226 if (old_ground != new_ground) {
02227 SetRailGroundType(tile, new_ground);
02228 MarkTileDirtyByTile(tile);
02229 }
02230 }
02231
02232
02233 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02234 {
02235
02236 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02237 TrackBits tb = GetTrackBits(tile);
02238 switch (tb) {
02239 default: NOT_REACHED();
02240 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02241 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02242 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02243 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02244 }
02245 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02246 }
02247
02248 if (mode != TRANSPORT_RAIL) return 0;
02249
02250 TrackBits trackbits = TRACK_BIT_NONE;
02251 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02252
02253 switch (GetRailTileType(tile)) {
02254 default: NOT_REACHED();
02255 case RAIL_TILE_NORMAL:
02256 trackbits = GetTrackBits(tile);
02257 break;
02258
02259 case RAIL_TILE_SIGNALS: {
02260 trackbits = GetTrackBits(tile);
02261 byte a = GetPresentSignals(tile);
02262 uint b = GetSignalStates(tile);
02263
02264 b &= a;
02265
02266
02267
02268
02269
02270
02271 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02272 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02273
02274 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02275 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02276 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02277 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02278
02279 break;
02280 }
02281
02282 case RAIL_TILE_DEPOT: {
02283 DiagDirection dir = GetRailDepotDirection(tile);
02284
02285 if (side != INVALID_DIAGDIR && side != dir) break;
02286
02287 trackbits = DiagDirToDiagTrackBits(dir);
02288 break;
02289 }
02290 }
02291
02292 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02293 }
02294
02295 static bool ClickTile_Track(TileIndex tile)
02296 {
02297 if (!IsRailDepot(tile)) return false;
02298
02299 ShowDepotWindow(tile, VEH_TRAIN);
02300 return true;
02301 }
02302
02303 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02304 {
02305 td->owner[0] = GetTileOwner(tile);
02306 switch (GetRailTileType(tile)) {
02307 case RAIL_TILE_NORMAL:
02308 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02309 break;
02310
02311 case RAIL_TILE_SIGNALS: {
02312 static const StringID signal_type[6][6] = {
02313 {
02314 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02315 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02316 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02317 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02318 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02319 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02320 },
02321 {
02322 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02323 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02324 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02325 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02326 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02327 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02328 },
02329 {
02330 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02331 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02332 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02333 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02334 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02335 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02336 },
02337 {
02338 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02339 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02340 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02341 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02342 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02343 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02344 },
02345 {
02346 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02347 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02348 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02349 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02350 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02351 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02352 },
02353 {
02354 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02355 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02356 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02357 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02358 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02359 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02360 }
02361 };
02362
02363 SignalType primary_signal;
02364 SignalType secondary_signal;
02365 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02366 primary_signal = GetSignalType(tile, TRACK_UPPER);
02367 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02368 } else {
02369 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02370 }
02371
02372 td->str = signal_type[secondary_signal][primary_signal];
02373 break;
02374 }
02375
02376 case RAIL_TILE_DEPOT:
02377 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02378 break;
02379
02380 default:
02381 NOT_REACHED();
02382 }
02383 }
02384
02385 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02386 {
02387 if (!IsTileOwner(tile, old_owner)) return;
02388
02389 if (new_owner != INVALID_OWNER) {
02390 SetTileOwner(tile, new_owner);
02391 } else {
02392 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02393 }
02394 }
02395
02396 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02397 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02398 static const int8 _deltacoord_leaveoffset[8] = {
02399 -1, 0, 1, 0,
02400 0, 1, 0, -1
02401 };
02402
02403
02409 int TicksToLeaveDepot(const Train *v)
02410 {
02411 DiagDirection dir = GetRailDepotDirection(v->tile);
02412 int length = v->tcache.cached_veh_length;
02413
02414 switch (dir) {
02415 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02416 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02417 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02418 default:
02419 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02420 }
02421
02422 return 0;
02423 }
02424
02427 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02428 {
02429 byte fract_coord;
02430 byte fract_coord_leave;
02431 DiagDirection dir;
02432 int length;
02433
02434
02435 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02436
02437 Train *v = Train::From(u);
02438
02439
02440 dir = GetRailDepotDirection(tile);
02441
02442
02443
02444 length = v->tcache.cached_veh_length;
02445
02446 fract_coord_leave =
02447 ((_fractcoords_enter[dir] & 0x0F) +
02448 (length + 1) * _deltacoord_leaveoffset[dir]) +
02449 (((_fractcoords_enter[dir] >> 4) +
02450 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02451
02452 fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02453
02454 if (_fractcoords_behind[dir] == fract_coord) {
02455
02456 return VETSB_CANNOT_ENTER;
02457 } else if (_fractcoords_enter[dir] == fract_coord) {
02458 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02459
02460 v->track = TRACK_BIT_DEPOT,
02461 v->vehstatus |= VS_HIDDEN;
02462 v->direction = ReverseDir(v->direction);
02463 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02464 v->tile = tile;
02465
02466 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02467 return VETSB_ENTERED_WORMHOLE;
02468 }
02469 } else if (fract_coord_leave == fract_coord) {
02470 if (DiagDirToDir(dir) == v->direction) {
02471
02472 if ((v = v->Next()) != NULL) {
02473 v->vehstatus &= ~VS_HIDDEN;
02474 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02475 }
02476 }
02477 }
02478
02479 return VETSB_CONTINUE;
02480 }
02481
02493 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02494 {
02495 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02496
02497
02498 if (CmdFailed(CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile))) return CMD_ERROR;
02499
02500
02501 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02502 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02503
02504 Corner track_corner;
02505 switch (rail_bits) {
02506 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02507 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02508 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02509 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02510
02511
02512 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02513 }
02514
02515
02516 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02517 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02518 if (z_old != z_new) return CMD_ERROR;
02519
02520 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02521
02522 if (tileh_old != tileh_new) {
02523
02524 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02525 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02526 }
02527 return cost;
02528 }
02529
02530 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02531 {
02532 uint z_old;
02533 Slope tileh_old = GetTileSlope(tile, &z_old);
02534 if (IsPlainRail(tile)) {
02535 TrackBits rail_bits = GetTrackBits(tile);
02536
02537 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02538
02539 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02540
02541
02542 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02543
02544
02545 Corner allowed_corner;
02546 switch (rail_bits) {
02547 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02548 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02549 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02550 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02551 default: return autoslope_result;
02552 }
02553
02554 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02555
02556
02557 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02558
02559
02560 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02561 if (allowed_corner == corner) continue;
02562 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02563 }
02564
02565
02566 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02567
02568
02569 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02570 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02571 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02572 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02573 }
02574 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02575 }
02576
02577
02578 extern const TileTypeProcs _tile_type_rail_procs = {
02579 DrawTile_Track,
02580 GetSlopeZ_Track,
02581 ClearTile_Track,
02582 NULL,
02583 GetTileDesc_Track,
02584 GetTileTrackStatus_Track,
02585 ClickTile_Track,
02586 NULL,
02587 TileLoop_Track,
02588 ChangeTileOwner_Track,
02589 NULL,
02590 VehicleEnter_Track,
02591 GetFoundation_Track,
02592 TerraformTile_Track,
02593 };