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