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