00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "landscape.h"
00015 #include "viewport_func.h"
00016 #include "command_func.h"
00017 #include "engine_base.h"
00018 #include "depot_base.h"
00019 #include "pathfinder/yapf/yapf_cache.h"
00020 #include "newgrf_engine.h"
00021 #include "landscape_type.h"
00022 #include "train.h"
00023 #include "variables.h"
00024 #include "autoslope.h"
00025 #include "water.h"
00026 #include "tunnelbridge_map.h"
00027 #include "window_func.h"
00028 #include "vehicle_func.h"
00029 #include "sound_func.h"
00030 #include "tunnelbridge.h"
00031 #include "functions.h"
00032 #include "elrail_func.h"
00033 #include "town.h"
00034 #include "pbs.h"
00035 #include "company_base.h"
00036
00037 #include "table/strings.h"
00038 #include "table/sprites.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 (ret.Failed()) 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 (ret.Failed()) 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 (ret.Failed()) return ret;
00419 cost.AddCost(ret);
00420
00421 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00422 if (ret.Failed()) 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 (DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Failed()) 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 (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) 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 (ret.Failed()) {
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 (cost.Failed()) 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 (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) 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 (ret.Succeeded()) {
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) t->First()->PowerChanged();
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 (ret.Failed()) 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 SpriteID pal = PAL_NONE;
01948
01949 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01950
01951 if (IsInvisibilitySet(TO_BUILDINGS)) {
01952
01953 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
01954 } else {
01955 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01956 }
01957
01958 image = dts->ground.sprite;
01959 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01960
01961
01962
01963 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
01964 if (image != SPR_FLAT_GRASS_TILE) {
01965 image += rti->snow_offset;
01966 } else {
01967 image = SPR_FLAT_SNOW_DESERT_TILE;
01968 }
01969 }
01970
01971 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
01972
01973
01974 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
01975 switch (GetRailDepotDirection(ti->tile)) {
01976 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
01977 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
01978 default: break;
01979 }
01980 }
01981
01982 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01983
01984
01985 DrawRailTileSeq(ti, dts, TO_BUILDINGS, rti->total_offset, 0, _drawtile_track_palette);
01986 }
01987 DrawBridgeMiddle(ti);
01988 }
01989
01990 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
01991 {
01992 const DrawTileSprites *dts = &_depot_gfx_table[dir];
01993 SpriteID image = dts->ground.sprite;
01994 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
01995
01996 x += 33;
01997 y += 17;
01998
01999 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02000 SpriteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02001
02002 DrawSprite(image, PAL_NONE, x, y);
02003 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02004 }
02005
02006 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02007 {
02008 uint z;
02009 Slope tileh = GetTileSlope(tile, &z);
02010
02011 if (tileh == SLOPE_FLAT) return z;
02012 if (IsPlainRail(tile)) {
02013 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02014 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02015 } else {
02016 return z + TILE_HEIGHT;
02017 }
02018 }
02019
02020 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02021 {
02022 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02023 }
02024
02025 static void TileLoop_Track(TileIndex tile)
02026 {
02027 RailGroundType old_ground = GetRailGroundType(tile);
02028 RailGroundType new_ground;
02029
02030 if (old_ground == RAIL_GROUND_WATER) {
02031 TileLoop_Water(tile);
02032 return;
02033 }
02034
02035 switch (_settings_game.game_creation.landscape) {
02036 case LT_ARCTIC: {
02037 uint z;
02038 Slope slope = GetTileSlope(tile, &z);
02039 bool half = false;
02040
02041
02042
02043 if (IsPlainRail(tile)) {
02044 TrackBits track = GetTrackBits(tile);
02045 Foundation f = GetRailFoundation(slope, track);
02046
02047 switch (f) {
02048 case FOUNDATION_NONE:
02049
02050 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02051 break;
02052
02053 case FOUNDATION_INCLINED_X:
02054 case FOUNDATION_INCLINED_Y:
02055
02056 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02057 break;
02058
02059 case FOUNDATION_STEEP_LOWER:
02060
02061 z += TILE_HEIGHT;
02062 break;
02063
02064 default:
02065
02066 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02067 z += TILE_HEIGHT;
02068 break;
02069 }
02070
02071 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02072 } else {
02073
02074 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02075 }
02076
02077
02078
02079
02080
02081 if (z > GetSnowLine()) {
02082 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02083
02084 new_ground = RAIL_GROUND_HALF_SNOW;
02085 } else {
02086 new_ground = RAIL_GROUND_ICE_DESERT;
02087 }
02088 goto set_ground;
02089 }
02090 break;
02091 }
02092
02093 case LT_TROPIC:
02094 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02095 new_ground = RAIL_GROUND_ICE_DESERT;
02096 goto set_ground;
02097 }
02098 break;
02099 }
02100
02101 if (!IsPlainRail(tile)) return;
02102
02103 new_ground = RAIL_GROUND_GRASS;
02104
02105 if (old_ground != RAIL_GROUND_BARREN) {
02106
02107 TrackBits rail = GetTrackBits(tile);
02108
02109 switch (rail) {
02110 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02111 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02112 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02113 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02114
02115 default: {
02116 Owner owner = GetTileOwner(tile);
02117
02118 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02119 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02120 (rail & TRACK_BIT_X)
02121 )) {
02122 TileIndex n = tile + TileDiffXY(0, -1);
02123 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02124
02125 if (!IsTileType(n, MP_RAILWAY) ||
02126 !IsTileOwner(n, owner) ||
02127 nrail == TRACK_BIT_UPPER ||
02128 nrail == TRACK_BIT_LEFT) {
02129 new_ground = RAIL_GROUND_FENCE_NW;
02130 }
02131 }
02132
02133 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02134 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02135 (rail & TRACK_BIT_X)
02136 )) {
02137 TileIndex n = tile + TileDiffXY(0, 1);
02138 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02139
02140 if (!IsTileType(n, MP_RAILWAY) ||
02141 !IsTileOwner(n, owner) ||
02142 nrail == TRACK_BIT_LOWER ||
02143 nrail == TRACK_BIT_RIGHT) {
02144 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02145 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02146 }
02147 }
02148
02149 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02150 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02151 (rail & TRACK_BIT_Y)
02152 )) {
02153 TileIndex n = tile + TileDiffXY(-1, 0);
02154 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02155
02156 if (!IsTileType(n, MP_RAILWAY) ||
02157 !IsTileOwner(n, owner) ||
02158 nrail == TRACK_BIT_UPPER ||
02159 nrail == TRACK_BIT_RIGHT) {
02160 new_ground = RAIL_GROUND_FENCE_NE;
02161 }
02162 }
02163
02164 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02165 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02166 (rail & TRACK_BIT_Y)
02167 )) {
02168 TileIndex n = tile + TileDiffXY(1, 0);
02169 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02170
02171 if (!IsTileType(n, MP_RAILWAY) ||
02172 !IsTileOwner(n, owner) ||
02173 nrail == TRACK_BIT_LOWER ||
02174 nrail == TRACK_BIT_LEFT) {
02175 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02176 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02177 }
02178 }
02179 break;
02180 }
02181 }
02182 }
02183
02184 set_ground:
02185 if (old_ground != new_ground) {
02186 SetRailGroundType(tile, new_ground);
02187 MarkTileDirtyByTile(tile);
02188 }
02189 }
02190
02191
02192 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02193 {
02194
02195 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02196 TrackBits tb = GetTrackBits(tile);
02197 switch (tb) {
02198 default: NOT_REACHED();
02199 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02200 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02201 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02202 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02203 }
02204 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02205 }
02206
02207 if (mode != TRANSPORT_RAIL) return 0;
02208
02209 TrackBits trackbits = TRACK_BIT_NONE;
02210 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02211
02212 switch (GetRailTileType(tile)) {
02213 default: NOT_REACHED();
02214 case RAIL_TILE_NORMAL:
02215 trackbits = GetTrackBits(tile);
02216 break;
02217
02218 case RAIL_TILE_SIGNALS: {
02219 trackbits = GetTrackBits(tile);
02220 byte a = GetPresentSignals(tile);
02221 uint b = GetSignalStates(tile);
02222
02223 b &= a;
02224
02225
02226
02227
02228
02229
02230 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02231 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02232
02233 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02234 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02235 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02236 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02237
02238 break;
02239 }
02240
02241 case RAIL_TILE_DEPOT: {
02242 DiagDirection dir = GetRailDepotDirection(tile);
02243
02244 if (side != INVALID_DIAGDIR && side != dir) break;
02245
02246 trackbits = DiagDirToDiagTrackBits(dir);
02247 break;
02248 }
02249 }
02250
02251 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02252 }
02253
02254 static bool ClickTile_Track(TileIndex tile)
02255 {
02256 if (!IsRailDepot(tile)) return false;
02257
02258 ShowDepotWindow(tile, VEH_TRAIN);
02259 return true;
02260 }
02261
02262 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02263 {
02264 td->owner[0] = GetTileOwner(tile);
02265 switch (GetRailTileType(tile)) {
02266 case RAIL_TILE_NORMAL:
02267 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02268 break;
02269
02270 case RAIL_TILE_SIGNALS: {
02271 static const StringID signal_type[6][6] = {
02272 {
02273 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02274 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02275 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02276 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02277 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02278 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02279 },
02280 {
02281 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02282 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02283 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02284 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02285 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02286 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02287 },
02288 {
02289 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02290 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02291 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02292 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02293 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02294 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02295 },
02296 {
02297 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02298 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02299 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02300 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02301 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02302 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02303 },
02304 {
02305 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02306 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02307 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02308 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02309 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02310 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02311 },
02312 {
02313 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02314 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02315 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02316 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02317 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02318 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02319 }
02320 };
02321
02322 SignalType primary_signal;
02323 SignalType secondary_signal;
02324 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02325 primary_signal = GetSignalType(tile, TRACK_UPPER);
02326 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02327 } else {
02328 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02329 }
02330
02331 td->str = signal_type[secondary_signal][primary_signal];
02332 break;
02333 }
02334
02335 case RAIL_TILE_DEPOT:
02336 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02337 break;
02338
02339 default:
02340 NOT_REACHED();
02341 }
02342 }
02343
02344 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02345 {
02346 if (!IsTileOwner(tile, old_owner)) return;
02347
02348 if (new_owner != INVALID_OWNER) {
02349 SetTileOwner(tile, new_owner);
02350 } else {
02351 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02352 }
02353 }
02354
02355 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02356 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02357 static const int8 _deltacoord_leaveoffset[8] = {
02358 -1, 0, 1, 0,
02359 0, 1, 0, -1
02360 };
02361
02362
02368 int TicksToLeaveDepot(const Train *v)
02369 {
02370 DiagDirection dir = GetRailDepotDirection(v->tile);
02371 int length = v->tcache.cached_veh_length;
02372
02373 switch (dir) {
02374 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02375 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02376 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02377 default:
02378 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02379 }
02380
02381 return 0;
02382 }
02383
02386 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02387 {
02388 byte fract_coord;
02389 byte fract_coord_leave;
02390 DiagDirection dir;
02391 int length;
02392
02393
02394 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02395
02396 Train *v = Train::From(u);
02397
02398
02399 dir = GetRailDepotDirection(tile);
02400
02401
02402
02403 length = v->tcache.cached_veh_length;
02404
02405 fract_coord_leave =
02406 ((_fractcoords_enter[dir] & 0x0F) +
02407 (length + 1) * _deltacoord_leaveoffset[dir]) +
02408 (((_fractcoords_enter[dir] >> 4) +
02409 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02410
02411 fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02412
02413 if (_fractcoords_behind[dir] == fract_coord) {
02414
02415 return VETSB_CANNOT_ENTER;
02416 } else if (_fractcoords_enter[dir] == fract_coord) {
02417 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02418
02419 v->track = TRACK_BIT_DEPOT,
02420 v->vehstatus |= VS_HIDDEN;
02421 v->direction = ReverseDir(v->direction);
02422 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02423 v->tile = tile;
02424
02425 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02426 return VETSB_ENTERED_WORMHOLE;
02427 }
02428 } else if (fract_coord_leave == fract_coord) {
02429 if (DiagDirToDir(dir) == v->direction) {
02430
02431 if ((v = v->Next()) != NULL) {
02432 v->vehstatus &= ~VS_HIDDEN;
02433 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02434 }
02435 }
02436 }
02437
02438 return VETSB_CONTINUE;
02439 }
02440
02452 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02453 {
02454 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02455
02456
02457 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CMD_ERROR;
02458
02459
02460 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02461 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02462
02463 Corner track_corner;
02464 switch (rail_bits) {
02465 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02466 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02467 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02468 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02469
02470
02471 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02472 }
02473
02474
02475 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02476 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02477 if (z_old != z_new) return CMD_ERROR;
02478
02479 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02480
02481 if (tileh_old != tileh_new) {
02482
02483 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02484 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02485 }
02486 return cost;
02487 }
02488
02489 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02490 {
02491 uint z_old;
02492 Slope tileh_old = GetTileSlope(tile, &z_old);
02493 if (IsPlainRail(tile)) {
02494 TrackBits rail_bits = GetTrackBits(tile);
02495
02496 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02497
02498 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02499
02500
02501 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02502
02503
02504 Corner allowed_corner;
02505 switch (rail_bits) {
02506 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02507 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02508 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02509 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02510 default: return autoslope_result;
02511 }
02512
02513 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02514
02515
02516 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02517
02518
02519 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02520 if (allowed_corner == corner) continue;
02521 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02522 }
02523
02524
02525 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02526
02527
02528 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02529 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02530 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02531 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02532 }
02533 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02534 }
02535
02536
02537 extern const TileTypeProcs _tile_type_rail_procs = {
02538 DrawTile_Track,
02539 GetSlopeZ_Track,
02540 ClearTile_Track,
02541 NULL,
02542 GetTileDesc_Track,
02543 GetTileTrackStatus_Track,
02544 ClickTile_Track,
02545 NULL,
02546 TileLoop_Track,
02547 ChangeTileOwner_Track,
02548 NULL,
02549 VehicleEnter_Track,
02550 GetFoundation_Track,
02551 TerraformTile_Track,
02552 };