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 (!IsPlainRailTile(tile)) return CMD_ERROR;
00325
00326 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_1001_IMPOSSIBLE_TRACK_COMBINATION);
00327
00328 if (!CheckTrackCombination(tile, trackbit, flags) ||
00329 !EnsureNoTrainOnTrack(tile, track)) {
00330 return CMD_ERROR;
00331 }
00332
00333 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00334 if (CmdFailed(ret)) return ret;
00335 cost.AddCost(ret);
00336
00337
00338
00339
00340 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00341 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00342 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00343 if (CmdFailed(ret)) return ret;
00344 cost.AddCost(ret);
00345 } else {
00346 return CMD_ERROR;
00347 }
00348 }
00349
00350 if (flags & DC_EXEC) {
00351 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00352 SetTrackBits(tile, GetTrackBits(tile) | trackbit);
00353 }
00354 break;
00355
00356 case MP_ROAD:
00357 #define M(x) (1 << (x))
00358
00359 if (!HasBit(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
00360 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00361 }
00362 #undef M
00363
00364 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00365
00366 if (IsNormalRoad(tile)) {
00367 if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
00368
00369 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERR_CROSSING_ON_ONEWAY_ROAD);
00370
00371 RoadTypes roadtypes = GetRoadTypes(tile);
00372 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00373 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00374 switch (roadtypes) {
00375 default: break;
00376 case ROADTYPES_TRAM:
00377
00378 if (flags & DC_EXEC) SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00379 roadtypes |= ROADTYPES_ROAD;
00380 break;
00381
00382 case ROADTYPES_ALL:
00383 if (road != tram) return CMD_ERROR;
00384 break;
00385 }
00386
00387 road |= tram;
00388
00389 if ((track == TRACK_X && road == ROAD_Y) ||
00390 (track == TRACK_Y && road == ROAD_X)) {
00391 if (flags & DC_EXEC) {
00392 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00393 UpdateLevelCrossing(tile, false);
00394 }
00395 break;
00396 }
00397 }
00398
00399 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00400 return_cmd_error(STR_1007_ALREADY_BUILT);
00401 }
00402
00403
00404 default:
00405
00406 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00407
00408 ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00409 if (CmdFailed(ret)) return ret;
00410 cost.AddCost(ret);
00411
00412 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00413 if (CmdFailed(ret)) return ret;
00414 cost.AddCost(ret);
00415
00416 if (water_ground) {
00417 cost.AddCost(-_price.clear_water);
00418 cost.AddCost(_price.clear_roughland);
00419 }
00420
00421 if (flags & DC_EXEC) {
00422 MakeRailNormal(tile, _current_company, trackbit, railtype);
00423 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00424 }
00425 break;
00426 }
00427
00428 if (flags & DC_EXEC) {
00429 MarkTileDirtyByTile(tile);
00430 AddTrackToSignalBuffer(tile, track, _current_company);
00431 YapfNotifyTrackLayoutChange(tile, track);
00432 }
00433
00434 return cost.AddCost(RailBuildCost(railtype));
00435 }
00436
00443 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00444 {
00445 Track track = (Track)p2;
00446 TrackBits trackbit;
00447 CommandCost cost(EXPENSES_CONSTRUCTION, _price.remove_rail );
00448 bool crossing = false;
00449
00450 if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
00451 trackbit = TrackToTrackBits(track);
00452
00453
00454
00455
00456
00457 Owner owner = INVALID_OWNER;
00458
00459 Vehicle *v = NULL;
00460
00461 switch (GetTileType(tile)) {
00462 case MP_ROAD: {
00463 if (!IsLevelCrossing(tile) ||
00464 GetCrossingRailBits(tile) != trackbit ||
00465 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00466 (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
00467 return CMD_ERROR;
00468 }
00469
00470 if (flags & DC_EXEC) {
00471 if (HasReservedTracks(tile, trackbit)) {
00472 v = GetTrainForReservation(tile, track);
00473 if (v != NULL) FreeTrainTrackReservation(v);
00474 }
00475 owner = GetTileOwner(tile);
00476 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00477 }
00478 break;
00479 }
00480
00481 case MP_RAILWAY: {
00482 TrackBits present;
00483
00484 if (!IsPlainRailTile(tile) ||
00485 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00486 !EnsureNoTrainOnTrack(tile, track)) {
00487 return CMD_ERROR;
00488 }
00489
00490 present = GetTrackBits(tile);
00491 if ((present & trackbit) == 0) return CMD_ERROR;
00492 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00493
00494
00495 if (HasSignalOnTrack(tile, track))
00496 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00497
00498 if (flags & DC_EXEC) {
00499 if (HasReservedTracks(tile, trackbit)) {
00500 v = GetTrainForReservation(tile, track);
00501 if (v != NULL) FreeTrainTrackReservation(v);
00502 }
00503 owner = GetTileOwner(tile);
00504 present ^= trackbit;
00505 if (present == 0) {
00506 Slope tileh = GetTileSlope(tile, NULL);
00507
00508 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00509 MakeShore(tile);
00510 } else {
00511 DoClearSquare(tile);
00512 }
00513 } else {
00514 SetTrackBits(tile, present);
00515 SetTrackReservation(tile, GetTrackReservation(tile) & present);
00516 }
00517 }
00518 break;
00519 }
00520
00521 default: return CMD_ERROR;
00522 }
00523
00524 if (flags & DC_EXEC) {
00525
00526 assert(IsValidCompanyID(owner));
00527
00528 MarkTileDirtyByTile(tile);
00529 if (crossing) {
00530
00531
00532
00533
00534 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00535 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00536 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00537 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00538 } else {
00539 AddTrackToSignalBuffer(tile, track, owner);
00540 YapfNotifyTrackLayoutChange(tile, track);
00541 }
00542
00543 if (v != NULL) TryPathReserve(v, true);
00544 }
00545
00546 return cost;
00547 }
00548
00549
00557 bool FloodHalftile(TileIndex t)
00558 {
00559 assert(IsPlainRailTile(t));
00560
00561 bool flooded = false;
00562 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00563
00564 Slope tileh = GetTileSlope(t, NULL);
00565 TrackBits rail_bits = GetTrackBits(t);
00566
00567 if (IsSlopeWithOneCornerRaised(tileh)) {
00568 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00569
00570 TrackBits to_remove = lower_track & rail_bits;
00571 if (to_remove != 0) {
00572 _current_company = OWNER_WATER;
00573 if (CmdFailed(DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL))) return flooded;
00574 flooded = true;
00575 rail_bits = rail_bits & ~to_remove;
00576 if (rail_bits == 0) {
00577 MakeShore(t);
00578 MarkTileDirtyByTile(t);
00579 return flooded;
00580 }
00581 }
00582
00583 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00584 flooded = true;
00585 SetRailGroundType(t, RAIL_GROUND_WATER);
00586 MarkTileDirtyByTile(t);
00587 }
00588 } else {
00589
00590 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00591 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00592 flooded = true;
00593 SetRailGroundType(t, RAIL_GROUND_WATER);
00594 MarkTileDirtyByTile(t);
00595 }
00596 }
00597 }
00598 return flooded;
00599 }
00600
00601 static const TileIndexDiffC _trackdelta[] = {
00602 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00603 { 0, 0 },
00604 { 0, 0 },
00605 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00606 { 0, 0 },
00607 { 0, 0 }
00608 };
00609
00610
00611 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00612 {
00613 int x = TileX(start);
00614 int y = TileY(start);
00615 int ex = TileX(end);
00616 int ey = TileY(end);
00617 int dx, dy, trdx, trdy;
00618
00619 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00620
00621
00622 dx = ex - x;
00623 dy = ey - y;
00624
00625
00626 trdx = _trackdelta[*trackdir].x;
00627 trdy = _trackdelta[*trackdir].y;
00628
00629 if (!IsDiagonalTrackdir(*trackdir)) {
00630 trdx += _trackdelta[*trackdir ^ 1].x;
00631 trdy += _trackdelta[*trackdir ^ 1].y;
00632 }
00633
00634
00635 while (
00636 (trdx <= 0 && dx > 0) ||
00637 (trdx >= 0 && dx < 0) ||
00638 (trdy <= 0 && dy > 0) ||
00639 (trdy >= 0 && dy < 0)
00640 ) {
00641 if (!HasBit(*trackdir, 3)) {
00642 SetBit(*trackdir, 3);
00643 trdx = -trdx;
00644 trdy = -trdy;
00645 } else {
00646 return CMD_ERROR;
00647 }
00648 }
00649
00650
00651
00652 if (!IsDiagonalTrackdir(*trackdir)) {
00653 trdx = _trackdelta[*trackdir].x;
00654 trdy = _trackdelta[*trackdir].y;
00655 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
00656 return CMD_ERROR;
00657 }
00658
00659 return CommandCost();
00660 }
00661
00671 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00672 {
00673 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00674 Track track = (Track)GB(p2, 4, 3);
00675 bool remove = HasBit(p2, 7);
00676 RailType railtype = (RailType)GB(p2, 0, 4);
00677
00678 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00679 if (p1 >= MapSize()) return CMD_ERROR;
00680 TileIndex end_tile = p1;
00681 Trackdir trackdir = TrackToTrackdir(track);
00682
00683 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
00684
00685 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00686
00687 for (;;) {
00688 ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00689
00690 if (CmdFailed(ret)) {
00691 if (_error_message != STR_1007_ALREADY_BUILT && !remove) break;
00692 _error_message = INVALID_STRING_ID;
00693 } else {
00694 total_cost.AddCost(ret);
00695 }
00696
00697 if (tile == end_tile) break;
00698
00699 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00700
00701
00702 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00703 }
00704
00705 return (total_cost.GetCost() == 0) ? CommandCost(remove ? INVALID_STRING_ID : (_error_message == INVALID_STRING_ID ? STR_1007_ALREADY_BUILT : _error_message)) : total_cost;
00706 }
00707
00719 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00720 {
00721 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00722 }
00723
00735 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00736 {
00737 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00738 }
00739
00749 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00750 {
00751 Slope tileh;
00752
00753
00754 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00755
00756 tileh = GetTileSlope(tile, NULL);
00757
00758 DiagDirection dir = Extract<DiagDirection, 0>(p2);
00759
00760
00761
00762
00763
00764
00765
00766
00767 if (tileh != SLOPE_FLAT && (
00768 !_settings_game.construction.build_on_slopes ||
00769 IsSteepSlope(tileh) ||
00770 !CanBuildDepotByTileh(dir, tileh)
00771 )) {
00772 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00773 }
00774
00775 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00776 if (CmdFailed(cost)) return CMD_ERROR;
00777
00778 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00779
00780 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00781
00782 if (flags & DC_EXEC) {
00783 Depot *d = new Depot(tile);
00784 MakeRailDepot(tile, _current_company, dir, (RailType)p1);
00785 MarkTileDirtyByTile(tile);
00786
00787 d->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00788
00789 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00790 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00791 }
00792
00793 return cost.AddCost(_price.build_train_depot);
00794 }
00795
00814 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00815 {
00816 Track track = (Track)GB(p1, 0, 3);
00817 bool ctrl_pressed = HasBit(p1, 3);
00818 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00819 SignalType sigtype = (SignalType)GB(p1, 5, 3);
00820 bool convert_signal = HasBit(p1, 8);
00821 SignalType cycle_start = (SignalType)GB(p1, 9, 3);
00822 SignalType cycle_stop = (SignalType)GB(p1, 12, 3);
00823 CommandCost cost;
00824 uint num_dir_cycle = GB(p1, 15, 2);
00825
00826 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00827
00828 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoTrainOnTrack(tile, track))
00829 return CMD_ERROR;
00830
00831
00832 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00833
00834
00835 if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) return CMD_ERROR;
00836
00837 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00838
00839 {
00840
00841 TrackBits trackbits = GetTrackBits(tile);
00842 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00843 trackbits != TRACK_BIT_HORZ &&
00844 trackbits != TRACK_BIT_VERT) {
00845 return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
00846 }
00847 }
00848
00849
00850 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00851
00852
00853 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00854
00855 if (!HasSignalOnTrack(tile, track)) {
00856
00857 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals);
00858 } else {
00859 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00860
00861 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
00862
00863 } else if (convert_signal) {
00864
00865 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00866
00867 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
00868 } else {
00869
00870 cost = CommandCost();
00871 }
00872
00873 } else {
00874
00875 cost = CommandCost();
00876 }
00877 }
00878
00879 if (flags & DC_EXEC) {
00880 Vehicle *v = NULL;
00881
00882
00883
00884 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
00885 v = GetTrainForReservation(tile, track);
00886 if (v != NULL) FreeTrainTrackReservation(v);
00887 }
00888
00889 if (!HasSignals(tile)) {
00890
00891 SetHasSignals(tile, true);
00892 SetSignalStates(tile, 0xF);
00893 SetPresentSignals(tile, 0);
00894 SetSignalType(tile, track, sigtype);
00895 SetSignalVariant(tile, track, sigvar);
00896 }
00897
00898 if (p2 == 0) {
00899 if (!HasSignalOnTrack(tile, track)) {
00900
00901 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
00902 SetSignalType(tile, track, sigtype);
00903 SetSignalVariant(tile, track, sigvar);
00904 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
00905 } else {
00906 if (convert_signal) {
00907
00908 if (ctrl_pressed) {
00909
00910 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00911
00912 sigtype = GetSignalType(tile, track);
00913 } else {
00914
00915 SetSignalType(tile, track, sigtype);
00916 SetSignalVariant(tile, track, sigvar);
00917 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
00918 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
00919 }
00920 }
00921
00922 } else if (ctrl_pressed) {
00923
00924 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
00925
00926 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
00927
00928 SetSignalType(tile, track, sigtype);
00929 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
00930 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
00931 }
00932 } else {
00933
00934 CycleSignalSide(tile, track);
00935
00936 sigtype = GetSignalType(tile, track);
00937 }
00938 }
00939 } else {
00940
00941
00942 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
00943 SetSignalVariant(tile, track, sigvar);
00944 SetSignalType(tile, track, sigtype);
00945 }
00946
00947 if (IsPbsSignal(sigtype)) {
00948
00949 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
00950 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetTrackReservation(tile), track) ? UINT_MAX : 0) & mask));
00951 }
00952 MarkTileDirtyByTile(tile);
00953 AddTrackToSignalBuffer(tile, track, _current_company);
00954 YapfNotifyTrackLayoutChange(tile, track);
00955 if (v != NULL) TryPathReserve(v, true);
00956 }
00957
00958 return cost;
00959 }
00960
00961 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
00962 {
00963 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
00964 if (tile == INVALID_TILE) return false;
00965
00966
00967 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00968
00969 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
00970 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
00971
00972
00973 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
00974
00975
00976 trackdir = RemoveFirstTrackdir(&trackdirbits);
00977
00978
00979 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
00980
00981 switch (GetTileType(tile)) {
00982 case MP_RAILWAY:
00983 if (IsRailDepot(tile)) return false;
00984 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
00985 signal_ctr++;
00986 if (IsDiagonalTrackdir(trackdir)) {
00987 signal_ctr++;
00988
00989 ClrBit(signal_ctr, 0);
00990 }
00991 return true;
00992
00993 case MP_ROAD:
00994 if (!IsLevelCrossing(tile)) return false;
00995 signal_ctr += 2;
00996 return true;
00997
00998 case MP_TUNNELBRIDGE: {
00999 TileIndex orig_tile = tile;
01000
01001 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01002 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01003
01004
01005
01006 tile = GetOtherTunnelBridgeEnd(tile);
01007
01008 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01009 return true;
01010 }
01011
01012 default: return false;
01013 }
01014 }
01015
01029 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01030 {
01031 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01032 int signal_ctr;
01033 byte signals;
01034 bool error = true;
01035 TileIndex end_tile;
01036 TileIndex start_tile = tile;
01037
01038 Track track = (Track)GB(p2, 0, 3);
01039 bool mode = HasBit(p2, 3);
01040 bool semaphores = HasBit(p2, 4);
01041 bool remove = HasBit(p2, 5);
01042 bool autofill = HasBit(p2, 6);
01043 Trackdir trackdir = TrackToTrackdir(track);
01044 byte signal_density = GB(p2, 24, 8);
01045
01046 if (p1 >= MapSize()) return CMD_ERROR;
01047 end_tile = p1;
01048 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01049
01050 if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) return CMD_ERROR;
01051
01052
01053
01054 signal_density *= 2;
01055
01056 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
01057
01058 track = TrackdirToTrack(trackdir);
01059 Trackdir start_trackdir = trackdir;
01060
01061
01062 if (!HasTrack(tile, track)) return CMD_ERROR;
01063
01064 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01065 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01066
01067
01068 if (HasSignalOnTrack(tile, track)) {
01069 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01070 assert(signals != 0);
01071
01072
01073 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01074
01075 sigtype = GetSignalType(tile, track);
01076
01077 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01078 } else {
01079 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01080 }
01081
01082 byte signal_dir = 0;
01083 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01084 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 signal_ctr = 0;
01095 for (;;) {
01096
01097 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01098 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01099 SB(p1, 3, 1, mode);
01100 SB(p1, 4, 1, semaphores);
01101 SB(p1, 5, 3, sigtype);
01102 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01103
01104
01105 signals = 0;
01106 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01107 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01108
01109 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01110
01111
01112 if (CmdSucceeded(ret)) {
01113 error = false;
01114 total_cost.AddCost(ret);
01115 }
01116 }
01117
01118 if (autofill) {
01119 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01120
01121
01122 if (tile == start_tile && trackdir == start_trackdir) break;
01123 } else {
01124 if (tile == end_tile) break;
01125
01126 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01127 signal_ctr++;
01128
01129
01130 if (IsDiagonalTrackdir(trackdir)) {
01131 signal_ctr++;
01132 } else {
01133 ToggleBit(trackdir, 0);
01134 }
01135 }
01136 }
01137
01138 return error ? CMD_ERROR : total_cost;
01139 }
01140
01156 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01157 {
01158 return CmdSignalTrackHelper(tile, flags, p1, p2,text);
01159 }
01160
01170 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01171 {
01172 Track track = (Track)GB(p1, 0, 3);
01173
01174 if (!ValParamTrackOrientation(track) ||
01175 !IsTileType(tile, MP_RAILWAY) ||
01176 !IsPlainRailTile(tile) ||
01177 !HasTrack(tile, track) ||
01178 !EnsureNoTrainOnTrack(tile, track) ||
01179 !HasSignalOnTrack(tile, track)) {
01180 return CMD_ERROR;
01181 }
01182
01183
01184 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01185
01186
01187 if (flags & DC_EXEC) {
01188 Vehicle *v = NULL;
01189 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01190 v = GetTrainForReservation(tile, track);
01191 }
01192 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01193
01194
01195 if (GetPresentSignals(tile) == 0) {
01196 SetSignalStates(tile, 0);
01197 SetHasSignals(tile, false);
01198 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01199 }
01200
01201 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01202 YapfNotifyTrackLayoutChange(tile, track);
01203 if (v != NULL) TryPathReserve(v, false);
01204
01205 MarkTileDirtyByTile(tile);
01206 }
01207
01208 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_signals);
01209 }
01210
01226 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01227 {
01228 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01229 }
01230
01232 Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01233 {
01234
01235
01236 if (v->type == VEH_TRAIN && !IsArticulatedPart(v)) {
01237 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
01238 if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First());
01239 }
01240
01241 return NULL;
01242 }
01243
01251 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01252 {
01253 CommandCost cost(EXPENSES_CONSTRUCTION);
01254 RailType totype = (RailType)p2;
01255
01256 if (!ValParamRailtype(totype)) return CMD_ERROR;
01257 if (p1 >= MapSize()) return CMD_ERROR;
01258
01259 uint ex = TileX(tile);
01260 uint ey = TileY(tile);
01261 uint sx = TileX(p1);
01262 uint sy = TileY(p1);
01263
01264
01265 if (ex < sx) Swap(ex, sx);
01266 if (ey < sy) Swap(ey, sy);
01267
01268 _error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
01269
01270 for (uint x = sx; x <= ex; ++x) {
01271 for (uint y = sy; y <= ey; ++y) {
01272 TileIndex tile = TileXY(x, y);
01273 TileType tt = GetTileType(tile);
01274
01275
01276 switch (tt) {
01277 case MP_RAILWAY:
01278 break;
01279 case MP_STATION:
01280 if (!IsRailwayStation(tile)) continue;
01281 break;
01282 case MP_ROAD:
01283 if (!IsLevelCrossing(tile)) continue;
01284 break;
01285 case MP_TUNNELBRIDGE:
01286 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01287 break;
01288 default: continue;
01289 }
01290
01291
01292 RailType type = GetRailType(tile);
01293
01294
01295 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01296
01297
01298 if (!CheckTileOwnership(tile)) continue;
01299
01300 SmallVector<Vehicle*, 2> vehicles_affected;
01301
01302
01303
01304 if (tt != MP_TUNNELBRIDGE) {
01305 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01306 if (flags & DC_EXEC) {
01307 TrackBits reserved = GetReservedTrackbits(tile);
01308 Track track;
01309 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01310 Vehicle *v = GetTrainForReservation(tile, track);
01311 if (v != NULL && !HasPowerOnRail(v->u.rail.railtype, totype)) {
01312
01313 FreeTrainTrackReservation(v);
01314 *vehicles_affected.Append() = v;
01315 }
01316 }
01317
01318 SetRailType(tile, totype);
01319 MarkTileDirtyByTile(tile);
01320
01321 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01322 }
01323 }
01324
01325 switch (tt) {
01326 case MP_RAILWAY:
01327 switch (GetRailTileType(tile)) {
01328 case RAIL_TILE_WAYPOINT:
01329 if (flags & DC_EXEC) {
01330
01331 YapfNotifyTrackLayoutChange(tile, GetRailWaypointTrack(tile));
01332 }
01333 cost.AddCost(RailConvertCost(type, totype));
01334 break;
01335
01336 case RAIL_TILE_DEPOT:
01337 if (flags & DC_EXEC) {
01338
01339 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01340
01341
01342 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01343 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01344 }
01345 cost.AddCost(RailConvertCost(type, totype));
01346 break;
01347
01348 default:
01349 if (flags & DC_EXEC) {
01350
01351 TrackBits tracks = GetTrackBits(tile);
01352 while (tracks != TRACK_BIT_NONE) {
01353 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01354 }
01355 }
01356 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01357 break;
01358 }
01359 break;
01360
01361 case MP_TUNNELBRIDGE: {
01362 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01363
01364
01365
01366 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01367 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01368
01369
01370 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01371 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01372
01373 if (flags & DC_EXEC) {
01374 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01375 if (GetTunnelBridgeReservation(tile)) {
01376 Vehicle *v = GetTrainForReservation(tile, track);
01377 if (v != NULL && !HasPowerOnRail(v->u.rail.railtype, totype)) {
01378
01379 FreeTrainTrackReservation(v);
01380 *vehicles_affected.Append() = v;
01381 }
01382 }
01383 SetRailType(tile, totype);
01384 SetRailType(endtile, totype);
01385
01386 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01387 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01388
01389 YapfNotifyTrackLayoutChange(tile, track);
01390 YapfNotifyTrackLayoutChange(endtile, track);
01391
01392 MarkTileDirtyByTile(tile);
01393 MarkTileDirtyByTile(endtile);
01394
01395 if (IsBridge(tile)) {
01396 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01397 TileIndex t = tile + delta;
01398 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01399 }
01400 }
01401
01402 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01403 } break;
01404
01405 default:
01406 if (flags & DC_EXEC) {
01407 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01408 YapfNotifyTrackLayoutChange(tile, track);
01409 }
01410
01411 cost.AddCost(RailConvertCost(type, totype));
01412 break;
01413 }
01414
01415 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01416 TryPathReserve(vehicles_affected[i], true);
01417 }
01418 }
01419 }
01420
01421 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01422 }
01423
01424 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01425 {
01426 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01427 return CMD_ERROR;
01428
01429 if (!EnsureNoVehicleOnGround(tile))
01430 return CMD_ERROR;
01431
01432 if (flags & DC_EXEC) {
01433
01434 DiagDirection dir = GetRailDepotDirection(tile);
01435 Owner owner = GetTileOwner(tile);
01436 Vehicle *v = NULL;
01437
01438 if (GetDepotWaypointReservation(tile)) {
01439 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01440 if (v != NULL) FreeTrainTrackReservation(v);
01441 }
01442
01443 DoClearSquare(tile);
01444 delete GetDepotByTile(tile);
01445 AddSideToSignalBuffer(tile, dir, owner);
01446 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01447 if (v != NULL) TryPathReserve(v, true);
01448 }
01449
01450 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
01451 }
01452
01453 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01454 {
01455 CommandCost cost(EXPENSES_CONSTRUCTION);
01456 CommandCost ret;
01457
01458 if (flags & DC_AUTO) {
01459 if (!IsTileOwner(tile, _current_company))
01460 return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
01461
01462 if (IsPlainRailTile(tile)) {
01463 return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
01464 } else {
01465 return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
01466 }
01467 }
01468
01469 switch (GetRailTileType(tile)) {
01470 case RAIL_TILE_SIGNALS:
01471 case RAIL_TILE_NORMAL: {
01472 Slope tileh = GetTileSlope(tile, NULL);
01473
01474 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01475
01476 TrackBits tracks = GetTrackBits(tile);
01477 while (tracks != TRACK_BIT_NONE) {
01478 Track track = RemoveFirstTrack(&tracks);
01479 ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01480 if (CmdFailed(ret)) return CMD_ERROR;
01481 cost.AddCost(ret);
01482 }
01483
01484
01485 if (water_ground && !(flags & DC_BANKRUPT)) {
01486 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01487
01488
01489 if (flags & DC_EXEC) DoClearSquare(tile);
01490 cost.AddCost(_price.clear_water);
01491 }
01492
01493 return cost;
01494 }
01495
01496 case RAIL_TILE_DEPOT:
01497 return RemoveTrainDepot(tile, flags);
01498
01499 case RAIL_TILE_WAYPOINT:
01500 return RemoveTrainWaypoint(tile, flags, false);
01501
01502 default:
01503 return CMD_ERROR;
01504 }
01505 }
01506
01511 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01512 {
01513 switch (track) {
01514 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01515 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01516 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01517 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01518 default: break;
01519 }
01520 return GetSlopeZ(x, y);
01521 }
01522
01523 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01524 {
01525 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01526 static const Point SignalPositions[2][12] = {
01527 {
01528
01529 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01530
01531 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01532 }, {
01533
01534 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01535
01536 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01537 }
01538 };
01539
01540 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01541 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01542
01543 SpriteID sprite;
01544
01545 SignalType type = GetSignalType(tile, track);
01546 SignalVariant variant = GetSignalVariant(tile, track);
01547
01548 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01549
01550 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01551 } else {
01552
01553 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01554 }
01555
01556 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01557 }
01558
01559 static uint32 _drawtile_track_palette;
01560
01561
01562 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01563 {
01564 RailFenceOffset rfo = RFO_FLAT_X;
01565 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01566 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01567 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01568 }
01569
01570 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01571 {
01572 RailFenceOffset rfo = RFO_FLAT_X;
01573 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01574 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01575 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01576 }
01577
01578 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01579 {
01580 DrawTrackFence_NW(ti, base_image);
01581 DrawTrackFence_SE(ti, base_image);
01582 }
01583
01584 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01585 {
01586 RailFenceOffset rfo = RFO_FLAT_Y;
01587 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01588 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01589 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01590 }
01591
01592 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01593 {
01594 RailFenceOffset rfo = RFO_FLAT_Y;
01595 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01596 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01597 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01598 }
01599
01600 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01601 {
01602 DrawTrackFence_NE(ti, base_image);
01603 DrawTrackFence_SW(ti, base_image);
01604 }
01605
01609 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01610 {
01611 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01612 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01613 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01614 }
01615
01619 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01620 {
01621 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01622 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01623 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01624 }
01625
01629 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01630 {
01631 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01632 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01633 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01634 }
01635
01639 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01640 {
01641 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01642 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01643 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01644 }
01645
01646
01647 static void DrawTrackDetails(const TileInfo *ti)
01648 {
01649
01650 SpriteID base_image = SPR_TRACK_FENCE_FLAT_X;
01651
01652 switch (GetRailGroundType(ti->tile)) {
01653 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01654 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01655 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01656 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01657 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01658 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01659 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01660 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01661 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01662 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01663 case RAIL_GROUND_WATER: {
01664 Corner track_corner;
01665 if (IsHalftileSlope(ti->tileh)) {
01666
01667 track_corner = GetHalftileSlopeCorner(ti->tileh);
01668 } else {
01669
01670 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01671 }
01672 switch (track_corner) {
01673 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01674 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01675 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01676 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01677 default: NOT_REACHED();
01678 }
01679 break;
01680 }
01681 default: break;
01682 }
01683 }
01684
01685
01691 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01692 {
01693
01694 static const int INF = 1000;
01695 static const SubSprite _halftile_sub_sprite[4] = {
01696 { -INF , -INF , 32 - 33, INF },
01697 { -INF , 0 + 7, INF , INF },
01698 { -31 + 33, -INF , INF , INF },
01699 { -INF , -INF , INF , 30 - 23 }
01700 };
01701
01702 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01703 RailGroundType rgt = GetRailGroundType(ti->tile);
01704 Foundation f = GetRailFoundation(ti->tileh, track);
01705 Corner halftile_corner = CORNER_INVALID;
01706
01707 if (IsNonContinuousFoundation(f)) {
01708
01709 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01710
01711 track &= ~CornerToTrackBits(halftile_corner);
01712 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01713 }
01714
01715 DrawFoundation(ti, f);
01716
01717
01718 SpriteID image;
01719 SpriteID pal = PAL_NONE;
01720 const SubSprite *sub = NULL;
01721 bool junction = false;
01722
01723
01724 if (track == 0) {
01725
01726 if (rgt == RAIL_GROUND_WATER) {
01727 if (IsSteepSlope(ti->tileh)) {
01728 DrawShoreTile(ti->tileh);
01729 image = 0;
01730 } else {
01731 image = SPR_FLAT_WATER_TILE;
01732 }
01733 } else {
01734 switch (rgt) {
01735 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01736 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOWY_TILE; break;
01737 default: image = SPR_FLAT_GRASS_TILE; break;
01738 }
01739 image += _tileh_to_sprite[ti->tileh];
01740 }
01741 } else {
01742 if (ti->tileh != SLOPE_FLAT) {
01743
01744 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01745 } else {
01746
01747 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
01748 (image++, track == TRACK_BIT_X) ||
01749 (image++, track == TRACK_BIT_UPPER) ||
01750 (image++, track == TRACK_BIT_LOWER) ||
01751 (image++, track == TRACK_BIT_RIGHT) ||
01752 (image++, track == TRACK_BIT_LEFT) ||
01753 (image++, track == TRACK_BIT_CROSS) ||
01754
01755 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
01756 (image++, track == TRACK_BIT_VERT) ||
01757
01758 (junction = true, false) ||
01759 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
01760 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
01761 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
01762 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
01763 (image++, true);
01764 }
01765
01766 switch (rgt) {
01767 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01768 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
01769 case RAIL_GROUND_WATER: {
01770
01771 DrawShoreTile(ti->tileh);
01772 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01773 sub = &(_halftile_sub_sprite[track_corner]);
01774 break;
01775 }
01776 default: break;
01777 }
01778 }
01779
01780 if (image != 0) DrawGroundSprite(image, pal, sub);
01781
01782
01783 if (junction) {
01784 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
01785 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
01786 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
01787 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
01788 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
01789 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
01790 }
01791
01792
01793 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
01794
01795 TrackBits pbs = GetTrackReservation(ti->tile) & track;
01796 if (pbs & TRACK_BIT_X) {
01797 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01798 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
01799 } else {
01800 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01801 }
01802 }
01803 if (pbs & TRACK_BIT_Y) {
01804 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01805 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
01806 } else {
01807 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01808 }
01809 }
01810 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
01811 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
01812 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
01813 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
01814 }
01815
01816 if (IsValidCorner(halftile_corner)) {
01817 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01818
01819
01820 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01821 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
01822 pal = PAL_NONE;
01823 switch (rgt) {
01824 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01825 case RAIL_GROUND_ICE_DESERT:
01826 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
01827 default: break;
01828 }
01829 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
01830
01831 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
01832 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
01833 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
01834 }
01835 }
01836 }
01837
01843 enum {
01844 SIGNAL_TO_SOUTHWEST = 0,
01845 SIGNAL_TO_NORTHEAST = 2,
01846 SIGNAL_TO_SOUTHEAST = 4,
01847 SIGNAL_TO_NORTHWEST = 6,
01848 SIGNAL_TO_EAST = 8,
01849 SIGNAL_TO_WEST = 10,
01850 SIGNAL_TO_SOUTH = 12,
01851 SIGNAL_TO_NORTH = 14,
01852 };
01853
01854 static void DrawSignals(TileIndex tile, TrackBits rails)
01855 {
01856 #define MAYBE_DRAW_SIGNAL(x,y,z,t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
01857
01858 if (!(rails & TRACK_BIT_Y)) {
01859 if (!(rails & TRACK_BIT_X)) {
01860 if (rails & TRACK_BIT_LEFT) {
01861 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
01862 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
01863 }
01864 if (rails & TRACK_BIT_RIGHT) {
01865 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
01866 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
01867 }
01868 if (rails & TRACK_BIT_UPPER) {
01869 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
01870 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
01871 }
01872 if (rails & TRACK_BIT_LOWER) {
01873 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
01874 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
01875 }
01876 } else {
01877 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
01878 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
01879 }
01880 } else {
01881 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
01882 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
01883 }
01884 }
01885
01886 static void DrawTile_Track(TileInfo *ti)
01887 {
01888 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01889 SpriteID image;
01890
01891 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
01892
01893 if (IsPlainRailTile(ti->tile)) {
01894 TrackBits rails = GetTrackBits(ti->tile);
01895
01896 DrawTrackBits(ti, rails);
01897
01898 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti);
01899
01900 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01901
01902 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
01903 } else {
01904
01905 const DrawTileSprites *dts;
01906 const DrawTileSeqStruct *dtss;
01907 uint32 relocation;
01908 SpriteID pal = PAL_NONE;
01909
01910 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01911
01912 if (IsRailDepot(ti->tile)) {
01913 if (IsInvisibilitySet(TO_BUILDINGS)) {
01914
01915 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
01916 } else {
01917 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01918 }
01919
01920 relocation = rti->total_offset;
01921
01922 image = dts->ground.sprite;
01923 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01924
01925
01926
01927 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
01928 if (image != SPR_FLAT_GRASS_TILE) {
01929 image += rti->snow_offset;
01930 } else {
01931 image = SPR_FLAT_SNOWY_TILE;
01932 }
01933 }
01934 } else {
01935
01936 byte stat_id = GetWaypointByTile(ti->tile)->stat_id;
01937 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id);
01938
01939 if (statspec != NULL) {
01940
01941 const Station *st = ComposeWaypointStation(ti->tile);
01942 uint gfx = 2;
01943
01944 if (HasBit(statspec->callbackmask, CBM_STATION_SPRITE_LAYOUT)) {
01945 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
01946 if (callback != CALLBACK_FAILED) gfx = callback;
01947 }
01948
01949 if (statspec->renderdata == NULL) {
01950 dts = GetStationTileLayout(STATION_RAIL, gfx);
01951 } else {
01952 dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
01953 }
01954
01955 if (dts != NULL && dts->seq != NULL) {
01956 relocation = GetCustomStationRelocation(statspec, st, ti->tile);
01957
01958 image = dts->ground.sprite;
01959 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01960 image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
01961 image += rti->custom_ground_offset;
01962 } else {
01963 image += rti->total_offset;
01964 }
01965
01966 pal = dts->ground.pal;
01967 } else {
01968 goto default_waypoint;
01969 }
01970 } else {
01971 default_waypoint:
01972
01973 dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)];
01974 relocation = 0;
01975 image = dts->ground.sprite + rti->total_offset;
01976 if (IsSnowRailGround(ti->tile)) image += rti->snow_offset;
01977 }
01978 }
01979
01980 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
01981
01982
01983 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && GetDepotWaypointReservation(ti->tile) &&
01984 (!IsRailDepot(ti->tile) || GetRailDepotDirection(ti->tile) == DIAGDIR_SW || GetRailDepotDirection(ti->tile) == DIAGDIR_SE)) {
01985 DrawGroundSprite(GetWaypointAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH);
01986 }
01987
01988 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01989
01990 foreach_draw_tile_seq(dtss, dts->seq) {
01991 SpriteID image = dtss->image.sprite;
01992 SpriteID pal = dtss->image.pal;
01993
01994
01995 if (IsInvisibilitySet(TO_BUILDINGS) && !HasBit(image, SPRITE_MODIFIER_OPAQUE)) return;
01996
01997
01998
01999
02000 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
02001 image += rti->total_offset;
02002 } else {
02003 image += relocation;
02004 }
02005
02006 pal = SpriteLayoutPaletteTransform(image, pal, _drawtile_track_palette);
02007
02008 if ((byte)dtss->delta_z != 0x80) {
02009 AddSortableSpriteToDraw(
02010 image, pal,
02011 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
02012 dtss->size_x, dtss->size_y,
02013 dtss->size_z, ti->z + dtss->delta_z,
02014 !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
02015 );
02016 } else {
02017
02018 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS));
02019 }
02020 }
02021 }
02022 DrawBridgeMiddle(ti);
02023 }
02024
02025
02026 static void DrawTileSequence(int x, int y, SpriteID ground, const DrawTileSeqStruct *dtss, uint32 offset)
02027 {
02028 SpriteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02029
02030 DrawSprite(ground, PAL_NONE, x, y);
02031 for (; dtss->image.sprite != 0; dtss++) {
02032 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
02033 SpriteID image = dtss->image.sprite + offset;
02034
02035 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOUR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
02036 }
02037 }
02038
02039 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02040 {
02041 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02042 SpriteID image = dts->ground.sprite;
02043 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02044
02045 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02046 DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
02047 }
02048
02049 void DrawDefaultWaypointSprite(int x, int y, RailType railtype)
02050 {
02051 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02052 const DrawTileSprites *dts = &_waypoint_gfx_table[AXIS_X];
02053
02054 DrawTileSequence(x, y, dts->ground.sprite + offset, dts->seq, 0);
02055 }
02056
02057 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02058 {
02059 uint z;
02060 Slope tileh = GetTileSlope(tile, &z);
02061
02062 if (tileh == SLOPE_FLAT) return z;
02063 if (IsPlainRailTile(tile)) {
02064 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02065 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02066 } else {
02067 return z + TILE_HEIGHT;
02068 }
02069 }
02070
02071 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02072 {
02073 return IsPlainRailTile(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02074 }
02075
02076 static void GetAcceptedCargo_Track(TileIndex tile, AcceptedCargo ac)
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 = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
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 = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
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 = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
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 = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
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 NULL,
02620 TileLoop_Track,
02621 ChangeTileOwner_Track,
02622 NULL,
02623 VehicleEnter_Track,
02624 GetFoundation_Track,
02625 TerraformTile_Track,
02626 };