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 TrackBits pbs = GetTrackReservation(ti->tile);
01795 if (pbs & TRACK_BIT_X) {
01796 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01797 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
01798 } else {
01799 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01800 }
01801 }
01802 if (pbs & TRACK_BIT_Y) {
01803 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
01804 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
01805 } else {
01806 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
01807 }
01808 }
01809 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));
01810 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));
01811 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));
01812 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));
01813 }
01814
01815 if (IsValidCorner(halftile_corner)) {
01816 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01817
01818
01819 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01820 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
01821 pal = PAL_NONE;
01822 switch (rgt) {
01823 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01824 case RAIL_GROUND_ICE_DESERT:
01825 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
01826 default: break;
01827 }
01828 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
01829
01830 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && IsSteepSlope(ti->tileh) && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
01831 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
01832 AddSortableSpriteToDraw(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 16);
01833 }
01834 }
01835 }
01836
01842 enum {
01843 SIGNAL_TO_SOUTHWEST = 0,
01844 SIGNAL_TO_NORTHEAST = 2,
01845 SIGNAL_TO_SOUTHEAST = 4,
01846 SIGNAL_TO_NORTHWEST = 6,
01847 SIGNAL_TO_EAST = 8,
01848 SIGNAL_TO_WEST = 10,
01849 SIGNAL_TO_SOUTH = 12,
01850 SIGNAL_TO_NORTH = 14,
01851 };
01852
01853 static void DrawSignals(TileIndex tile, TrackBits rails)
01854 {
01855 #define MAYBE_DRAW_SIGNAL(x,y,z,t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
01856
01857 if (!(rails & TRACK_BIT_Y)) {
01858 if (!(rails & TRACK_BIT_X)) {
01859 if (rails & TRACK_BIT_LEFT) {
01860 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
01861 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
01862 }
01863 if (rails & TRACK_BIT_RIGHT) {
01864 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
01865 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
01866 }
01867 if (rails & TRACK_BIT_UPPER) {
01868 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
01869 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
01870 }
01871 if (rails & TRACK_BIT_LOWER) {
01872 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
01873 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
01874 }
01875 } else {
01876 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
01877 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
01878 }
01879 } else {
01880 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
01881 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
01882 }
01883 }
01884
01885 static void DrawTile_Track(TileInfo *ti)
01886 {
01887 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01888 SpriteID image;
01889
01890 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
01891
01892 if (IsPlainRailTile(ti->tile)) {
01893 TrackBits rails = GetTrackBits(ti->tile);
01894
01895 DrawTrackBits(ti, rails);
01896
01897 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti);
01898
01899 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01900
01901 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
01902 } else {
01903
01904 const DrawTileSprites *dts;
01905 const DrawTileSeqStruct *dtss;
01906 uint32 relocation;
01907 SpriteID pal = PAL_NONE;
01908
01909 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01910
01911 if (IsRailDepot(ti->tile)) {
01912 if (IsInvisibilitySet(TO_BUILDINGS)) {
01913
01914 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
01915 } else {
01916 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01917 }
01918
01919 relocation = rti->total_offset;
01920
01921 image = dts->ground.sprite;
01922 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01923
01924
01925
01926 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
01927 if (image != SPR_FLAT_GRASS_TILE) {
01928 image += rti->snow_offset;
01929 } else {
01930 image = SPR_FLAT_SNOWY_TILE;
01931 }
01932 }
01933 } else {
01934
01935 byte stat_id = GetWaypointByTile(ti->tile)->stat_id;
01936 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id);
01937
01938 if (statspec != NULL) {
01939
01940 const Station *st = ComposeWaypointStation(ti->tile);
01941 uint gfx = 2;
01942
01943 if (HasBit(statspec->callbackmask, CBM_STATION_SPRITE_LAYOUT)) {
01944 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
01945 if (callback != CALLBACK_FAILED) gfx = callback;
01946 }
01947
01948 if (statspec->renderdata == NULL) {
01949 dts = GetStationTileLayout(STATION_RAIL, gfx);
01950 } else {
01951 dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
01952 }
01953
01954 if (dts != NULL && dts->seq != NULL) {
01955 relocation = GetCustomStationRelocation(statspec, st, ti->tile);
01956
01957 image = dts->ground.sprite;
01958 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01959 image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
01960 image += rti->custom_ground_offset;
01961 } else {
01962 image += rti->total_offset;
01963 }
01964
01965 pal = dts->ground.pal;
01966 } else {
01967 goto default_waypoint;
01968 }
01969 } else {
01970 default_waypoint:
01971
01972 dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)];
01973 relocation = 0;
01974 image = dts->ground.sprite + rti->total_offset;
01975 if (IsSnowRailGround(ti->tile)) image += rti->snow_offset;
01976 }
01977 }
01978
01979 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
01980
01981
01982 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && GetDepotWaypointReservation(ti->tile) &&
01983 (!IsRailDepot(ti->tile) || GetRailDepotDirection(ti->tile) == DIAGDIR_SW || GetRailDepotDirection(ti->tile) == DIAGDIR_SE)) {
01984 DrawGroundSprite(GetWaypointAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH);
01985 }
01986
01987 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
01988
01989 foreach_draw_tile_seq(dtss, dts->seq) {
01990 SpriteID image = dtss->image.sprite;
01991 SpriteID pal = dtss->image.pal;
01992
01993
01994 if (IsInvisibilitySet(TO_BUILDINGS) && !HasBit(image, SPRITE_MODIFIER_OPAQUE)) return;
01995
01996
01997
01998
01999 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
02000 image += rti->total_offset;
02001 } else {
02002 image += relocation;
02003 }
02004
02005 pal = SpriteLayoutPaletteTransform(image, pal, _drawtile_track_palette);
02006
02007 if ((byte)dtss->delta_z != 0x80) {
02008 AddSortableSpriteToDraw(
02009 image, pal,
02010 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
02011 dtss->size_x, dtss->size_y,
02012 dtss->size_z, ti->z + dtss->delta_z,
02013 !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
02014 );
02015 } else {
02016
02017 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS));
02018 }
02019 }
02020 }
02021 DrawBridgeMiddle(ti);
02022 }
02023
02024
02025 static void DrawTileSequence(int x, int y, SpriteID ground, const DrawTileSeqStruct *dtss, uint32 offset)
02026 {
02027 SpriteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02028
02029 DrawSprite(ground, PAL_NONE, x, y);
02030 for (; dtss->image.sprite != 0; dtss++) {
02031 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
02032 SpriteID image = dtss->image.sprite + offset;
02033
02034 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOUR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
02035 }
02036 }
02037
02038 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02039 {
02040 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02041 SpriteID image = dts->ground.sprite;
02042 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02043
02044 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02045 DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
02046 }
02047
02048 void DrawDefaultWaypointSprite(int x, int y, RailType railtype)
02049 {
02050 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
02051 const DrawTileSprites *dts = &_waypoint_gfx_table[AXIS_X];
02052
02053 DrawTileSequence(x, y, dts->ground.sprite + offset, dts->seq, 0);
02054 }
02055
02056 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02057 {
02058 uint z;
02059 Slope tileh = GetTileSlope(tile, &z);
02060
02061 if (tileh == SLOPE_FLAT) return z;
02062 if (IsPlainRailTile(tile)) {
02063 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02064 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02065 } else {
02066 return z + TILE_HEIGHT;
02067 }
02068 }
02069
02070 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02071 {
02072 return IsPlainRailTile(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02073 }
02074
02075 static void GetAcceptedCargo_Track(TileIndex tile, AcceptedCargo ac)
02076 {
02077
02078 }
02079
02080 static void AnimateTile_Track(TileIndex tile)
02081 {
02082
02083 }
02084
02085 static void TileLoop_Track(TileIndex tile)
02086 {
02087 RailGroundType old_ground = GetRailGroundType(tile);
02088 RailGroundType new_ground;
02089
02090 if (old_ground == RAIL_GROUND_WATER) {
02091 TileLoop_Water(tile);
02092 return;
02093 }
02094
02095 switch (_settings_game.game_creation.landscape) {
02096 case LT_ARCTIC: {
02097 uint z;
02098 Slope slope = GetTileSlope(tile, &z);
02099 bool half = false;
02100
02101
02102
02103 if (IsPlainRailTile(tile)) {
02104 TrackBits track = GetTrackBits(tile);
02105 Foundation f = GetRailFoundation(slope, track);
02106
02107 switch (f) {
02108 case FOUNDATION_NONE:
02109
02110 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02111 break;
02112
02113 case FOUNDATION_INCLINED_X:
02114 case FOUNDATION_INCLINED_Y:
02115
02116 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02117 break;
02118
02119 case FOUNDATION_STEEP_LOWER:
02120
02121 z += TILE_HEIGHT;
02122 break;
02123
02124 default:
02125
02126 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02127 z += TILE_HEIGHT;
02128 break;
02129 }
02130
02131 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02132 } else {
02133
02134 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02135 }
02136
02137
02138
02139
02140
02141 if (z > GetSnowLine()) {
02142 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02143
02144 new_ground = RAIL_GROUND_HALF_SNOW;
02145 } else {
02146 new_ground = RAIL_GROUND_ICE_DESERT;
02147 }
02148 goto set_ground;
02149 }
02150 break;
02151 }
02152
02153 case LT_TROPIC:
02154 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02155 new_ground = RAIL_GROUND_ICE_DESERT;
02156 goto set_ground;
02157 }
02158 break;
02159 }
02160
02161 if (!IsPlainRailTile(tile)) return;
02162
02163 new_ground = RAIL_GROUND_GRASS;
02164
02165 if (old_ground != RAIL_GROUND_BARREN) {
02166
02167 TrackBits rail = GetTrackBits(tile);
02168
02169 switch (rail) {
02170 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02171 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02172 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02173 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02174
02175 default: {
02176 Owner owner = GetTileOwner(tile);
02177
02178 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02179 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02180 (rail & TRACK_BIT_X)
02181 )) {
02182 TileIndex n = tile + TileDiffXY(0, -1);
02183 TrackBits nrail = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02184
02185 if (!IsTileType(n, MP_RAILWAY) ||
02186 !IsTileOwner(n, owner) ||
02187 nrail == TRACK_BIT_UPPER ||
02188 nrail == TRACK_BIT_LEFT) {
02189 new_ground = RAIL_GROUND_FENCE_NW;
02190 }
02191 }
02192
02193 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02194 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02195 (rail & TRACK_BIT_X)
02196 )) {
02197 TileIndex n = tile + TileDiffXY(0, 1);
02198 TrackBits nrail = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02199
02200 if (!IsTileType(n, MP_RAILWAY) ||
02201 !IsTileOwner(n, owner) ||
02202 nrail == TRACK_BIT_LOWER ||
02203 nrail == TRACK_BIT_RIGHT) {
02204 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02205 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02206 }
02207 }
02208
02209 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02210 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02211 (rail & TRACK_BIT_Y)
02212 )) {
02213 TileIndex n = tile + TileDiffXY(-1, 0);
02214 TrackBits nrail = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02215
02216 if (!IsTileType(n, MP_RAILWAY) ||
02217 !IsTileOwner(n, owner) ||
02218 nrail == TRACK_BIT_UPPER ||
02219 nrail == TRACK_BIT_RIGHT) {
02220 new_ground = RAIL_GROUND_FENCE_NE;
02221 }
02222 }
02223
02224 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02225 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02226 (rail & TRACK_BIT_Y)
02227 )) {
02228 TileIndex n = tile + TileDiffXY(1, 0);
02229 TrackBits nrail = (IsTileType(n, MP_RAILWAY) && IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02230
02231 if (!IsTileType(n, MP_RAILWAY) ||
02232 !IsTileOwner(n, owner) ||
02233 nrail == TRACK_BIT_LOWER ||
02234 nrail == TRACK_BIT_LEFT) {
02235 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02236 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02237 }
02238 }
02239 break;
02240 }
02241 }
02242 }
02243
02244 set_ground:
02245 if (old_ground != new_ground) {
02246 SetRailGroundType(tile, new_ground);
02247 MarkTileDirtyByTile(tile);
02248 }
02249 }
02250
02251
02252 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02253 {
02254
02255 if (mode == TRANSPORT_WATER && IsPlainRailTile(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02256 TrackBits tb = GetTrackBits(tile);
02257 switch (tb) {
02258 default: NOT_REACHED();
02259 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02260 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02261 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02262 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02263 }
02264 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02265 }
02266
02267 if (mode != TRANSPORT_RAIL) return 0;
02268
02269 TrackBits trackbits = TRACK_BIT_NONE;
02270 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02271
02272 switch (GetRailTileType(tile)) {
02273 default: NOT_REACHED();
02274 case RAIL_TILE_NORMAL:
02275 trackbits = GetTrackBits(tile);
02276 break;
02277
02278 case RAIL_TILE_SIGNALS: {
02279 trackbits = GetTrackBits(tile);
02280 byte a = GetPresentSignals(tile);
02281 uint b = GetSignalStates(tile);
02282
02283 b &= a;
02284
02285
02286
02287
02288
02289
02290 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02291 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02292
02293 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02294 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02295 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02296 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02297
02298 break;
02299 }
02300
02301 case RAIL_TILE_DEPOT: {
02302 DiagDirection dir = GetRailDepotDirection(tile);
02303
02304 if (side != INVALID_DIAGDIR && side != dir) break;
02305
02306 trackbits = DiagDirToDiagTrackBits(dir);
02307 break;
02308 }
02309
02310 case RAIL_TILE_WAYPOINT:
02311 trackbits = GetRailWaypointBits(tile);
02312 break;
02313 }
02314
02315 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02316 }
02317
02318 static bool ClickTile_Track(TileIndex tile)
02319 {
02320 switch (GetRailTileType(tile)) {
02321 case RAIL_TILE_DEPOT: ShowDepotWindow(tile, VEH_TRAIN); return true;
02322 case RAIL_TILE_WAYPOINT: ShowWaypointWindow(GetWaypointByTile(tile)); return true;
02323 default: return false;
02324 }
02325 }
02326
02327 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02328 {
02329 td->owner[0] = GetTileOwner(tile);
02330 switch (GetRailTileType(tile)) {
02331 case RAIL_TILE_NORMAL:
02332 td->str = STR_1021_RAILROAD_TRACK;
02333 break;
02334
02335 case RAIL_TILE_SIGNALS: {
02336 const StringID signal_type[6][6] = {
02337 {
02338 STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS,
02339 STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS,
02340 STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS,
02341 STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS,
02342 STR_RAILROAD_TRACK_WITH_NORMAL_PBSSIGNALS,
02343 STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02344 },
02345 {
02346 STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS,
02347 STR_RAILROAD_TRACK_WITH_PRESIGNALS,
02348 STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS,
02349 STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS,
02350 STR_RAILROAD_TRACK_WITH_PRE_PBSSIGNALS,
02351 STR_RAILROAD_TRACK_WITH_PRE_NOENTRYSIGNALS
02352 },
02353 {
02354 STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS,
02355 STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS,
02356 STR_RAILROAD_TRACK_WITH_EXITSIGNALS,
02357 STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS,
02358 STR_RAILROAD_TRACK_WITH_EXIT_PBSSIGNALS,
02359 STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS
02360 },
02361 {
02362 STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS,
02363 STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS,
02364 STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS,
02365 STR_RAILROAD_TRACK_WITH_COMBOSIGNALS,
02366 STR_RAILROAD_TRACK_WITH_COMBO_PBSSIGNALS,
02367 STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS
02368 },
02369 {
02370 STR_RAILROAD_TRACK_WITH_NORMAL_PBSSIGNALS,
02371 STR_RAILROAD_TRACK_WITH_PRE_PBSSIGNALS,
02372 STR_RAILROAD_TRACK_WITH_EXIT_PBSSIGNALS,
02373 STR_RAILROAD_TRACK_WITH_COMBO_PBSSIGNALS,
02374 STR_RAILROAD_TRACK_WITH_PBSSIGNALS,
02375 STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS
02376 },
02377 {
02378 STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02379 STR_RAILROAD_TRACK_WITH_PRE_NOENTRYSIGNALS,
02380 STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02381 STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02382 STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS,
02383 STR_RAILROAD_TRACK_WITH_NOENTRYSIGNALS
02384 }
02385 };
02386
02387 SignalType primary_signal;
02388 SignalType secondary_signal;
02389 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02390 primary_signal = GetSignalType(tile, TRACK_UPPER);
02391 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02392 } else {
02393 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02394 }
02395
02396 td->str = signal_type[secondary_signal][primary_signal];
02397 break;
02398 }
02399
02400 case RAIL_TILE_DEPOT:
02401 td->str = STR_1023_RAILROAD_TRAIN_DEPOT;
02402 break;
02403
02404 case RAIL_TILE_WAYPOINT:
02405 default:
02406 td->str = STR_LANDINFO_WAYPOINT;
02407 break;
02408 }
02409 }
02410
02411 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02412 {
02413 if (!IsTileOwner(tile, old_owner)) return;
02414
02415 if (new_owner != INVALID_OWNER) {
02416 SetTileOwner(tile, new_owner);
02417 } else {
02418 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02419 }
02420 }
02421
02422 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02423 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02424 static const signed char _deltacoord_leaveoffset[8] = {
02425 -1, 0, 1, 0,
02426 0, 1, 0, -1
02427 };
02428
02429
02435 int TicksToLeaveDepot(const Vehicle *v)
02436 {
02437 DiagDirection dir = GetRailDepotDirection(v->tile);
02438 int length = v->u.rail.cached_veh_length;
02439
02440 switch (dir) {
02441 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02442 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02443 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02444 default:
02445 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02446 }
02447
02448 return 0;
02449 }
02450
02453 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
02454 {
02455 byte fract_coord;
02456 byte fract_coord_leave;
02457 DiagDirection dir;
02458 int length;
02459
02460
02461 if (v->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02462
02463
02464 dir = GetRailDepotDirection(tile);
02465
02466
02467
02468 length = v->u.rail.cached_veh_length;
02469
02470 fract_coord_leave =
02471 ((_fractcoords_enter[dir] & 0x0F) +
02472 (length + 1) * _deltacoord_leaveoffset[dir]) +
02473 (((_fractcoords_enter[dir] >> 4) +
02474 ((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
02475
02476 fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02477
02478 if (_fractcoords_behind[dir] == fract_coord) {
02479
02480 return VETSB_CANNOT_ENTER;
02481 } else if (_fractcoords_enter[dir] == fract_coord) {
02482 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02483
02484 v->u.rail.track = TRACK_BIT_DEPOT,
02485 v->vehstatus |= VS_HIDDEN;
02486 v->direction = ReverseDir(v->direction);
02487 if (v->Next() == NULL) VehicleEnterDepot(v);
02488 v->tile = tile;
02489
02490 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02491 return VETSB_ENTERED_WORMHOLE;
02492 }
02493 } else if (fract_coord_leave == fract_coord) {
02494 if (DiagDirToDir(dir) == v->direction) {
02495
02496 if ((v = v->Next()) != NULL) {
02497 v->vehstatus &= ~VS_HIDDEN;
02498 v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02499 }
02500 }
02501 }
02502
02503 return VETSB_CONTINUE;
02504 }
02505
02517 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02518 {
02519 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02520
02521
02522 if (CmdFailed(CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile))) return CMD_ERROR;
02523
02524
02525 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02526 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02527
02528 Corner track_corner;
02529 switch (rail_bits) {
02530 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02531 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02532 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02533 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02534
02535
02536 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price.terraform));
02537 }
02538
02539
02540 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02541 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02542 if (z_old != z_new) return CMD_ERROR;
02543
02544 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
02545
02546 if (tileh_old != tileh_new) {
02547
02548 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price.clear_water);
02549 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02550 }
02551 return cost;
02552 }
02553
02554 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02555 {
02556 uint z_old;
02557 Slope tileh_old = GetTileSlope(tile, &z_old);
02558 if (IsPlainRailTile(tile)) {
02559 TrackBits rail_bits = GetTrackBits(tile);
02560
02561 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02562
02563 _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
02564
02565
02566 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02567
02568
02569 Corner allowed_corner;
02570 switch (rail_bits) {
02571 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02572 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02573 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02574 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02575 default: return autoslope_result;
02576 }
02577
02578 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02579
02580
02581 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02582
02583
02584 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02585 if (allowed_corner == corner) continue;
02586 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02587 }
02588
02589
02590 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02591
02592
02593 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0);
02594 } else {
02595 if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) {
02596 switch (GetRailTileType(tile)) {
02597 case RAIL_TILE_WAYPOINT: {
02598 CommandCost cost = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, GetRailWaypointBits(tile));
02599 if (!CmdFailed(cost)) return cost;
02600 break;
02601 }
02602
02603 case RAIL_TILE_DEPOT:
02604 if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
02605 break;
02606
02607 default: NOT_REACHED();
02608 }
02609 }
02610 }
02611 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02612 }
02613
02614
02615 extern const TileTypeProcs _tile_type_rail_procs = {
02616 DrawTile_Track,
02617 GetSlopeZ_Track,
02618 ClearTile_Track,
02619 GetAcceptedCargo_Track,
02620 GetTileDesc_Track,
02621 GetTileTrackStatus_Track,
02622 ClickTile_Track,
02623 AnimateTile_Track,
02624 TileLoop_Track,
02625 ChangeTileOwner_Track,
02626 NULL,
02627 VehicleEnter_Track,
02628 GetFoundation_Track,
02629 TerraformTile_Track,
02630 };