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