00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "landscape.h"
00015 #include "viewport_func.h"
00016 #include "command_func.h"
00017 #include "engine_base.h"
00018 #include "depot_base.h"
00019 #include "pathfinder/yapf/yapf_cache.h"
00020 #include "newgrf_engine.h"
00021 #include "landscape_type.h"
00022 #include "newgrf_railtype.h"
00023 #include "newgrf_commons.h"
00024 #include "train.h"
00025 #include "variables.h"
00026 #include "autoslope.h"
00027 #include "water.h"
00028 #include "tunnelbridge_map.h"
00029 #include "window_func.h"
00030 #include "vehicle_func.h"
00031 #include "sound_func.h"
00032 #include "tunnelbridge.h"
00033 #include "functions.h"
00034 #include "elrail_func.h"
00035 #include "town.h"
00036 #include "pbs.h"
00037 #include "company_base.h"
00038
00039 #include "table/strings.h"
00040 #include "table/sprites.h"
00041 #include "table/railtypes.h"
00042 #include "table/track_land.h"
00043
00044 RailtypeInfo _railtypes[RAILTYPE_END];
00045
00046 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
00047
00051 void ResetRailTypes()
00052 {
00053 memset(_railtypes, 0, sizeof(_railtypes));
00054 memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes));
00055 }
00056
00057 void ResolveRailTypeGUISprites(RailtypeInfo *rti)
00058 {
00059 SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
00060 if (cursors_base != 0) {
00061 rti->gui_sprites.build_ns_rail = cursors_base + 0;
00062 rti->gui_sprites.build_x_rail = cursors_base + 1;
00063 rti->gui_sprites.build_ew_rail = cursors_base + 2;
00064 rti->gui_sprites.build_y_rail = cursors_base + 3;
00065 rti->gui_sprites.auto_rail = cursors_base + 4;
00066 rti->gui_sprites.build_depot = cursors_base + 5;
00067 rti->gui_sprites.build_tunnel = cursors_base + 6;
00068 rti->gui_sprites.convert_rail = cursors_base + 7;
00069 rti->cursor.rail_ns = cursors_base + 8;
00070 rti->cursor.rail_swne = cursors_base + 9;
00071 rti->cursor.rail_ew = cursors_base + 10;
00072 rti->cursor.rail_nwse = cursors_base + 11;
00073 rti->cursor.autorail = cursors_base + 12;
00074 rti->cursor.depot = cursors_base + 13;
00075 rti->cursor.tunnel = cursors_base + 14;
00076 rti->cursor.convert = cursors_base + 15;
00077 }
00078 }
00079
00080 void InitRailTypes()
00081 {
00082 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00083 RailtypeInfo *rti = &_railtypes[rt];
00084 ResolveRailTypeGUISprites(rti);
00085 }
00086 }
00087
00088 RailType AllocateRailType(RailTypeLabel label)
00089 {
00090 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00091 RailtypeInfo *rti = &_railtypes[rt];
00092
00093 if (rti->label == 0) {
00094
00095 memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti));
00096 rti->label = label;
00097
00098
00099 rti->powered_railtypes = (RailTypes)(1 << rt);
00100 rti->compatible_railtypes = (RailTypes)(1 << rt);
00101 return rt;
00102 }
00103 }
00104
00105 return INVALID_RAILTYPE;
00106 }
00107
00108 static const byte _track_sloped_sprites[14] = {
00109 14, 15, 22, 13,
00110 0, 21, 17, 12,
00111 23, 0, 18, 20,
00112 19, 16
00113 };
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00149 {
00150 TrackBits rail_bits = *(TrackBits *)data;
00151
00152 if (v->type != VEH_TRAIN) return NULL;
00153
00154 Train *t = Train::From(v);
00155 if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
00156
00157 _error_message = STR_ERROR_TRAIN_IN_THE_WAY + v->type;
00158 return v;
00159 }
00160
00168 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
00169 {
00170 TrackBits rail_bits = TrackToTrackBits(track);
00171
00172 return !HasVehicleOnPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc);
00173 }
00174
00181 static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00182 {
00183 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00184
00185
00186
00187 TrackBits current = GetTrackBits(tile);
00188 TrackBits future = current | to_build;
00189
00190
00191 if (current == future) {
00192
00193 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00194 }
00195
00196
00197 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00198
00199
00200 if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
00201 return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
00202 }
00203 }
00204
00205 return CommandCost();
00206 }
00207
00208
00210 static const TrackBits _valid_tracks_without_foundation[15] = {
00211 TRACK_BIT_ALL,
00212 TRACK_BIT_RIGHT,
00213 TRACK_BIT_UPPER,
00214 TRACK_BIT_X,
00215
00216 TRACK_BIT_LEFT,
00217 TRACK_BIT_NONE,
00218 TRACK_BIT_Y,
00219 TRACK_BIT_LOWER,
00220
00221 TRACK_BIT_LOWER,
00222 TRACK_BIT_Y,
00223 TRACK_BIT_NONE,
00224 TRACK_BIT_LEFT,
00225
00226 TRACK_BIT_X,
00227 TRACK_BIT_UPPER,
00228 TRACK_BIT_RIGHT,
00229 };
00230
00232 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00233 TRACK_BIT_NONE,
00234 TRACK_BIT_LEFT,
00235 TRACK_BIT_LOWER,
00236 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00237
00238 TRACK_BIT_RIGHT,
00239 TRACK_BIT_ALL,
00240 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00241 TRACK_BIT_ALL,
00242
00243 TRACK_BIT_UPPER,
00244 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00245 TRACK_BIT_ALL,
00246 TRACK_BIT_ALL,
00247
00248 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00249 TRACK_BIT_ALL,
00250 TRACK_BIT_ALL
00251 };
00252
00260 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00261 {
00262 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00263
00264 if (IsSteepSlope(tileh)) {
00265
00266 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00267 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00268
00269
00270 Corner highest_corner = GetHighestSlopeCorner(tileh);
00271 TrackBits higher_track = CornerToTrackBits(highest_corner);
00272
00273
00274 if (bits == higher_track) return HalftileFoundation(highest_corner);
00275
00276
00277 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00278
00279
00280 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00281 } else {
00282 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00283
00284 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00285
00286 Corner track_corner;
00287 switch (bits) {
00288 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00289 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00290 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00291 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00292
00293 case TRACK_BIT_HORZ:
00294 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00295 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00296 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00297
00298 case TRACK_BIT_VERT:
00299 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00300 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00301 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00302
00303 case TRACK_BIT_X:
00304 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00305 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00306
00307 case TRACK_BIT_Y:
00308 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00309 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00310
00311 default:
00312 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00313 }
00314
00315
00316
00317 if (!valid_on_leveled) return FOUNDATION_INVALID;
00318
00319
00320 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00321
00322
00323 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00324
00325
00326 return SpecialRailFoundation(track_corner);
00327 }
00328 }
00329
00330
00340 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00341 {
00342
00343 if (IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_RAILWAY) && (GetRailGroundType(tile) == RAIL_GROUND_WATER))) {
00344 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00345 }
00346
00347 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00348
00349
00350 if ((f_new == FOUNDATION_INVALID) ||
00351 ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00352 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00353 }
00354
00355 Foundation f_old = GetRailFoundation(tileh, existing);
00356 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00357 }
00358
00359
00360 static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
00361
00370 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00371 {
00372 RailType railtype = (RailType)p1;
00373 Track track = (Track)p2;
00374 CommandCost cost(EXPENSES_CONSTRUCTION);
00375
00376 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00377
00378 Slope tileh = GetTileSlope(tile, NULL);
00379 TrackBits trackbit = TrackToTrackBits(track);
00380
00381 switch (GetTileType(tile)) {
00382 case MP_RAILWAY: {
00383 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00384
00385 if (!IsPlainRail(tile)) return CMD_ERROR;
00386
00387 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00388
00389 CommandCost ret = CheckTrackCombination(tile, trackbit, flags);
00390 ret.SetGlobalErrorMessage();
00391 if (ret.Failed()) return ret;
00392
00393 if (!EnsureNoTrainOnTrack(tile, track)) return CMD_ERROR;
00394
00395 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00396 if (ret.Failed()) return ret;
00397 cost.AddCost(ret);
00398
00399
00400
00401
00402 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00403 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00404 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00405 if (ret.Failed()) return ret;
00406 cost.AddCost(ret);
00407 } else {
00408 return CMD_ERROR;
00409 }
00410 }
00411
00412 if (flags & DC_EXEC) {
00413 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00414 SetTrackBits(tile, GetTrackBits(tile) | trackbit);
00415 }
00416 break;
00417 }
00418
00419 case MP_ROAD:
00420 #define M(x) (1 << (x))
00421
00422 if (!HasBit(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
00423 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00424 }
00425 #undef M
00426
00427 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00428
00429 if (IsNormalRoad(tile)) {
00430 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00431
00432 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00433
00434 RoadTypes roadtypes = GetRoadTypes(tile);
00435 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00436 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00437 switch (roadtypes) {
00438 default: break;
00439 case ROADTYPES_TRAM:
00440
00441 if (flags & DC_EXEC) SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00442 roadtypes |= ROADTYPES_ROAD;
00443 break;
00444
00445 case ROADTYPES_ALL:
00446 if (road != tram) return CMD_ERROR;
00447 break;
00448 }
00449
00450 road |= tram;
00451
00452 if ((track == TRACK_X && road == ROAD_Y) ||
00453 (track == TRACK_Y && road == ROAD_X)) {
00454 if (flags & DC_EXEC) {
00455 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00456 UpdateLevelCrossing(tile, false);
00457 }
00458 break;
00459 }
00460 }
00461
00462 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00463 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00464 }
00465
00466
00467 default: {
00468
00469 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00470
00471 CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00472 if (ret.Failed()) return ret;
00473 cost.AddCost(ret);
00474
00475 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00476 if (ret.Failed()) return ret;
00477 cost.AddCost(ret);
00478
00479 if (water_ground) {
00480 cost.AddCost(-_price[PR_CLEAR_WATER]);
00481 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00482 }
00483
00484 if (flags & DC_EXEC) {
00485 MakeRailNormal(tile, _current_company, trackbit, railtype);
00486 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00487 }
00488 break;
00489 }
00490 }
00491
00492 if (flags & DC_EXEC) {
00493 MarkTileDirtyByTile(tile);
00494 AddTrackToSignalBuffer(tile, track, _current_company);
00495 YapfNotifyTrackLayoutChange(tile, track);
00496 }
00497
00498 cost.AddCost(RailBuildCost(railtype));
00499 return cost;
00500 }
00501
00510 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00511 {
00512 Track track = (Track)p2;
00513 CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_RAIL] );
00514 bool crossing = false;
00515
00516 if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
00517 TrackBits trackbit = TrackToTrackBits(track);
00518
00519
00520
00521
00522
00523 Owner owner = INVALID_OWNER;
00524
00525 Train *v = NULL;
00526
00527 switch (GetTileType(tile)) {
00528 case MP_ROAD: {
00529 if (!IsLevelCrossing(tile) ||
00530 GetCrossingRailBits(tile) != trackbit ||
00531 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00532 (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
00533 return CMD_ERROR;
00534 }
00535
00536 if (flags & DC_EXEC) {
00537 if (HasReservedTracks(tile, trackbit)) {
00538 v = GetTrainForReservation(tile, track);
00539 if (v != NULL) FreeTrainTrackReservation(v);
00540 }
00541 owner = GetTileOwner(tile);
00542 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00543 }
00544 break;
00545 }
00546
00547 case MP_RAILWAY: {
00548 TrackBits present;
00549
00550 if (!IsPlainRail(tile) ||
00551 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00552 !EnsureNoTrainOnTrack(tile, track)) {
00553 return CMD_ERROR;
00554 }
00555
00556 present = GetTrackBits(tile);
00557 if ((present & trackbit) == 0) return CMD_ERROR;
00558 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00559
00560
00561 if (HasSignalOnTrack(tile, track))
00562 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00563
00564 if (flags & DC_EXEC) {
00565 if (HasReservedTracks(tile, trackbit)) {
00566 v = GetTrainForReservation(tile, track);
00567 if (v != NULL) FreeTrainTrackReservation(v);
00568 }
00569 owner = GetTileOwner(tile);
00570 present ^= trackbit;
00571 if (present == 0) {
00572 Slope tileh = GetTileSlope(tile, NULL);
00573
00574 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00575 MakeShore(tile);
00576 } else {
00577 DoClearSquare(tile);
00578 }
00579 } else {
00580 SetTrackBits(tile, present);
00581 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00582 }
00583 }
00584 break;
00585 }
00586
00587 default: return CMD_ERROR;
00588 }
00589
00590 if (flags & DC_EXEC) {
00591
00592 assert(Company::IsValidID(owner));
00593
00594 MarkTileDirtyByTile(tile);
00595 if (crossing) {
00596
00597
00598
00599
00600 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00601 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00602 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00603 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00604 } else {
00605 AddTrackToSignalBuffer(tile, track, owner);
00606 YapfNotifyTrackLayoutChange(tile, track);
00607 }
00608
00609 if (v != NULL) TryPathReserve(v, true);
00610 }
00611
00612 return cost;
00613 }
00614
00615
00623 bool FloodHalftile(TileIndex t)
00624 {
00625 assert(IsPlainRailTile(t));
00626
00627 bool flooded = false;
00628 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00629
00630 Slope tileh = GetTileSlope(t, NULL);
00631 TrackBits rail_bits = GetTrackBits(t);
00632
00633 if (IsSlopeWithOneCornerRaised(tileh)) {
00634 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00635
00636 TrackBits to_remove = lower_track & rail_bits;
00637 if (to_remove != 0) {
00638 _current_company = OWNER_WATER;
00639 if (DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Failed()) return flooded;
00640 flooded = true;
00641 rail_bits = rail_bits & ~to_remove;
00642 if (rail_bits == 0) {
00643 MakeShore(t);
00644 MarkTileDirtyByTile(t);
00645 return flooded;
00646 }
00647 }
00648
00649 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00650 flooded = true;
00651 SetRailGroundType(t, RAIL_GROUND_WATER);
00652 MarkTileDirtyByTile(t);
00653 }
00654 } else {
00655
00656 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00657 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00658 flooded = true;
00659 SetRailGroundType(t, RAIL_GROUND_WATER);
00660 MarkTileDirtyByTile(t);
00661 }
00662 }
00663 }
00664 return flooded;
00665 }
00666
00667 static const TileIndexDiffC _trackdelta[] = {
00668 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00669 { 0, 0 },
00670 { 0, 0 },
00671 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00672 { 0, 0 },
00673 { 0, 0 }
00674 };
00675
00676
00677 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00678 {
00679 int x = TileX(start);
00680 int y = TileY(start);
00681 int ex = TileX(end);
00682 int ey = TileY(end);
00683
00684 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00685
00686
00687 int dx = ex - x;
00688 int dy = ey - y;
00689
00690
00691 int trdx = _trackdelta[*trackdir].x;
00692 int trdy = _trackdelta[*trackdir].y;
00693
00694 if (!IsDiagonalTrackdir(*trackdir)) {
00695 trdx += _trackdelta[*trackdir ^ 1].x;
00696 trdy += _trackdelta[*trackdir ^ 1].y;
00697 }
00698
00699
00700 while (
00701 (trdx <= 0 && dx > 0) ||
00702 (trdx >= 0 && dx < 0) ||
00703 (trdy <= 0 && dy > 0) ||
00704 (trdy >= 0 && dy < 0)
00705 ) {
00706 if (!HasBit(*trackdir, 3)) {
00707 SetBit(*trackdir, 3);
00708 trdx = -trdx;
00709 trdy = -trdy;
00710 } else {
00711 return CMD_ERROR;
00712 }
00713 }
00714
00715
00716
00717 if (!IsDiagonalTrackdir(*trackdir)) {
00718 trdx = _trackdelta[*trackdir].x;
00719 trdy = _trackdelta[*trackdir].y;
00720 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
00721 return CMD_ERROR;
00722 }
00723
00724 return CommandCost();
00725 }
00726
00739 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00740 {
00741 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00742 Track track = (Track)GB(p2, 4, 3);
00743 bool remove = HasBit(p2, 7);
00744 RailType railtype = (RailType)GB(p2, 0, 4);
00745
00746 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00747 if (p1 >= MapSize()) return CMD_ERROR;
00748 TileIndex end_tile = p1;
00749 Trackdir trackdir = TrackToTrackdir(track);
00750
00751 if (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) return CMD_ERROR;
00752
00753 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00754
00755 for (;;) {
00756 ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00757
00758 if (ret.Failed()) {
00759 if (_error_message != STR_ERROR_ALREADY_BUILT && !remove) {
00760 if (HasBit(p2, 8)) return CMD_ERROR;
00761 break;
00762 }
00763 _error_message = INVALID_STRING_ID;
00764 } else {
00765 total_cost.AddCost(ret);
00766 }
00767
00768 if (tile == end_tile) break;
00769
00770 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00771
00772
00773 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00774 }
00775
00776 return (total_cost.GetCost() == 0) ? CommandCost(remove ? INVALID_STRING_ID : (_error_message == INVALID_STRING_ID ? STR_ERROR_ALREADY_BUILT : _error_message)) : total_cost;
00777 }
00778
00792 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00793 {
00794 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00795 }
00796
00810 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00811 {
00812 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00813 }
00814
00826 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00827 {
00828
00829 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00830
00831 Slope tileh = GetTileSlope(tile, NULL);
00832
00833 DiagDirection dir = Extract<DiagDirection, 0>(p2);
00834
00835
00836
00837
00838
00839
00840
00841
00842 if (tileh != SLOPE_FLAT && (
00843 !_settings_game.construction.build_on_slopes ||
00844 IsSteepSlope(tileh) ||
00845 !CanBuildDepotByTileh(dir, tileh)
00846 )) {
00847 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00848 }
00849
00850 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00851 if (cost.Failed()) return CMD_ERROR;
00852
00853 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00854
00855 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00856
00857 if (flags & DC_EXEC) {
00858 Depot *d = new Depot(tile);
00859 d->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00860
00861 MakeRailDepot(tile, _current_company, d->index, dir, (RailType)p1);
00862 MarkTileDirtyByTile(tile);
00863
00864 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00865 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00866 }
00867
00868 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00869 return cost;
00870 }
00871
00892 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00893 {
00894 Track track = (Track)GB(p1, 0, 3);
00895 bool ctrl_pressed = HasBit(p1, 3);
00896 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00897 SignalType sigtype = (SignalType)GB(p1, 5, 3);
00898 bool convert_signal = HasBit(p1, 8);
00899 SignalType cycle_start = (SignalType)GB(p1, 9, 3);
00900 SignalType cycle_stop = (SignalType)GB(p1, 12, 3);
00901 uint num_dir_cycle = GB(p1, 15, 2);
00902
00903 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00904
00905
00906 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00907 !HasTrack(tile, track) || !EnsureNoTrainOnTrack(tile, track)) {
00908 return CMD_ERROR;
00909 }
00910
00911
00912 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00913
00914 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00915
00916 {
00917
00918 TrackBits trackbits = GetTrackBits(tile);
00919 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00920 trackbits != TRACK_BIT_HORZ &&
00921 trackbits != TRACK_BIT_VERT) {
00922 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
00923 }
00924 }
00925
00926
00927 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00928
00929
00930 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00931
00932 CommandCost cost;
00933 if (!HasSignalOnTrack(tile, track)) {
00934
00935 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00936 } else {
00937 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00938
00939 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00940
00941 } else if (convert_signal) {
00942
00943 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00944
00945 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00946 } else {
00947
00948 cost = CommandCost();
00949 }
00950
00951 } else {
00952
00953 cost = CommandCost();
00954 }
00955 }
00956
00957 if (flags & DC_EXEC) {
00958 Train *v = NULL;
00959
00960
00961
00962 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
00963 v = GetTrainForReservation(tile, track);
00964 if (v != NULL) FreeTrainTrackReservation(v);
00965 }
00966
00967 if (!HasSignals(tile)) {
00968
00969 SetHasSignals(tile, true);
00970 SetSignalStates(tile, 0xF);
00971 SetPresentSignals(tile, 0);
00972 SetSignalType(tile, track, sigtype);
00973 SetSignalVariant(tile, track, sigvar);
00974 }
00975
00976 if (p2 == 0) {
00977 if (!HasSignalOnTrack(tile, track)) {
00978
00979 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
00980 SetSignalType(tile, track, sigtype);
00981 SetSignalVariant(tile, track, sigvar);
00982 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
00983 } else {
00984 if (convert_signal) {
00985
00986 if (ctrl_pressed) {
00987
00988 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00989
00990 sigtype = GetSignalType(tile, track);
00991 } else {
00992
00993 SetSignalType(tile, track, sigtype);
00994 SetSignalVariant(tile, track, sigvar);
00995 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
00996 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
00997 }
00998 }
00999
01000 } else if (ctrl_pressed) {
01001
01002 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01003
01004 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01005
01006 SetSignalType(tile, track, sigtype);
01007 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01008 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01009 }
01010 } else {
01011
01012 CycleSignalSide(tile, track);
01013
01014 sigtype = GetSignalType(tile, track);
01015 }
01016 }
01017 } else {
01018
01019
01020 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01021 SetSignalVariant(tile, track, sigvar);
01022 SetSignalType(tile, track, sigtype);
01023 }
01024
01025 if (IsPbsSignal(sigtype)) {
01026
01027 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01028 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01029 }
01030 MarkTileDirtyByTile(tile);
01031 AddTrackToSignalBuffer(tile, track, _current_company);
01032 YapfNotifyTrackLayoutChange(tile, track);
01033 if (v != NULL) {
01034
01035 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01036 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01037 TryPathReserve(v, true);
01038 }
01039 }
01040 }
01041
01042 return cost;
01043 }
01044
01045 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01046 {
01047 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01048 if (tile == INVALID_TILE) return false;
01049
01050
01051 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01052
01053 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01054 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01055
01056
01057 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01058
01059
01060 trackdir = RemoveFirstTrackdir(&trackdirbits);
01061
01062
01063 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01064
01065 switch (GetTileType(tile)) {
01066 case MP_RAILWAY:
01067 if (IsRailDepot(tile)) return false;
01068 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01069 signal_ctr++;
01070 if (IsDiagonalTrackdir(trackdir)) {
01071 signal_ctr++;
01072
01073 ClrBit(signal_ctr, 0);
01074 }
01075 return true;
01076
01077 case MP_ROAD:
01078 if (!IsLevelCrossing(tile)) return false;
01079 signal_ctr += 2;
01080 return true;
01081
01082 case MP_TUNNELBRIDGE: {
01083 TileIndex orig_tile = tile;
01084
01085 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01086 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01087
01088
01089
01090 tile = GetOtherTunnelBridgeEnd(tile);
01091
01092 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01093 return true;
01094 }
01095
01096 default: return false;
01097 }
01098 }
01099
01115 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01116 {
01117 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01118 bool err = true;
01119 TileIndex start_tile = tile;
01120
01121 Track track = (Track)GB(p2, 0, 3);
01122 bool mode = HasBit(p2, 3);
01123 bool semaphores = HasBit(p2, 4);
01124 bool remove = HasBit(p2, 5);
01125 bool autofill = HasBit(p2, 6);
01126 Trackdir trackdir = TrackToTrackdir(track);
01127 byte signal_density = GB(p2, 24, 8);
01128
01129 if (p1 >= MapSize()) return CMD_ERROR;
01130 TileIndex end_tile = p1;
01131 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01132
01133 if (!IsPlainRailTile(tile)) return CMD_ERROR;
01134
01135
01136
01137 signal_density *= 2;
01138
01139 if (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) return CMD_ERROR;
01140
01141 track = TrackdirToTrack(trackdir);
01142 Trackdir start_trackdir = trackdir;
01143
01144
01145 if (!HasTrack(tile, track)) return CMD_ERROR;
01146
01147 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01148 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01149
01150 byte signals;
01151
01152 if (HasSignalOnTrack(tile, track)) {
01153 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01154 assert(signals != 0);
01155
01156
01157 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01158
01159 sigtype = GetSignalType(tile, track);
01160
01161 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01162 } else {
01163 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01164 }
01165
01166 byte signal_dir = 0;
01167 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01168 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178 int signal_ctr = 0;
01179 for (;;) {
01180
01181 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01182 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01183 SB(p1, 3, 1, mode);
01184 SB(p1, 4, 1, semaphores);
01185 SB(p1, 5, 3, sigtype);
01186 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01187
01188
01189 signals = 0;
01190 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01191 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01192
01193 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01194
01195
01196 if (ret.Succeeded()) {
01197 err = false;
01198 total_cost.AddCost(ret);
01199 }
01200 }
01201
01202 if (autofill) {
01203 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01204
01205
01206 if (tile == start_tile && trackdir == start_trackdir) break;
01207 } else {
01208 if (tile == end_tile) break;
01209
01210 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01211 signal_ctr++;
01212
01213
01214 if (IsDiagonalTrackdir(trackdir)) {
01215 signal_ctr++;
01216 } else {
01217 ToggleBit(trackdir, 0);
01218 }
01219 }
01220 }
01221
01222 return err ? CMD_ERROR : total_cost;
01223 }
01224
01242 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01243 {
01244 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01245 }
01246
01258 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01259 {
01260 Track track = (Track)GB(p1, 0, 3);
01261
01262 if (!ValParamTrackOrientation(track) ||
01263 !IsPlainRailTile(tile) ||
01264 !HasTrack(tile, track) ||
01265 !EnsureNoTrainOnTrack(tile, track) ||
01266 !HasSignalOnTrack(tile, track)) {
01267 return CMD_ERROR;
01268 }
01269
01270
01271 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01272
01273
01274 if (flags & DC_EXEC) {
01275 Train *v = NULL;
01276 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01277 v = GetTrainForReservation(tile, track);
01278 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01279
01280 Trackdir td = TrackToTrackdir(track);
01281 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01282
01283 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01284 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01285 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01286 if (HasReservedTracks(next, tracks)) {
01287 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01288 }
01289 }
01290 }
01291 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01292
01293
01294 if (GetPresentSignals(tile) == 0) {
01295 SetSignalStates(tile, 0);
01296 SetHasSignals(tile, false);
01297 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01298 }
01299
01300 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01301 YapfNotifyTrackLayoutChange(tile, track);
01302 if (v != NULL) TryPathReserve(v, false);
01303
01304 MarkTileDirtyByTile(tile);
01305 }
01306
01307 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01308 }
01309
01327 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01328 {
01329 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01330 }
01331
01333 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01334 {
01335 if (v->type != VEH_TRAIN) return NULL;
01336
01337
01338
01339 Train *t = Train::From(v);
01340 if (t->IsArticulatedPart()) return NULL;
01341
01342 const RailVehicleInfo *rvi = RailVehInfo(t->engine_type);
01343 if (GetVehicleProperty(t, PROP_TRAIN_POWER, rvi->power) != 0) t->First()->PowerChanged();
01344
01345 return NULL;
01346 }
01347
01357 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01358 {
01359 CommandCost cost(EXPENSES_CONSTRUCTION);
01360 RailType totype = (RailType)p2;
01361
01362 if (!ValParamRailtype(totype)) return CMD_ERROR;
01363 if (p1 >= MapSize()) return CMD_ERROR;
01364
01365 uint ex = TileX(tile);
01366 uint ey = TileY(tile);
01367 uint sx = TileX(p1);
01368 uint sy = TileY(p1);
01369
01370
01371 if (ex < sx) Swap(ex, sx);
01372 if (ey < sy) Swap(ey, sy);
01373
01374 _error_message = STR_ERROR_NO_SUITABLE_RAILROAD_TRACK;
01375
01376 for (uint x = sx; x <= ex; ++x) {
01377 for (uint y = sy; y <= ey; ++y) {
01378 TileIndex tile = TileXY(x, y);
01379 TileType tt = GetTileType(tile);
01380
01381
01382 switch (tt) {
01383 case MP_RAILWAY:
01384 break;
01385 case MP_STATION:
01386 if (!HasStationRail(tile)) continue;
01387 break;
01388 case MP_ROAD:
01389 if (!IsLevelCrossing(tile)) continue;
01390 break;
01391 case MP_TUNNELBRIDGE:
01392 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01393 break;
01394 default: continue;
01395 }
01396
01397
01398 RailType type = GetRailType(tile);
01399
01400
01401 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01402
01403
01404 if (!CheckTileOwnership(tile)) continue;
01405
01406 SmallVector<Train *, 2> vehicles_affected;
01407
01408
01409
01410 if (tt != MP_TUNNELBRIDGE) {
01411 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01412 if (flags & DC_EXEC) {
01413 TrackBits reserved = GetReservedTrackbits(tile);
01414 Track track;
01415 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01416 Train *v = GetTrainForReservation(tile, track);
01417 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01418
01419 FreeTrainTrackReservation(v);
01420 *vehicles_affected.Append() = v;
01421 }
01422 }
01423
01424 SetRailType(tile, totype);
01425 MarkTileDirtyByTile(tile);
01426
01427 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01428 }
01429 }
01430
01431 switch (tt) {
01432 case MP_RAILWAY:
01433 switch (GetRailTileType(tile)) {
01434 case RAIL_TILE_DEPOT:
01435 if (flags & DC_EXEC) {
01436
01437 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01438
01439
01440 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01441 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01442 }
01443 cost.AddCost(RailConvertCost(type, totype));
01444 break;
01445
01446 default:
01447 if (flags & DC_EXEC) {
01448
01449 TrackBits tracks = GetTrackBits(tile);
01450 while (tracks != TRACK_BIT_NONE) {
01451 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01452 }
01453 }
01454 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01455 break;
01456 }
01457 break;
01458
01459 case MP_TUNNELBRIDGE: {
01460 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01461
01462
01463
01464 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01465 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01466
01467
01468 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01469 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01470
01471 if (flags & DC_EXEC) {
01472 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01473 if (HasTunnelBridgeReservation(tile)) {
01474 Train *v = GetTrainForReservation(tile, track);
01475 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01476
01477 FreeTrainTrackReservation(v);
01478 *vehicles_affected.Append() = v;
01479 }
01480 }
01481 SetRailType(tile, totype);
01482 SetRailType(endtile, totype);
01483
01484 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01485 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01486
01487 YapfNotifyTrackLayoutChange(tile, track);
01488 YapfNotifyTrackLayoutChange(endtile, track);
01489
01490 MarkTileDirtyByTile(tile);
01491 MarkTileDirtyByTile(endtile);
01492
01493 if (IsBridge(tile)) {
01494 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01495 TileIndex t = tile + delta;
01496 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01497 }
01498 }
01499
01500 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01501 } break;
01502
01503 default:
01504 if (flags & DC_EXEC) {
01505 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01506 YapfNotifyTrackLayoutChange(tile, track);
01507 }
01508
01509 cost.AddCost(RailConvertCost(type, totype));
01510 break;
01511 }
01512
01513 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01514 TryPathReserve(vehicles_affected[i], true);
01515 }
01516 }
01517 }
01518
01519 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01520 }
01521
01522 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01523 {
01524 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01525 return CMD_ERROR;
01526
01527 if (!EnsureNoVehicleOnGround(tile))
01528 return CMD_ERROR;
01529
01530 if (flags & DC_EXEC) {
01531
01532 DiagDirection dir = GetRailDepotDirection(tile);
01533 Owner owner = GetTileOwner(tile);
01534 Train *v = NULL;
01535
01536 if (HasDepotReservation(tile)) {
01537 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01538 if (v != NULL) FreeTrainTrackReservation(v);
01539 }
01540
01541 delete Depot::GetByTile(tile);
01542 DoClearSquare(tile);
01543 AddSideToSignalBuffer(tile, dir, owner);
01544 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01545 if (v != NULL) TryPathReserve(v, true);
01546 }
01547
01548 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01549 }
01550
01551 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01552 {
01553 CommandCost cost(EXPENSES_CONSTRUCTION);
01554
01555 if (flags & DC_AUTO) {
01556 if (!IsTileOwner(tile, _current_company)) {
01557 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01558 }
01559
01560 if (IsPlainRail(tile)) {
01561 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01562 } else {
01563 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01564 }
01565 }
01566
01567 switch (GetRailTileType(tile)) {
01568 case RAIL_TILE_SIGNALS:
01569 case RAIL_TILE_NORMAL: {
01570 Slope tileh = GetTileSlope(tile, NULL);
01571
01572 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01573
01574 TrackBits tracks = GetTrackBits(tile);
01575 while (tracks != TRACK_BIT_NONE) {
01576 Track track = RemoveFirstTrack(&tracks);
01577 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01578 if (ret.Failed()) return CMD_ERROR;
01579 cost.AddCost(ret);
01580 }
01581
01582
01583 if (water_ground && !(flags & DC_BANKRUPT)) {
01584 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01585
01586
01587 if (flags & DC_EXEC) DoClearSquare(tile);
01588 cost.AddCost(_price[PR_CLEAR_WATER]);
01589 }
01590
01591 return cost;
01592 }
01593
01594 case RAIL_TILE_DEPOT:
01595 return RemoveTrainDepot(tile, flags);
01596
01597 default:
01598 return CMD_ERROR;
01599 }
01600 }
01601
01606 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01607 {
01608 switch (track) {
01609 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01610 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01611 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01612 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01613 default: break;
01614 }
01615 return GetSlopeZ(x, y);
01616 }
01617
01618 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01619 {
01620 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01621 static const Point SignalPositions[2][12] = {
01622 {
01623
01624 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01625
01626 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01627 }, {
01628
01629 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01630
01631 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01632 }
01633 };
01634
01635 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01636 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01637
01638 SpriteID sprite;
01639
01640 SignalType type = GetSignalType(tile, track);
01641 SignalVariant variant = GetSignalVariant(tile, track);
01642
01643 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01644
01645 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01646 } else {
01647
01648 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01649 }
01650
01651 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01652 }
01653
01654 static uint32 _drawtile_track_palette;
01655
01656
01657 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01658 {
01659 RailFenceOffset rfo = RFO_FLAT_X;
01660 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01661 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01662 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01663 }
01664
01665 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01666 {
01667 RailFenceOffset rfo = RFO_FLAT_X;
01668 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01669 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01670 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01671 }
01672
01673 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01674 {
01675 DrawTrackFence_NW(ti, base_image);
01676 DrawTrackFence_SE(ti, base_image);
01677 }
01678
01679 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01680 {
01681 RailFenceOffset rfo = RFO_FLAT_Y;
01682 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01683 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01684 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01685 }
01686
01687 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01688 {
01689 RailFenceOffset rfo = RFO_FLAT_Y;
01690 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01691 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01692 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01693 }
01694
01695 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01696 {
01697 DrawTrackFence_NE(ti, base_image);
01698 DrawTrackFence_SW(ti, base_image);
01699 }
01700
01704 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01705 {
01706 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01707 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01708 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01709 }
01710
01714 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01715 {
01716 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01717 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01718 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01719 }
01720
01724 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01725 {
01726 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01727 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01728 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01729 }
01730
01734 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01735 {
01736 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01737 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01738 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01739 }
01740
01741
01742 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01743 {
01744
01745 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES);
01746 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01747
01748 switch (GetRailGroundType(ti->tile)) {
01749 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01750 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01751 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01752 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01753 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01754 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01755 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01756 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01757 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01758 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01759 case RAIL_GROUND_WATER: {
01760 Corner track_corner;
01761 if (IsHalftileSlope(ti->tileh)) {
01762
01763 track_corner = GetHalftileSlopeCorner(ti->tileh);
01764 } else {
01765
01766 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01767 }
01768 switch (track_corner) {
01769 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01770 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01771 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01772 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01773 default: NOT_REACHED();
01774 }
01775 break;
01776 }
01777 default: break;
01778 }
01779 }
01780
01781
01782 static const int INF = 1000;
01783 static const SubSprite _halftile_sub_sprite[4] = {
01784 { -INF , -INF , 32 - 33, INF },
01785 { -INF , 0 + 7, INF , INF },
01786 { -31 + 33, -INF , INF , INF },
01787 { -INF , -INF , INF , 30 - 23 }
01788 };
01789
01790 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01791 {
01792 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01793 }
01794
01795 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01796 {
01797 RailGroundType rgt = GetRailGroundType(ti->tile);
01798 Foundation f = GetRailFoundation(ti->tileh, track);
01799 Corner halftile_corner = CORNER_INVALID;
01800
01801 if (IsNonContinuousFoundation(f)) {
01802
01803 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01804
01805 track &= ~CornerToTrackBits(halftile_corner);
01806 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01807 }
01808
01809 DrawFoundation(ti, f);
01810
01811
01812
01813 if (track == TRACK_BIT_NONE && rgt == RAIL_GROUND_WATER) {
01814 if (IsSteepSlope(ti->tileh)) {
01815 DrawShoreTile(ti->tileh);
01816 } else {
01817 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01818 }
01819 } else {
01820 SpriteID image;
01821
01822 switch (rgt) {
01823 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01824 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01825 default: image = SPR_FLAT_GRASS_TILE; break;
01826 }
01827
01828 image += _tileh_to_sprite[ti->tileh];
01829
01830 DrawGroundSprite(image, PAL_NONE);
01831 }
01832
01833 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01834 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01835 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01836
01837 if (track == TRACK_BIT_NONE) {
01838
01839 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01840 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01841 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01842 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01843 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01844 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01845 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
01846 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
01847 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
01848 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
01849 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
01850 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
01851 } else {
01852 switch (track) {
01853
01854
01855 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
01856 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
01857 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
01858 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01859 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
01860 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01861 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
01862 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
01863 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01864 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
01865 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01866
01867 default:
01868
01869 if ((track & TRACK_BIT_3WAY_NE) == 0) {
01870 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
01871 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
01872 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
01873 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
01874 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
01875 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
01876 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
01877 } else {
01878 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
01879 }
01880
01881
01882 track &= ~pbs;
01883
01884
01885 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
01886 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
01887 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
01888 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
01889 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
01890 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
01891 }
01892
01893
01894 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
01895 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
01896 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
01897 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
01898 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
01899 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
01900 }
01901
01902 if (IsValidCorner(halftile_corner)) {
01903 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01904
01905
01906 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01907
01908 SpriteID image;
01909 switch (rgt) {
01910 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01911 case RAIL_GROUND_ICE_DESERT:
01912 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01913 default: image = SPR_FLAT_GRASS_TILE; break;
01914 }
01915
01916 image += _tileh_to_sprite[fake_slope];
01917
01918 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
01919
01920 track = CornerToTrackBits(halftile_corner);
01921
01922 int offset;
01923 switch (track) {
01924 default: NOT_REACHED();
01925 case TRACK_BIT_UPPER: offset = RTO_N; break;
01926 case TRACK_BIT_LOWER: offset = RTO_S; break;
01927 case TRACK_BIT_RIGHT: offset = RTO_E; break;
01928 case TRACK_BIT_LEFT: offset = RTO_W; break;
01929 }
01930
01931 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
01932 if (HasReservedTracks(ti->tile, track)) {
01933 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
01934 }
01935 }
01936 }
01937
01943 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01944 {
01945 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01946
01947 if (rti->UsesOverlay()) {
01948 DrawTrackBitsOverlay(ti, track, rti);
01949 return;
01950 }
01951
01952 RailGroundType rgt = GetRailGroundType(ti->tile);
01953 Foundation f = GetRailFoundation(ti->tileh, track);
01954 Corner halftile_corner = CORNER_INVALID;
01955
01956 if (IsNonContinuousFoundation(f)) {
01957
01958 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01959
01960 track &= ~CornerToTrackBits(halftile_corner);
01961 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01962 }
01963
01964 DrawFoundation(ti, f);
01965
01966
01967 SpriteID image;
01968 PaletteID pal = PAL_NONE;
01969 const SubSprite *sub = NULL;
01970 bool junction = false;
01971
01972
01973 if (track == 0) {
01974
01975 if (rgt == RAIL_GROUND_WATER) {
01976 if (IsSteepSlope(ti->tileh)) {
01977 DrawShoreTile(ti->tileh);
01978 image = 0;
01979 } else {
01980 image = SPR_FLAT_WATER_TILE;
01981 }
01982 } else {
01983 switch (rgt) {
01984 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01985 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01986 default: image = SPR_FLAT_GRASS_TILE; break;
01987 }
01988 image += _tileh_to_sprite[ti->tileh];
01989 }
01990 } else {
01991 if (ti->tileh != SLOPE_FLAT) {
01992
01993 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01994 } else {
01995
01996 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
01997 (image++, track == TRACK_BIT_X) ||
01998 (image++, track == TRACK_BIT_UPPER) ||
01999 (image++, track == TRACK_BIT_LOWER) ||
02000 (image++, track == TRACK_BIT_RIGHT) ||
02001 (image++, track == TRACK_BIT_LEFT) ||
02002 (image++, track == TRACK_BIT_CROSS) ||
02003
02004 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02005 (image++, track == TRACK_BIT_VERT) ||
02006
02007 (junction = true, false) ||
02008 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02009 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02010 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02011 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02012 (image++, true);
02013 }
02014
02015 switch (rgt) {
02016 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02017 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02018 case RAIL_GROUND_WATER: {
02019
02020 DrawShoreTile(ti->tileh);
02021 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02022 sub = &(_halftile_sub_sprite[track_corner]);
02023 break;
02024 }
02025 default: break;
02026 }
02027 }
02028
02029 if (image != 0) DrawGroundSprite(image, pal, sub);
02030
02031
02032 if (junction) {
02033 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02034 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02035 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02036 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02037 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02038 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02039 }
02040
02041
02042 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02043
02044 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02045 if (pbs & TRACK_BIT_X) {
02046 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02047 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02048 } else {
02049 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02050 }
02051 }
02052 if (pbs & TRACK_BIT_Y) {
02053 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02054 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02055 } else {
02056 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02057 }
02058 }
02059 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
02060 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
02061 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
02062 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
02063 }
02064
02065 if (IsValidCorner(halftile_corner)) {
02066 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02067
02068
02069 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02070 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02071 pal = PAL_NONE;
02072 switch (rgt) {
02073 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02074 case RAIL_GROUND_ICE_DESERT:
02075 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02076 default: break;
02077 }
02078 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02079
02080 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02081 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02082 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
02083 }
02084 }
02085 }
02086
02092 enum {
02093 SIGNAL_TO_SOUTHWEST = 0,
02094 SIGNAL_TO_NORTHEAST = 2,
02095 SIGNAL_TO_SOUTHEAST = 4,
02096 SIGNAL_TO_NORTHWEST = 6,
02097 SIGNAL_TO_EAST = 8,
02098 SIGNAL_TO_WEST = 10,
02099 SIGNAL_TO_SOUTH = 12,
02100 SIGNAL_TO_NORTH = 14,
02101 };
02102
02103 static void DrawSignals(TileIndex tile, TrackBits rails)
02104 {
02105 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02106
02107 if (!(rails & TRACK_BIT_Y)) {
02108 if (!(rails & TRACK_BIT_X)) {
02109 if (rails & TRACK_BIT_LEFT) {
02110 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02111 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02112 }
02113 if (rails & TRACK_BIT_RIGHT) {
02114 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02115 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02116 }
02117 if (rails & TRACK_BIT_UPPER) {
02118 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02119 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02120 }
02121 if (rails & TRACK_BIT_LOWER) {
02122 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02123 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02124 }
02125 } else {
02126 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02127 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02128 }
02129 } else {
02130 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02131 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02132 }
02133 }
02134
02135 static void DrawTile_Track(TileInfo *ti)
02136 {
02137 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02138
02139 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02140
02141 if (IsPlainRail(ti->tile)) {
02142 TrackBits rails = GetTrackBits(ti->tile);
02143
02144 DrawTrackBits(ti, rails);
02145
02146 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02147
02148 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02149
02150 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02151 } else {
02152
02153 const DrawTileSprites *dts;
02154 PaletteID pal = PAL_NONE;
02155 SpriteID relocation;
02156
02157 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02158
02159 if (IsInvisibilitySet(TO_BUILDINGS)) {
02160
02161 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02162 } else {
02163 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02164 }
02165
02166 SpriteID image;
02167 if (rti->UsesOverlay()) {
02168 image = SPR_FLAT_GRASS_TILE;
02169 } else {
02170 image = dts->ground.sprite;
02171 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
02172 }
02173
02174
02175
02176 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02177 if (image != SPR_FLAT_GRASS_TILE) {
02178 image += rti->snow_offset;
02179 } else {
02180 image = SPR_FLAT_SNOW_DESERT_TILE;
02181 }
02182 }
02183
02184 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02185
02186 if (rti->UsesOverlay()) {
02187 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02188
02189 switch (GetRailDepotDirection(ti->tile)) {
02190 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02191 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02192 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02193 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02194 default: break;
02195 }
02196
02197 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02198 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02199
02200 switch (GetRailDepotDirection(ti->tile)) {
02201 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02202 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02203 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02204 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02205 default: break;
02206 }
02207 }
02208
02209 relocation = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02210 relocation -= SPR_RAIL_DEPOT_SE_1;
02211 } else {
02212
02213 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02214 switch (GetRailDepotDirection(ti->tile)) {
02215 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02216 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02217 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02218 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02219 default: break;
02220 }
02221 }
02222
02223 relocation = rti->total_offset;
02224 }
02225
02226 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02227
02228 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02229 }
02230 DrawBridgeMiddle(ti);
02231 }
02232
02233 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02234 {
02235 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02236 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02237 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02238 uint32 offset = rti->total_offset;
02239
02240 x += 33;
02241 y += 17;
02242
02243 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02244 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02245
02246 DrawSprite(image, PAL_NONE, x, y);
02247
02248 if (rti->UsesOverlay()) {
02249 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02250
02251 switch (dir) {
02252 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02253 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02254 default: break;
02255 }
02256
02257 offset = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02258 offset -= SPR_RAIL_DEPOT_SE_1;
02259 }
02260
02261 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02262 }
02263
02264 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02265 {
02266 uint z;
02267 Slope tileh = GetTileSlope(tile, &z);
02268
02269 if (tileh == SLOPE_FLAT) return z;
02270 if (IsPlainRail(tile)) {
02271 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02272 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02273 } else {
02274 return z + TILE_HEIGHT;
02275 }
02276 }
02277
02278 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02279 {
02280 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02281 }
02282
02283 static void TileLoop_Track(TileIndex tile)
02284 {
02285 RailGroundType old_ground = GetRailGroundType(tile);
02286 RailGroundType new_ground;
02287
02288 if (old_ground == RAIL_GROUND_WATER) {
02289 TileLoop_Water(tile);
02290 return;
02291 }
02292
02293 switch (_settings_game.game_creation.landscape) {
02294 case LT_ARCTIC: {
02295 uint z;
02296 Slope slope = GetTileSlope(tile, &z);
02297 bool half = false;
02298
02299
02300
02301 if (IsPlainRail(tile)) {
02302 TrackBits track = GetTrackBits(tile);
02303 Foundation f = GetRailFoundation(slope, track);
02304
02305 switch (f) {
02306 case FOUNDATION_NONE:
02307
02308 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02309 break;
02310
02311 case FOUNDATION_INCLINED_X:
02312 case FOUNDATION_INCLINED_Y:
02313
02314 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02315 break;
02316
02317 case FOUNDATION_STEEP_LOWER:
02318
02319 z += TILE_HEIGHT;
02320 break;
02321
02322 default:
02323
02324 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02325 z += TILE_HEIGHT;
02326 break;
02327 }
02328
02329 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02330 } else {
02331
02332 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02333 }
02334
02335
02336
02337
02338
02339 if (z > GetSnowLine()) {
02340 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02341
02342 new_ground = RAIL_GROUND_HALF_SNOW;
02343 } else {
02344 new_ground = RAIL_GROUND_ICE_DESERT;
02345 }
02346 goto set_ground;
02347 }
02348 break;
02349 }
02350
02351 case LT_TROPIC:
02352 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02353 new_ground = RAIL_GROUND_ICE_DESERT;
02354 goto set_ground;
02355 }
02356 break;
02357 }
02358
02359 if (!IsPlainRail(tile)) return;
02360
02361 new_ground = RAIL_GROUND_GRASS;
02362
02363 if (old_ground != RAIL_GROUND_BARREN) {
02364
02365 TrackBits rail = GetTrackBits(tile);
02366
02367 switch (rail) {
02368 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02369 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02370 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02371 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02372
02373 default: {
02374 Owner owner = GetTileOwner(tile);
02375
02376 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02377 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02378 (rail & TRACK_BIT_X)
02379 )) {
02380 TileIndex n = tile + TileDiffXY(0, -1);
02381 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02382
02383 if (!IsTileType(n, MP_RAILWAY) ||
02384 !IsTileOwner(n, owner) ||
02385 nrail == TRACK_BIT_UPPER ||
02386 nrail == TRACK_BIT_LEFT) {
02387 new_ground = RAIL_GROUND_FENCE_NW;
02388 }
02389 }
02390
02391 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02392 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02393 (rail & TRACK_BIT_X)
02394 )) {
02395 TileIndex n = tile + TileDiffXY(0, 1);
02396 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02397
02398 if (!IsTileType(n, MP_RAILWAY) ||
02399 !IsTileOwner(n, owner) ||
02400 nrail == TRACK_BIT_LOWER ||
02401 nrail == TRACK_BIT_RIGHT) {
02402 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02403 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02404 }
02405 }
02406
02407 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02408 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02409 (rail & TRACK_BIT_Y)
02410 )) {
02411 TileIndex n = tile + TileDiffXY(-1, 0);
02412 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02413
02414 if (!IsTileType(n, MP_RAILWAY) ||
02415 !IsTileOwner(n, owner) ||
02416 nrail == TRACK_BIT_UPPER ||
02417 nrail == TRACK_BIT_RIGHT) {
02418 new_ground = RAIL_GROUND_FENCE_NE;
02419 }
02420 }
02421
02422 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02423 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02424 (rail & TRACK_BIT_Y)
02425 )) {
02426 TileIndex n = tile + TileDiffXY(1, 0);
02427 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02428
02429 if (!IsTileType(n, MP_RAILWAY) ||
02430 !IsTileOwner(n, owner) ||
02431 nrail == TRACK_BIT_LOWER ||
02432 nrail == TRACK_BIT_LEFT) {
02433 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02434 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02435 }
02436 }
02437 break;
02438 }
02439 }
02440 }
02441
02442 set_ground:
02443 if (old_ground != new_ground) {
02444 SetRailGroundType(tile, new_ground);
02445 MarkTileDirtyByTile(tile);
02446 }
02447 }
02448
02449
02450 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02451 {
02452
02453 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02454 TrackBits tb = GetTrackBits(tile);
02455 switch (tb) {
02456 default: NOT_REACHED();
02457 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02458 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02459 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02460 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02461 }
02462 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02463 }
02464
02465 if (mode != TRANSPORT_RAIL) return 0;
02466
02467 TrackBits trackbits = TRACK_BIT_NONE;
02468 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02469
02470 switch (GetRailTileType(tile)) {
02471 default: NOT_REACHED();
02472 case RAIL_TILE_NORMAL:
02473 trackbits = GetTrackBits(tile);
02474 break;
02475
02476 case RAIL_TILE_SIGNALS: {
02477 trackbits = GetTrackBits(tile);
02478 byte a = GetPresentSignals(tile);
02479 uint b = GetSignalStates(tile);
02480
02481 b &= a;
02482
02483
02484
02485
02486
02487
02488 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02489 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02490
02491 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02492 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02493 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02494 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02495
02496 break;
02497 }
02498
02499 case RAIL_TILE_DEPOT: {
02500 DiagDirection dir = GetRailDepotDirection(tile);
02501
02502 if (side != INVALID_DIAGDIR && side != dir) break;
02503
02504 trackbits = DiagDirToDiagTrackBits(dir);
02505 break;
02506 }
02507 }
02508
02509 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02510 }
02511
02512 static bool ClickTile_Track(TileIndex tile)
02513 {
02514 if (!IsRailDepot(tile)) return false;
02515
02516 ShowDepotWindow(tile, VEH_TRAIN);
02517 return true;
02518 }
02519
02520 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02521 {
02522 td->owner[0] = GetTileOwner(tile);
02523 switch (GetRailTileType(tile)) {
02524 case RAIL_TILE_NORMAL:
02525 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02526 break;
02527
02528 case RAIL_TILE_SIGNALS: {
02529 static const StringID signal_type[6][6] = {
02530 {
02531 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02532 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02533 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02534 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02535 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02536 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02537 },
02538 {
02539 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02540 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02541 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02542 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02543 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02544 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02545 },
02546 {
02547 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02548 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02549 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02550 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02551 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02552 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02553 },
02554 {
02555 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02556 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02557 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02558 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02559 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02560 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02561 },
02562 {
02563 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02564 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02565 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02566 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02567 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02568 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02569 },
02570 {
02571 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02572 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02573 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02574 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02575 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02576 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02577 }
02578 };
02579
02580 SignalType primary_signal;
02581 SignalType secondary_signal;
02582 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02583 primary_signal = GetSignalType(tile, TRACK_UPPER);
02584 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02585 } else {
02586 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02587 }
02588
02589 td->str = signal_type[secondary_signal][primary_signal];
02590 break;
02591 }
02592
02593 case RAIL_TILE_DEPOT:
02594 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02595 break;
02596
02597 default:
02598 NOT_REACHED();
02599 }
02600 }
02601
02602 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02603 {
02604 if (!IsTileOwner(tile, old_owner)) return;
02605
02606 if (new_owner != INVALID_OWNER) {
02607 SetTileOwner(tile, new_owner);
02608 } else {
02609 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02610 }
02611 }
02612
02613 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02614 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02615 static const int8 _deltacoord_leaveoffset[8] = {
02616 -1, 0, 1, 0,
02617 0, 1, 0, -1
02618 };
02619
02620
02626 int TicksToLeaveDepot(const Train *v)
02627 {
02628 DiagDirection dir = GetRailDepotDirection(v->tile);
02629 int length = v->tcache.cached_veh_length;
02630
02631 switch (dir) {
02632 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02633 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02634 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02635 default:
02636 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02637 }
02638
02639 return 0;
02640 }
02641
02644 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02645 {
02646
02647 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02648
02649 Train *v = Train::From(u);
02650
02651
02652 DiagDirection dir = GetRailDepotDirection(tile);
02653
02654
02655
02656 int length = v->tcache.cached_veh_length;
02657
02658 byte fract_coord_leave =
02659 ((_fractcoords_enter[dir] & 0x0F) +
02660 (length + 1) * _deltacoord_leaveoffset[dir]) +
02661 (((_fractcoords_enter[dir] >> 4) +
02662 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02663
02664 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02665
02666 if (_fractcoords_behind[dir] == fract_coord) {
02667
02668 return VETSB_CANNOT_ENTER;
02669 } else if (_fractcoords_enter[dir] == fract_coord) {
02670 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02671
02672 v->track = TRACK_BIT_DEPOT,
02673 v->vehstatus |= VS_HIDDEN;
02674 v->direction = ReverseDir(v->direction);
02675 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02676 v->tile = tile;
02677
02678 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02679 return VETSB_ENTERED_WORMHOLE;
02680 }
02681 } else if (fract_coord_leave == fract_coord) {
02682 if (DiagDirToDir(dir) == v->direction) {
02683
02684 if ((v = v->Next()) != NULL) {
02685 v->vehstatus &= ~VS_HIDDEN;
02686 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02687 }
02688 }
02689 }
02690
02691 return VETSB_CONTINUE;
02692 }
02693
02705 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02706 {
02707 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02708
02709
02710 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CMD_ERROR;
02711
02712
02713 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02714 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02715
02716 Corner track_corner;
02717 switch (rail_bits) {
02718 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02719 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02720 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02721 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02722
02723
02724 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02725 }
02726
02727
02728 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02729 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02730 if (z_old != z_new) return CMD_ERROR;
02731
02732 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02733
02734 if (tileh_old != tileh_new) {
02735
02736 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02737 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02738 }
02739 return cost;
02740 }
02741
02742 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02743 {
02744 uint z_old;
02745 Slope tileh_old = GetTileSlope(tile, &z_old);
02746 if (IsPlainRail(tile)) {
02747 TrackBits rail_bits = GetTrackBits(tile);
02748
02749 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02750
02751 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02752
02753
02754 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02755
02756
02757 Corner allowed_corner;
02758 switch (rail_bits) {
02759 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02760 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02761 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02762 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02763 default: return autoslope_result;
02764 }
02765
02766 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02767
02768
02769 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02770
02771
02772 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02773 if (allowed_corner == corner) continue;
02774 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02775 }
02776
02777
02778 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02779
02780
02781 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02782 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02783 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02784 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02785 }
02786 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02787 }
02788
02789
02790 extern const TileTypeProcs _tile_type_rail_procs = {
02791 DrawTile_Track,
02792 GetSlopeZ_Track,
02793 ClearTile_Track,
02794 NULL,
02795 GetTileDesc_Track,
02796 GetTileTrackStatus_Track,
02797 ClickTile_Track,
02798 NULL,
02799 TileLoop_Track,
02800 ChangeTileOwner_Track,
02801 NULL,
02802 VehicleEnter_Track,
02803 GetFoundation_Track,
02804 TerraformTile_Track,
02805 };