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) TryPathReserve(v, true);
00977 }
00978
00979 return cost;
00980 }
00981
00982 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
00983 {
00984 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
00985 if (tile == INVALID_TILE) return false;
00986
00987
00988 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00989
00990 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
00991 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
00992
00993
00994 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
00995
00996
00997 trackdir = RemoveFirstTrackdir(&trackdirbits);
00998
00999
01000 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01001
01002 switch (GetTileType(tile)) {
01003 case MP_RAILWAY:
01004 if (IsRailDepot(tile)) return false;
01005 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01006 signal_ctr++;
01007 if (IsDiagonalTrackdir(trackdir)) {
01008 signal_ctr++;
01009
01010 ClrBit(signal_ctr, 0);
01011 }
01012 return true;
01013
01014 case MP_ROAD:
01015 if (!IsLevelCrossing(tile)) return false;
01016 signal_ctr += 2;
01017 return true;
01018
01019 case MP_TUNNELBRIDGE: {
01020 TileIndex orig_tile = tile;
01021
01022 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01023 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01024
01025
01026
01027 tile = GetOtherTunnelBridgeEnd(tile);
01028
01029 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01030 return true;
01031 }
01032
01033 default: return false;
01034 }
01035 }
01036
01052 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01053 {
01054 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01055 int signal_ctr;
01056 byte signals;
01057 bool err = true;
01058 TileIndex end_tile;
01059 TileIndex start_tile = tile;
01060
01061 Track track = (Track)GB(p2, 0, 3);
01062 bool mode = HasBit(p2, 3);
01063 bool semaphores = HasBit(p2, 4);
01064 bool remove = HasBit(p2, 5);
01065 bool autofill = HasBit(p2, 6);
01066 Trackdir trackdir = TrackToTrackdir(track);
01067 byte signal_density = GB(p2, 24, 8);
01068
01069 if (p1 >= MapSize()) return CMD_ERROR;
01070 end_tile = p1;
01071 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01072
01073 if (!IsPlainRailTile(tile)) return CMD_ERROR;
01074
01075
01076
01077 signal_density *= 2;
01078
01079 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
01080
01081 track = TrackdirToTrack(trackdir);
01082 Trackdir start_trackdir = trackdir;
01083
01084
01085 if (!HasTrack(tile, track)) return CMD_ERROR;
01086
01087 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01088 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01089
01090
01091 if (HasSignalOnTrack(tile, track)) {
01092 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01093 assert(signals != 0);
01094
01095
01096 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01097
01098 sigtype = GetSignalType(tile, track);
01099
01100 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01101 } else {
01102 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01103 }
01104
01105 byte signal_dir = 0;
01106 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01107 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117 signal_ctr = 0;
01118 for (;;) {
01119
01120 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01121 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01122 SB(p1, 3, 1, mode);
01123 SB(p1, 4, 1, semaphores);
01124 SB(p1, 5, 3, sigtype);
01125 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01126
01127
01128 signals = 0;
01129 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01130 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01131
01132 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01133
01134
01135 if (CmdSucceeded(ret)) {
01136 err = false;
01137 total_cost.AddCost(ret);
01138 }
01139 }
01140
01141 if (autofill) {
01142 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01143
01144
01145 if (tile == start_tile && trackdir == start_trackdir) break;
01146 } else {
01147 if (tile == end_tile) break;
01148
01149 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01150 signal_ctr++;
01151
01152
01153 if (IsDiagonalTrackdir(trackdir)) {
01154 signal_ctr++;
01155 } else {
01156 ToggleBit(trackdir, 0);
01157 }
01158 }
01159 }
01160
01161 return err ? CMD_ERROR : total_cost;
01162 }
01163
01181 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01182 {
01183 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01184 }
01185
01197 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01198 {
01199 Track track = (Track)GB(p1, 0, 3);
01200
01201 if (!ValParamTrackOrientation(track) ||
01202 !IsPlainRailTile(tile) ||
01203 !HasTrack(tile, track) ||
01204 !EnsureNoTrainOnTrack(tile, track) ||
01205 !HasSignalOnTrack(tile, track)) {
01206 return CMD_ERROR;
01207 }
01208
01209
01210 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01211
01212
01213 if (flags & DC_EXEC) {
01214 Train *v = NULL;
01215 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01216 v = GetTrainForReservation(tile, track);
01217 }
01218 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01219
01220
01221 if (GetPresentSignals(tile) == 0) {
01222 SetSignalStates(tile, 0);
01223 SetHasSignals(tile, false);
01224 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01225 }
01226
01227 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01228 YapfNotifyTrackLayoutChange(tile, track);
01229 if (v != NULL) TryPathReserve(v, false);
01230
01231 MarkTileDirtyByTile(tile);
01232 }
01233
01234 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01235 }
01236
01254 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01255 {
01256 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01257 }
01258
01260 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01261 {
01262 if (v->type != VEH_TRAIN) return NULL;
01263
01264
01265
01266 Train *t = Train::From(v);
01267 if (t->IsArticulatedPart()) return NULL;
01268
01269 const RailVehicleInfo *rvi = RailVehInfo(t->engine_type);
01270 if (GetVehicleProperty(t, PROP_TRAIN_POWER, rvi->power) != 0) TrainPowerChanged(t->First());
01271
01272 return NULL;
01273 }
01274
01284 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01285 {
01286 CommandCost cost(EXPENSES_CONSTRUCTION);
01287 RailType totype = (RailType)p2;
01288
01289 if (!ValParamRailtype(totype)) return CMD_ERROR;
01290 if (p1 >= MapSize()) return CMD_ERROR;
01291
01292 uint ex = TileX(tile);
01293 uint ey = TileY(tile);
01294 uint sx = TileX(p1);
01295 uint sy = TileY(p1);
01296
01297
01298 if (ex < sx) Swap(ex, sx);
01299 if (ey < sy) Swap(ey, sy);
01300
01301 _error_message = STR_ERROR_NO_SUITABLE_RAILROAD_TRACK;
01302
01303 for (uint x = sx; x <= ex; ++x) {
01304 for (uint y = sy; y <= ey; ++y) {
01305 TileIndex tile = TileXY(x, y);
01306 TileType tt = GetTileType(tile);
01307
01308
01309 switch (tt) {
01310 case MP_RAILWAY:
01311 break;
01312 case MP_STATION:
01313 if (!HasStationRail(tile)) continue;
01314 break;
01315 case MP_ROAD:
01316 if (!IsLevelCrossing(tile)) continue;
01317 break;
01318 case MP_TUNNELBRIDGE:
01319 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01320 break;
01321 default: continue;
01322 }
01323
01324
01325 RailType type = GetRailType(tile);
01326
01327
01328 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01329
01330
01331 if (!CheckTileOwnership(tile)) continue;
01332
01333 SmallVector<Train *, 2> vehicles_affected;
01334
01335
01336
01337 if (tt != MP_TUNNELBRIDGE) {
01338 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01339 if (flags & DC_EXEC) {
01340 TrackBits reserved = GetReservedTrackbits(tile);
01341 Track track;
01342 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01343 Train *v = GetTrainForReservation(tile, track);
01344 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01345
01346 FreeTrainTrackReservation(v);
01347 *vehicles_affected.Append() = v;
01348 }
01349 }
01350
01351 SetRailType(tile, totype);
01352 MarkTileDirtyByTile(tile);
01353
01354 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01355 }
01356 }
01357
01358 switch (tt) {
01359 case MP_RAILWAY:
01360 switch (GetRailTileType(tile)) {
01361 case RAIL_TILE_DEPOT:
01362 if (flags & DC_EXEC) {
01363
01364 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01365
01366
01367 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01368 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01369 }
01370 cost.AddCost(RailConvertCost(type, totype));
01371 break;
01372
01373 default:
01374 if (flags & DC_EXEC) {
01375
01376 TrackBits tracks = GetTrackBits(tile);
01377 while (tracks != TRACK_BIT_NONE) {
01378 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01379 }
01380 }
01381 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01382 break;
01383 }
01384 break;
01385
01386 case MP_TUNNELBRIDGE: {
01387 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01388
01389
01390
01391 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01392 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01393
01394
01395 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01396 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01397
01398 if (flags & DC_EXEC) {
01399 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01400 if (HasTunnelBridgeReservation(tile)) {
01401 Train *v = GetTrainForReservation(tile, track);
01402 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01403
01404 FreeTrainTrackReservation(v);
01405 *vehicles_affected.Append() = v;
01406 }
01407 }
01408 SetRailType(tile, totype);
01409 SetRailType(endtile, totype);
01410
01411 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01412 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01413
01414 YapfNotifyTrackLayoutChange(tile, track);
01415 YapfNotifyTrackLayoutChange(endtile, track);
01416
01417 MarkTileDirtyByTile(tile);
01418 MarkTileDirtyByTile(endtile);
01419
01420 if (IsBridge(tile)) {
01421 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01422 TileIndex t = tile + delta;
01423 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01424 }
01425 }
01426
01427 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01428 } break;
01429
01430 default:
01431 if (flags & DC_EXEC) {
01432 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01433 YapfNotifyTrackLayoutChange(tile, track);
01434 }
01435
01436 cost.AddCost(RailConvertCost(type, totype));
01437 break;
01438 }
01439
01440 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01441 TryPathReserve(vehicles_affected[i], true);
01442 }
01443 }
01444 }
01445
01446 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01447 }
01448
01449 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01450 {
01451 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01452 return CMD_ERROR;
01453
01454 if (!EnsureNoVehicleOnGround(tile))
01455 return CMD_ERROR;
01456
01457 if (flags & DC_EXEC) {
01458
01459 DiagDirection dir = GetRailDepotDirection(tile);
01460 Owner owner = GetTileOwner(tile);
01461 Train *v = NULL;
01462
01463 if (HasDepotReservation(tile)) {
01464 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01465 if (v != NULL) FreeTrainTrackReservation(v);
01466 }
01467
01468 delete Depot::GetByTile(tile);
01469 DoClearSquare(tile);
01470 AddSideToSignalBuffer(tile, dir, owner);
01471 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01472 if (v != NULL) TryPathReserve(v, true);
01473 }
01474
01475 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01476 }
01477
01478 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01479 {
01480 CommandCost cost(EXPENSES_CONSTRUCTION);
01481 CommandCost ret;
01482
01483 if (flags & DC_AUTO) {
01484 if (!IsTileOwner(tile, _current_company)) {
01485 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01486 }
01487
01488 if (IsPlainRail(tile)) {
01489 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01490 } else {
01491 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01492 }
01493 }
01494
01495 switch (GetRailTileType(tile)) {
01496 case RAIL_TILE_SIGNALS:
01497 case RAIL_TILE_NORMAL: {
01498 Slope tileh = GetTileSlope(tile, NULL);
01499
01500 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01501
01502 TrackBits tracks = GetTrackBits(tile);
01503 while (tracks != TRACK_BIT_NONE) {
01504 Track track = RemoveFirstTrack(&tracks);
01505 ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01506 if (CmdFailed(ret)) return CMD_ERROR;
01507 cost.AddCost(ret);
01508 }
01509
01510
01511 if (water_ground && !(flags & DC_BANKRUPT)) {
01512 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01513
01514
01515 if (flags & DC_EXEC) DoClearSquare(tile);
01516 cost.AddCost(_price[PR_CLEAR_WATER]);
01517 }
01518
01519 return cost;
01520 }
01521
01522 case RAIL_TILE_DEPOT:
01523 return RemoveTrainDepot(tile, flags);
01524
01525 default:
01526 return CMD_ERROR;
01527 }
01528 }
01529
01534 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01535 {
01536 switch (track) {
01537 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01538 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01539 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01540 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01541 default: break;
01542 }
01543 return GetSlopeZ(x, y);
01544 }
01545
01546 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01547 {
01548 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01549 static const Point SignalPositions[2][12] = {
01550 {
01551
01552 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01553
01554 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01555 }, {
01556
01557 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01558
01559 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01560 }
01561 };
01562
01563 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01564 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01565
01566 SpriteID sprite;
01567
01568 SignalType type = GetSignalType(tile, track);
01569 SignalVariant variant = GetSignalVariant(tile, track);
01570
01571 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01572
01573 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01574 } else {
01575
01576 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01577 }
01578
01579 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01580 }
01581
01582 static uint32 _drawtile_track_palette;
01583
01584
01585 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01586 {
01587 RailFenceOffset rfo = RFO_FLAT_X;
01588 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01589 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01590 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01591 }
01592
01593 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01594 {
01595 RailFenceOffset rfo = RFO_FLAT_X;
01596 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01597 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01598 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01599 }
01600
01601 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01602 {
01603 DrawTrackFence_NW(ti, base_image);
01604 DrawTrackFence_SE(ti, base_image);
01605 }
01606
01607 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01608 {
01609 RailFenceOffset rfo = RFO_FLAT_Y;
01610 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01611 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01612 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01613 }
01614
01615 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01616 {
01617 RailFenceOffset rfo = RFO_FLAT_Y;
01618 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01619 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01620 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01621 }
01622
01623 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01624 {
01625 DrawTrackFence_NE(ti, base_image);
01626 DrawTrackFence_SW(ti, base_image);
01627 }
01628
01632 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01633 {
01634 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01635 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01636 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01637 }
01638
01642 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01643 {
01644 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01645 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01646 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01647 }
01648
01652 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01653 {
01654 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01655 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01656 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01657 }
01658
01662 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01663 {
01664 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01665 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01666 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01667 }
01668
01669
01670 static void DrawTrackDetails(const TileInfo *ti)
01671 {
01672
01673 SpriteID base_image = SPR_TRACK_FENCE_FLAT_X;
01674
01675 switch (GetRailGroundType(ti->tile)) {
01676 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01677 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01678 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01679 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01680 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01681 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01682 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01683 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01684 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01685 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01686 case RAIL_GROUND_WATER: {
01687 Corner track_corner;
01688 if (IsHalftileSlope(ti->tileh)) {
01689
01690 track_corner = GetHalftileSlopeCorner(ti->tileh);
01691 } else {
01692
01693 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01694 }
01695 switch (track_corner) {
01696 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01697 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01698 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01699 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01700 default: NOT_REACHED();
01701 }
01702 break;
01703 }
01704 default: break;
01705 }
01706 }
01707
01708
01714 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01715 {
01716
01717 static const int INF = 1000;
01718 static const SubSprite _halftile_sub_sprite[4] = {
01719 { -INF , -INF , 32 - 33, INF },
01720 { -INF , 0 + 7, INF , INF },
01721 { -31 + 33, -INF , INF , INF },
01722 { -INF , -INF , INF , 30 - 23 }
01723 };
01724
01725 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01726 RailGroundType rgt = GetRailGroundType(ti->tile);
01727 Foundation f = GetRailFoundation(ti->tileh, track);
01728 Corner halftile_corner = CORNER_INVALID;
01729
01730 if (IsNonContinuousFoundation(f)) {
01731
01732 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01733
01734 track &= ~CornerToTrackBits(halftile_corner);
01735 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01736 }
01737
01738 DrawFoundation(ti, f);
01739
01740
01741 SpriteID image;
01742 SpriteID pal = PAL_NONE;
01743 const SubSprite *sub = NULL;
01744 bool junction = false;
01745
01746
01747 if (track == 0) {
01748
01749 if (rgt == RAIL_GROUND_WATER) {
01750 if (IsSteepSlope(ti->tileh)) {
01751 DrawShoreTile(ti->tileh);
01752 image = 0;
01753 } else {
01754 image = SPR_FLAT_WATER_TILE;
01755 }
01756 } else {
01757 switch (rgt) {
01758 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01759 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01760 default: image = SPR_FLAT_GRASS_TILE; break;
01761 }
01762 image += _tileh_to_sprite[ti->tileh];
01763 }
01764 } else {
01765 if (ti->tileh != SLOPE_FLAT) {
01766
01767 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01768 } else {
01769
01770 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
01771 (image++, track == TRACK_BIT_X) ||
01772 (image++, track == TRACK_BIT_UPPER) ||
01773 (image++, track == TRACK_BIT_LOWER) ||
01774 (image++, track == TRACK_BIT_RIGHT) ||
01775 (image++, track == TRACK_BIT_LEFT) ||
01776 (image++, track == TRACK_BIT_CROSS) ||
01777
01778 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
01779 (image++, track == TRACK_BIT_VERT) ||
01780
01781 (junction = true, false) ||
01782 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
01783 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
01784 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
01785 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
01786 (image++, true);
01787 }
01788
01789 switch (rgt) {
01790 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01791 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
01792 case RAIL_GROUND_WATER: {
01793
01794 DrawShoreTile(ti->tileh);
01795 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01796 sub = &(_halftile_sub_sprite[track_corner]);
01797 break;
01798 }
01799 default: break;
01800 }
01801 }
01802
01803 if (image != 0) DrawGroundSprite(image, pal, sub);
01804
01805
01806 if (junction) {
01807 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
01808 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
01809 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
01810 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
01811 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
01812 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
01813 }
01814
01815
01816 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
01817
01818 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
01819 if (pbs & TRACK_BIT_X) {
01820 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01821 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
01822 } else {
01823 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01824 }
01825 }
01826 if (pbs & TRACK_BIT_Y) {
01827 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01828 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
01829 } else {
01830 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01831 }
01832 }
01833 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
01834 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
01835 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
01836 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
01837 }
01838
01839 if (IsValidCorner(halftile_corner)) {
01840 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01841
01842
01843 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01844 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
01845 pal = PAL_NONE;
01846 switch (rgt) {
01847 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01848 case RAIL_GROUND_ICE_DESERT:
01849 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
01850 default: break;
01851 }
01852 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
01853
01854 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
01855 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
01856 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
01857 }
01858 }
01859 }
01860
01866 enum {
01867 SIGNAL_TO_SOUTHWEST = 0,
01868 SIGNAL_TO_NORTHEAST = 2,
01869 SIGNAL_TO_SOUTHEAST = 4,
01870 SIGNAL_TO_NORTHWEST = 6,
01871 SIGNAL_TO_EAST = 8,
01872 SIGNAL_TO_WEST = 10,
01873 SIGNAL_TO_SOUTH = 12,
01874 SIGNAL_TO_NORTH = 14,
01875 };
01876
01877 static void DrawSignals(TileIndex tile, TrackBits rails)
01878 {
01879 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
01880
01881 if (!(rails & TRACK_BIT_Y)) {
01882 if (!(rails & TRACK_BIT_X)) {
01883 if (rails & TRACK_BIT_LEFT) {
01884 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
01885 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
01886 }
01887 if (rails & TRACK_BIT_RIGHT) {
01888 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
01889 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
01890 }
01891 if (rails & TRACK_BIT_UPPER) {
01892 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
01893 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
01894 }
01895 if (rails & TRACK_BIT_LOWER) {
01896 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
01897 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
01898 }
01899 } else {
01900 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
01901 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
01902 }
01903 } else {
01904 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
01905 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
01906 }
01907 }
01908
01909 static void DrawTile_Track(TileInfo *ti)
01910 {
01911 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01912 SpriteID image;
01913
01914 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
01915
01916 if (IsPlainRail(ti->tile)) {
01917 TrackBits rails = GetTrackBits(ti->tile);
01918
01919 DrawTrackBits(ti, rails);
01920
01921 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti);
01922
01923 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01924
01925 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
01926 } else {
01927
01928 const DrawTileSprites *dts;
01929 const DrawTileSeqStruct *dtss;
01930 uint32 relocation;
01931 SpriteID pal = PAL_NONE;
01932
01933 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01934
01935 if (IsInvisibilitySet(TO_BUILDINGS)) {
01936
01937 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
01938 } else {
01939 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01940 }
01941
01942 relocation = rti->total_offset;
01943
01944 image = dts->ground.sprite;
01945 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01946
01947
01948
01949 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
01950 if (image != SPR_FLAT_GRASS_TILE) {
01951 image += rti->snow_offset;
01952 } else {
01953 image = SPR_FLAT_SNOW_DESERT_TILE;
01954 }
01955 }
01956
01957 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
01958
01959
01960 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
01961 switch (GetRailDepotDirection(ti->tile)) {
01962 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
01963 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
01964 default: break;
01965 }
01966 }
01967
01968 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01969
01970 foreach_draw_tile_seq(dtss, dts->seq) {
01971 SpriteID image = dtss->image.sprite;
01972 SpriteID pal = dtss->image.pal;
01973
01974
01975 if (IsInvisibilitySet(TO_BUILDINGS) && !HasBit(image, SPRITE_MODIFIER_OPAQUE)) return;
01976
01977
01978
01979
01980 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01981 image += rti->total_offset;
01982 } else {
01983 image += relocation;
01984 }
01985
01986 pal = SpriteLayoutPaletteTransform(image, pal, _drawtile_track_palette);
01987
01988 if ((byte)dtss->delta_z != 0x80) {
01989 AddSortableSpriteToDraw(
01990 image, pal,
01991 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
01992 dtss->size_x, dtss->size_y,
01993 dtss->size_z, ti->z + dtss->delta_z,
01994 !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
01995 );
01996 } else {
01997
01998 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS));
01999 }
02000 }
02001 }
02002 DrawBridgeMiddle(ti);
02003 }
02004
02005
02006 static void DrawTileSequence(int x, int y, SpriteID ground, const DrawTileSeqStruct *dtss, uint32 offset)
02007 {
02008 SpriteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02009
02010 DrawSprite(ground, PAL_NONE, x, y);
02011 for (; dtss->image.sprite != 0; dtss++) {
02012 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
02013 SpriteID image = dtss->image.sprite + offset;
02014
02015 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOUR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
02016 }
02017 }
02018
02019 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02020 {
02021 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02022 SpriteID image = dts->ground.sprite;
02023 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02024
02025 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02026 DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
02027 }
02028
02029 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02030 {
02031 uint z;
02032 Slope tileh = GetTileSlope(tile, &z);
02033
02034 if (tileh == SLOPE_FLAT) return z;
02035 if (IsPlainRail(tile)) {
02036 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02037 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02038 } else {
02039 return z + TILE_HEIGHT;
02040 }
02041 }
02042
02043 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02044 {
02045 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02046 }
02047
02048 static void TileLoop_Track(TileIndex tile)
02049 {
02050 RailGroundType old_ground = GetRailGroundType(tile);
02051 RailGroundType new_ground;
02052
02053 if (old_ground == RAIL_GROUND_WATER) {
02054 TileLoop_Water(tile);
02055 return;
02056 }
02057
02058 switch (_settings_game.game_creation.landscape) {
02059 case LT_ARCTIC: {
02060 uint z;
02061 Slope slope = GetTileSlope(tile, &z);
02062 bool half = false;
02063
02064
02065
02066 if (IsPlainRail(tile)) {
02067 TrackBits track = GetTrackBits(tile);
02068 Foundation f = GetRailFoundation(slope, track);
02069
02070 switch (f) {
02071 case FOUNDATION_NONE:
02072
02073 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02074 break;
02075
02076 case FOUNDATION_INCLINED_X:
02077 case FOUNDATION_INCLINED_Y:
02078
02079 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02080 break;
02081
02082 case FOUNDATION_STEEP_LOWER:
02083
02084 z += TILE_HEIGHT;
02085 break;
02086
02087 default:
02088
02089 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02090 z += TILE_HEIGHT;
02091 break;
02092 }
02093
02094 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02095 } else {
02096
02097 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02098 }
02099
02100
02101
02102
02103
02104 if (z > GetSnowLine()) {
02105 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02106
02107 new_ground = RAIL_GROUND_HALF_SNOW;
02108 } else {
02109 new_ground = RAIL_GROUND_ICE_DESERT;
02110 }
02111 goto set_ground;
02112 }
02113 break;
02114 }
02115
02116 case LT_TROPIC:
02117 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02118 new_ground = RAIL_GROUND_ICE_DESERT;
02119 goto set_ground;
02120 }
02121 break;
02122 }
02123
02124 if (!IsPlainRail(tile)) return;
02125
02126 new_ground = RAIL_GROUND_GRASS;
02127
02128 if (old_ground != RAIL_GROUND_BARREN) {
02129
02130 TrackBits rail = GetTrackBits(tile);
02131
02132 switch (rail) {
02133 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02134 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02135 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02136 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02137
02138 default: {
02139 Owner owner = GetTileOwner(tile);
02140
02141 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02142 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02143 (rail & TRACK_BIT_X)
02144 )) {
02145 TileIndex n = tile + TileDiffXY(0, -1);
02146 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02147
02148 if (!IsTileType(n, MP_RAILWAY) ||
02149 !IsTileOwner(n, owner) ||
02150 nrail == TRACK_BIT_UPPER ||
02151 nrail == TRACK_BIT_LEFT) {
02152 new_ground = RAIL_GROUND_FENCE_NW;
02153 }
02154 }
02155
02156 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02157 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02158 (rail & TRACK_BIT_X)
02159 )) {
02160 TileIndex n = tile + TileDiffXY(0, 1);
02161 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02162
02163 if (!IsTileType(n, MP_RAILWAY) ||
02164 !IsTileOwner(n, owner) ||
02165 nrail == TRACK_BIT_LOWER ||
02166 nrail == TRACK_BIT_RIGHT) {
02167 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02168 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02169 }
02170 }
02171
02172 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02173 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02174 (rail & TRACK_BIT_Y)
02175 )) {
02176 TileIndex n = tile + TileDiffXY(-1, 0);
02177 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02178
02179 if (!IsTileType(n, MP_RAILWAY) ||
02180 !IsTileOwner(n, owner) ||
02181 nrail == TRACK_BIT_UPPER ||
02182 nrail == TRACK_BIT_RIGHT) {
02183 new_ground = RAIL_GROUND_FENCE_NE;
02184 }
02185 }
02186
02187 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02188 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02189 (rail & TRACK_BIT_Y)
02190 )) {
02191 TileIndex n = tile + TileDiffXY(1, 0);
02192 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02193
02194 if (!IsTileType(n, MP_RAILWAY) ||
02195 !IsTileOwner(n, owner) ||
02196 nrail == TRACK_BIT_LOWER ||
02197 nrail == TRACK_BIT_LEFT) {
02198 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02199 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02200 }
02201 }
02202 break;
02203 }
02204 }
02205 }
02206
02207 set_ground:
02208 if (old_ground != new_ground) {
02209 SetRailGroundType(tile, new_ground);
02210 MarkTileDirtyByTile(tile);
02211 }
02212 }
02213
02214
02215 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02216 {
02217
02218 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02219 TrackBits tb = GetTrackBits(tile);
02220 switch (tb) {
02221 default: NOT_REACHED();
02222 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02223 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02224 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02225 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02226 }
02227 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02228 }
02229
02230 if (mode != TRANSPORT_RAIL) return 0;
02231
02232 TrackBits trackbits = TRACK_BIT_NONE;
02233 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02234
02235 switch (GetRailTileType(tile)) {
02236 default: NOT_REACHED();
02237 case RAIL_TILE_NORMAL:
02238 trackbits = GetTrackBits(tile);
02239 break;
02240
02241 case RAIL_TILE_SIGNALS: {
02242 trackbits = GetTrackBits(tile);
02243 byte a = GetPresentSignals(tile);
02244 uint b = GetSignalStates(tile);
02245
02246 b &= a;
02247
02248
02249
02250
02251
02252
02253 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02254 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02255
02256 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02257 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02258 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02259 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02260
02261 break;
02262 }
02263
02264 case RAIL_TILE_DEPOT: {
02265 DiagDirection dir = GetRailDepotDirection(tile);
02266
02267 if (side != INVALID_DIAGDIR && side != dir) break;
02268
02269 trackbits = DiagDirToDiagTrackBits(dir);
02270 break;
02271 }
02272 }
02273
02274 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02275 }
02276
02277 static bool ClickTile_Track(TileIndex tile)
02278 {
02279 if (!IsRailDepot(tile)) return false;
02280
02281 ShowDepotWindow(tile, VEH_TRAIN);
02282 return true;
02283 }
02284
02285 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02286 {
02287 td->owner[0] = GetTileOwner(tile);
02288 switch (GetRailTileType(tile)) {
02289 case RAIL_TILE_NORMAL:
02290 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02291 break;
02292
02293 case RAIL_TILE_SIGNALS: {
02294 static const StringID signal_type[6][6] = {
02295 {
02296 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02297 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02298 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02299 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02300 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02301 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02302 },
02303 {
02304 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02305 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02306 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02307 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02308 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02309 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02310 },
02311 {
02312 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02313 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02314 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02315 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02316 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02317 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02318 },
02319 {
02320 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02321 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02322 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02323 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02324 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02325 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02326 },
02327 {
02328 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02329 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02330 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02331 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02332 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02333 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02334 },
02335 {
02336 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02337 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02338 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02339 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02340 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02341 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02342 }
02343 };
02344
02345 SignalType primary_signal;
02346 SignalType secondary_signal;
02347 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02348 primary_signal = GetSignalType(tile, TRACK_UPPER);
02349 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02350 } else {
02351 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02352 }
02353
02354 td->str = signal_type[secondary_signal][primary_signal];
02355 break;
02356 }
02357
02358 case RAIL_TILE_DEPOT:
02359 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02360 break;
02361
02362 default:
02363 NOT_REACHED();
02364 }
02365 }
02366
02367 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02368 {
02369 if (!IsTileOwner(tile, old_owner)) return;
02370
02371 if (new_owner != INVALID_OWNER) {
02372 SetTileOwner(tile, new_owner);
02373 } else {
02374 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02375 }
02376 }
02377
02378 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02379 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02380 static const int8 _deltacoord_leaveoffset[8] = {
02381 -1, 0, 1, 0,
02382 0, 1, 0, -1
02383 };
02384
02385
02391 int TicksToLeaveDepot(const Train *v)
02392 {
02393 DiagDirection dir = GetRailDepotDirection(v->tile);
02394 int length = v->tcache.cached_veh_length;
02395
02396 switch (dir) {
02397 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02398 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02399 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02400 default:
02401 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02402 }
02403
02404 return 0;
02405 }
02406
02409 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02410 {
02411 byte fract_coord;
02412 byte fract_coord_leave;
02413 DiagDirection dir;
02414 int length;
02415
02416
02417 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02418
02419 Train *v = Train::From(u);
02420
02421
02422 dir = GetRailDepotDirection(tile);
02423
02424
02425
02426 length = v->tcache.cached_veh_length;
02427
02428 fract_coord_leave =
02429 ((_fractcoords_enter[dir] & 0x0F) +
02430 (length + 1) * _deltacoord_leaveoffset[dir]) +
02431 (((_fractcoords_enter[dir] >> 4) +
02432 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02433
02434 fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02435
02436 if (_fractcoords_behind[dir] == fract_coord) {
02437
02438 return VETSB_CANNOT_ENTER;
02439 } else if (_fractcoords_enter[dir] == fract_coord) {
02440 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02441
02442 v->track = TRACK_BIT_DEPOT,
02443 v->vehstatus |= VS_HIDDEN;
02444 v->direction = ReverseDir(v->direction);
02445 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02446 v->tile = tile;
02447
02448 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02449 return VETSB_ENTERED_WORMHOLE;
02450 }
02451 } else if (fract_coord_leave == fract_coord) {
02452 if (DiagDirToDir(dir) == v->direction) {
02453
02454 if ((v = v->Next()) != NULL) {
02455 v->vehstatus &= ~VS_HIDDEN;
02456 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02457 }
02458 }
02459 }
02460
02461 return VETSB_CONTINUE;
02462 }
02463
02475 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02476 {
02477 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02478
02479
02480 if (CmdFailed(CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile))) return CMD_ERROR;
02481
02482
02483 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02484 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02485
02486 Corner track_corner;
02487 switch (rail_bits) {
02488 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02489 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02490 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02491 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02492
02493
02494 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02495 }
02496
02497
02498 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02499 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02500 if (z_old != z_new) return CMD_ERROR;
02501
02502 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02503
02504 if (tileh_old != tileh_new) {
02505
02506 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02507 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02508 }
02509 return cost;
02510 }
02511
02512 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02513 {
02514 uint z_old;
02515 Slope tileh_old = GetTileSlope(tile, &z_old);
02516 if (IsPlainRail(tile)) {
02517 TrackBits rail_bits = GetTrackBits(tile);
02518
02519 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02520
02521 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02522
02523
02524 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02525
02526
02527 Corner allowed_corner;
02528 switch (rail_bits) {
02529 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02530 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02531 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02532 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02533 default: return autoslope_result;
02534 }
02535
02536 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02537
02538
02539 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02540
02541
02542 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02543 if (allowed_corner == corner) continue;
02544 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02545 }
02546
02547
02548 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02549
02550
02551 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02552 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02553 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02554 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02555 }
02556 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02557 }
02558
02559
02560 extern const TileTypeProcs _tile_type_rail_procs = {
02561 DrawTile_Track,
02562 GetSlopeZ_Track,
02563 ClearTile_Track,
02564 NULL,
02565 GetTileDesc_Track,
02566 GetTileTrackStatus_Track,
02567 ClickTile_Track,
02568 NULL,
02569 TileLoop_Track,
02570 ChangeTileOwner_Track,
02571 NULL,
02572 VehicleEnter_Track,
02573 GetFoundation_Track,
02574 TerraformTile_Track,
02575 };