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