Initial implementation of two rail types per tile
This commit is contained in:
@@ -249,6 +249,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li style="color: blue">m8 bits 11..6 = <a name="TrackType">secondary track type</a> (used for lower or right track when two parallel tracks on tile)</li>
|
||||
<li>m4 bits 7..4: see signals</li>
|
||||
<li>m4 bits 3..0: Ground type (values with fences are not valid for depots and checkpoints)
|
||||
<table>
|
||||
@@ -1729,6 +1730,7 @@
|
||||
<li>m7 bit 5 set = on snow or desert</li>
|
||||
<li>m7 bits 7..6: present road types for road</li>
|
||||
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway</li>
|
||||
<li style="color: blue">m8 bits 11..6 = <a name="TrackType">secondary track type</a> for railway (used for bridge-bypassing track when two parallel tracks on custom bridge head)</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -109,7 +109,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">XXXX XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOOO OO</span>XX XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO</span> <span class="used_p">PPPP PP</span>XX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">rail with signals</td>
|
||||
@@ -135,7 +135,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">XX<span class="free">O</span>X <span class="free">OO</span>XX</td>
|
||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">OOOO OOOO OO</span>XX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=3>2</td>
|
||||
@@ -376,7 +376,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">O</span><span class="used_p">P</span>XX XX<span class="used_p">PP</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">OOOO</span> <span class="used_p">PPPP PP</span>XX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=2>A</td>
|
||||
|
174
src/elrail.cpp
174
src/elrail.cpp
@@ -79,46 +79,77 @@ static inline TLG GetTLG(TileIndex t)
|
||||
return (TLG)((HasBit(TileX(t), 0) << 1) + HasBit(TileY(t), 0));
|
||||
}
|
||||
|
||||
struct DualTrackBits {
|
||||
TrackBitsByte primary;
|
||||
TrackBitsByte secondary;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds which Electrified Rail Bits are present on a given tile.
|
||||
* @param t tile to check
|
||||
* @param override pointer to PCP override, can be NULL
|
||||
* @return trackbits of tile if it is electrified
|
||||
*/
|
||||
static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
|
||||
static DualTrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
|
||||
{
|
||||
DualTrackBits out;
|
||||
out.primary = TRACK_BIT_NONE;
|
||||
out.secondary = TRACK_BIT_NONE;
|
||||
switch (GetTileType(t)) {
|
||||
case MP_RAILWAY:
|
||||
if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE;
|
||||
case MP_RAILWAY: {
|
||||
switch (GetRailTileType(t)) {
|
||||
case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS:
|
||||
return GetTrackBits(t);
|
||||
default:
|
||||
return TRACK_BIT_NONE;
|
||||
case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS: {
|
||||
RailType secondary = GetTileSecondaryRailTypeIfValid(t);
|
||||
TrackBits present_bits = GetTrackBits(t);
|
||||
if (secondary != INVALID_RAILTYPE) {
|
||||
if (HasRailCatenary(GetSecondaryRailType(t))) {
|
||||
out.secondary = present_bits & TRACK_BIT_RT_2;
|
||||
}
|
||||
present_bits &= TRACK_BIT_RT_1;
|
||||
}
|
||||
if (HasRailCatenary(GetRailType(t))) {
|
||||
out.primary = present_bits;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (GetTunnelBridgeTransportType(t) != TRANSPORT_RAIL) return TRACK_BIT_NONE;
|
||||
if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE;
|
||||
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
|
||||
case MP_TUNNELBRIDGE: {
|
||||
if (GetTunnelBridgeTransportType(t) != TRANSPORT_RAIL) break;
|
||||
TrackBits primary_bits = GetPrimaryTunnelBridgeTrackBits(t);
|
||||
TrackBits secondary_bits = GetSecondaryTunnelBridgeTrackBits(t);
|
||||
if (HasRailCatenary(GetRailType(t))) {
|
||||
out.primary = primary_bits;
|
||||
}
|
||||
if (secondary_bits && HasRailCatenary(GetSecondaryRailType(t))) {
|
||||
out.secondary = secondary_bits;
|
||||
}
|
||||
if ((out.primary | out.secondary) && override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
|
||||
*override = 1 << GetTunnelBridgeDirection(t);
|
||||
}
|
||||
return GetTunnelBridgeTrackBits(t);
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_ROAD:
|
||||
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
|
||||
if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE;
|
||||
return GetCrossingRailBits(t);
|
||||
if (!IsLevelCrossing(t)) break;
|
||||
if (!HasRailCatenary(GetRailType(t))) break;
|
||||
out.primary = GetCrossingRailBits(t);
|
||||
break;
|
||||
|
||||
case MP_STATION:
|
||||
if (!HasStationRail(t)) return TRACK_BIT_NONE;
|
||||
if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE;
|
||||
return TrackToTrackBits(GetRailStationTrack(t));
|
||||
if (!HasStationRail(t)) break;
|
||||
if (!HasRailCatenary(GetRailType(t))) break;
|
||||
out.primary = TrackToTrackBits(GetRailStationTrack(t));
|
||||
break;
|
||||
|
||||
default:
|
||||
return TRACK_BIT_NONE;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +166,7 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks)
|
||||
* as needing no catenary. We make an exception for blocked station tiles with a matching
|
||||
* axis that still display wires to preserve visual continuity. */
|
||||
TileIndex next_tile = TileAddByDiagDir(t, d);
|
||||
RailType rt = GetTileRailType(next_tile);
|
||||
RailType rt = GetTileRailTypeByEntryDir(next_tile, d);
|
||||
if (rt == INVALID_RAILTYPE || !HasRailCatenary(rt) ||
|
||||
((TrackStatusToTrackBits(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTracks(d)) == TRACK_BIT_NONE &&
|
||||
(!HasStationTileRail(next_tile) || GetRailStationAxis(next_tile) != DiagDirToAxis(d) || !CanStationTileHaveWires(next_tile)))) {
|
||||
@@ -173,9 +204,9 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks)
|
||||
/**
|
||||
* Get the base wire sprite to use.
|
||||
*/
|
||||
static inline SpriteID GetWireBase(TileIndex tile, TileContext context = TCX_NORMAL)
|
||||
static inline SpriteID GetWireBase(TileIndex tile, RailType rt, TileContext context = TCX_NORMAL)
|
||||
{
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
SpriteID wires = GetCustomRailSprite(rti, tile, RTSG_WIRES, context);
|
||||
return wires == 0 ? SPR_WIRE_BASE : wires;
|
||||
}
|
||||
@@ -183,9 +214,9 @@ static inline SpriteID GetWireBase(TileIndex tile, TileContext context = TCX_NOR
|
||||
/**
|
||||
* Get the base pylon sprite to use.
|
||||
*/
|
||||
static inline SpriteID GetPylonBase(TileIndex tile, TileContext context = TCX_NORMAL)
|
||||
static inline SpriteID GetPylonBase(TileIndex tile, RailType rt, TileContext context = TCX_NORMAL)
|
||||
{
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
SpriteID pylons = GetCustomRailSprite(rti, tile, RTSG_PYLONS, context);
|
||||
return pylons == 0 ? SPR_PYLON_BASE : pylons;
|
||||
}
|
||||
@@ -256,7 +287,7 @@ void DrawRailCatenaryOnTunnel(const TileInfo *ti)
|
||||
|
||||
DiagDirection dir = GetTunnelBridgeDirection(ti->tile);
|
||||
|
||||
SpriteID wire_base = GetWireBase(ti->tile);
|
||||
SpriteID wire_base = GetWireBase(ti->tile, GetRailType(ti->tile));
|
||||
|
||||
const SortableSpriteStruct *sss = &RailCatenarySpriteData_Tunnel[dir];
|
||||
const int *BB_data = _tunnel_wire_BB[dir];
|
||||
@@ -304,15 +335,52 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
|
||||
* 2) on the "far" end of a bridge head (the one that connects to bridge middle),
|
||||
* because that one is drawn on the bridge. Exception is for length 0 bridges
|
||||
* which have no middle tiles */
|
||||
trackconfig[TS_HOME] = GetRailTrackBitsUniversal(ti->tile, &OverridePCP);
|
||||
DualTrackBits home_track_config = GetRailTrackBitsUniversal(ti->tile, &OverridePCP);
|
||||
trackconfig[TS_HOME] = home_track_config.primary | home_track_config.secondary;
|
||||
wireconfig[TS_HOME] = MaskWireBits(ti->tile, trackconfig[TS_HOME]);
|
||||
/* If a track bit is present that is not in the main direction, the track is level */
|
||||
isflat[TS_HOME] = ((trackconfig[TS_HOME] & (TRACK_BIT_HORZ | TRACK_BIT_VERT)) != 0);
|
||||
|
||||
AdjustTileh(ti->tile, &tileh[TS_HOME]);
|
||||
|
||||
SpriteID pylon_normal = GetPylonBase(ti->tile);
|
||||
SpriteID pylon_halftile = (halftile_corner != CORNER_INVALID) ? GetPylonBase(ti->tile, TCX_UPPER_HALFTILE) : pylon_normal;
|
||||
SpriteID pylon_normal = 0;
|
||||
SpriteID pylon_halftile = 0;
|
||||
SpriteID pylon_normal_secondary = 0;
|
||||
SpriteID pylon_halftile_secondary = 0;
|
||||
|
||||
auto get_pylon_sprite = [&](DiagDirection edge, bool halftile) -> SpriteID {
|
||||
static const uint edge_tracks[] = {
|
||||
TRACK_BIT_UPPER | TRACK_BIT_RIGHT, // DIAGDIR_NE
|
||||
TRACK_BIT_LOWER | TRACK_BIT_RIGHT, // DIAGDIR_SE
|
||||
TRACK_BIT_LOWER | TRACK_BIT_LEFT, // DIAGDIR_SW
|
||||
TRACK_BIT_UPPER | TRACK_BIT_LEFT, // DIAGDIR_NW
|
||||
};
|
||||
if (home_track_config.secondary && (home_track_config.secondary & edge_tracks[edge])) {
|
||||
if (pylon_normal_secondary == 0) {
|
||||
pylon_normal_secondary = GetPylonBase(ti->tile, GetSecondaryRailType(ti->tile));
|
||||
}
|
||||
if (halftile) {
|
||||
if (pylon_halftile_secondary == 0) {
|
||||
pylon_halftile_secondary = (halftile_corner != CORNER_INVALID) ? GetPylonBase(ti->tile, GetSecondaryRailType(ti->tile), TCX_UPPER_HALFTILE) : pylon_normal_secondary;
|
||||
}
|
||||
return pylon_halftile_secondary;
|
||||
} else {
|
||||
return pylon_normal_secondary;
|
||||
}
|
||||
} else {
|
||||
if (pylon_normal == 0) {
|
||||
pylon_normal = GetPylonBase(ti->tile, GetRailType(ti->tile));
|
||||
}
|
||||
if (halftile) {
|
||||
if (pylon_halftile == 0) {
|
||||
pylon_halftile = (halftile_corner != CORNER_INVALID) ? GetPylonBase(ti->tile, GetRailType(ti->tile), TCX_UPPER_HALFTILE) : pylon_normal;
|
||||
}
|
||||
return pylon_halftile;
|
||||
} else {
|
||||
return pylon_normal;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
|
||||
static const uint edge_corners[] = {
|
||||
@@ -321,14 +389,15 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
|
||||
1 << CORNER_S | 1 << CORNER_W, // DIAGDIR_SW
|
||||
1 << CORNER_N | 1 << CORNER_W, // DIAGDIR_NW
|
||||
};
|
||||
SpriteID pylon_base = (halftile_corner != CORNER_INVALID && HasBit(edge_corners[i], halftile_corner)) ? pylon_halftile : pylon_normal;
|
||||
SpriteID pylon_base = get_pylon_sprite(i, halftile_corner != CORNER_INVALID && HasBit(edge_corners[i], halftile_corner));
|
||||
TileIndex neighbour = ti->tile + TileOffsByDiagDir(i);
|
||||
int elevation = GetPCPElevation(ti->tile, i);
|
||||
|
||||
/* Here's one of the main headaches. GetTileSlope does not correct for possibly
|
||||
* existing foundataions, so we do have to do that manually later on.*/
|
||||
tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour);
|
||||
trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL);
|
||||
DualTrackBits neighbour_track_config = GetRailTrackBitsUniversal(neighbour, NULL);
|
||||
trackconfig[TS_NEIGHBOUR] = neighbour_track_config.primary | neighbour_track_config.secondary;
|
||||
wireconfig[TS_NEIGHBOUR] = MaskWireBits(neighbour, trackconfig[TS_NEIGHBOUR]);
|
||||
if (IsTunnelTile(neighbour) && i != GetTunnelBridgeDirection(neighbour)) wireconfig[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE;
|
||||
|
||||
@@ -382,7 +451,7 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
|
||||
if (IsTileType(neighbour, MP_STATION) || IsTileType(neighbour, MP_ROAD)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
|
||||
|
||||
/* Read the foundations if they are present, and adjust the tileh */
|
||||
if (trackconfig[TS_NEIGHBOUR] != TRACK_BIT_NONE && IsTileType(neighbour, MP_RAILWAY) && HasRailCatenary(GetRailType(neighbour))) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
|
||||
if (trackconfig[TS_NEIGHBOUR] != TRACK_BIT_NONE && IsTileType(neighbour, MP_RAILWAY) && HasRailCatenary(GetTileRailTypeByEntryDir(neighbour, i))) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
|
||||
if (IsBridgeTile(neighbour)) {
|
||||
foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetTunnelBridgeDirection(neighbour)));
|
||||
}
|
||||
@@ -458,8 +527,6 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
|
||||
/* Don't draw a wire if the station tile does not want any */
|
||||
if (IsRailStationTile(ti->tile) && !CanStationTileHaveWires(ti->tile)) return;
|
||||
|
||||
SpriteID wire_normal = GetWireBase(ti->tile);
|
||||
SpriteID wire_halftile = (halftile_corner != CORNER_INVALID) ? GetWireBase(ti->tile, TCX_UPPER_HALFTILE) : wire_normal;
|
||||
Track halftile_track;
|
||||
switch (halftile_corner) {
|
||||
case CORNER_W: halftile_track = TRACK_LEFT; break;
|
||||
@@ -469,10 +536,43 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
|
||||
default: halftile_track = INVALID_TRACK; break;
|
||||
}
|
||||
|
||||
SpriteID wire_normal = 0;
|
||||
SpriteID wire_halftile = 0;
|
||||
SpriteID wire_normal_secondary = 0;
|
||||
SpriteID wire_halftile_secondary = 0;
|
||||
|
||||
auto get_wire_sprite = [&](Track track, bool halftile) -> SpriteID {
|
||||
if (home_track_config.secondary && HasTrack(home_track_config.secondary, track)) {
|
||||
if (wire_normal_secondary == 0) {
|
||||
wire_normal_secondary = GetWireBase(ti->tile, GetSecondaryRailType(ti->tile));
|
||||
}
|
||||
if (halftile) {
|
||||
if (wire_halftile_secondary == 0) {
|
||||
wire_halftile_secondary = (halftile_corner != CORNER_INVALID) ? GetWireBase(ti->tile, GetSecondaryRailType(ti->tile), TCX_UPPER_HALFTILE) : wire_normal_secondary;
|
||||
}
|
||||
return wire_halftile_secondary;
|
||||
} else {
|
||||
return wire_normal_secondary;
|
||||
}
|
||||
} else {
|
||||
if (wire_normal == 0) {
|
||||
wire_normal = GetWireBase(ti->tile, GetRailType(ti->tile));
|
||||
}
|
||||
if (halftile) {
|
||||
if (wire_halftile == 0) {
|
||||
wire_halftile = (halftile_corner != CORNER_INVALID) ? GetWireBase(ti->tile, GetRailType(ti->tile), TCX_UPPER_HALFTILE) : wire_normal;
|
||||
}
|
||||
return wire_halftile;
|
||||
} else {
|
||||
return wire_normal;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Drawing of pylons is finished, now draw the wires */
|
||||
Track t;
|
||||
FOR_EACH_SET_TRACK(t, wireconfig[TS_HOME]) {
|
||||
SpriteID wire_base = (t == halftile_track) ? wire_halftile : wire_normal;
|
||||
SpriteID wire_base = get_wire_sprite(t, (t == halftile_track));
|
||||
byte PCPconfig = HasBit(PCPstatus, PCPpositions[t][0]) +
|
||||
(HasBit(PCPstatus, PCPpositions[t][1]) << 1);
|
||||
|
||||
@@ -527,14 +627,14 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti)
|
||||
|
||||
height = GetBridgePixelHeight(end);
|
||||
|
||||
SpriteID wire_base = GetWireBase(end, TCX_ON_BRIDGE);
|
||||
SpriteID wire_base = GetWireBase(end, GetRailType(end), TCX_ON_BRIDGE);
|
||||
|
||||
AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset,
|
||||
sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset,
|
||||
IsTransparencySet(TO_CATENARY)
|
||||
);
|
||||
|
||||
SpriteID pylon_base = GetPylonBase(end, TCX_ON_BRIDGE);
|
||||
SpriteID pylon_base = GetPylonBase(end, GetRailType(end), TCX_ON_BRIDGE);
|
||||
|
||||
/* Finished with wires, draw pylons
|
||||
* every other tile needs a pylon on the northern end */
|
||||
@@ -570,7 +670,7 @@ void DrawRailCatenary(const TileInfo *ti)
|
||||
if (IsRailDepot(ti->tile)) {
|
||||
const SortableSpriteStruct *sss = &RailCatenarySpriteData_Depot[GetRailDepotDirection(ti->tile)];
|
||||
|
||||
SpriteID wire_base = GetWireBase(ti->tile);
|
||||
SpriteID wire_base = GetWireBase(ti->tile, GetRailType(ti->tile));
|
||||
|
||||
/* This wire is not visible with the default depot sprites */
|
||||
AddSortableSpriteToDraw(
|
||||
|
@@ -29,9 +29,9 @@ static inline bool HasRailCatenary(RailType rt)
|
||||
* Test if we should draw rail catenary
|
||||
* @param rt Rail type to test
|
||||
*/
|
||||
static inline bool HasRailCatenaryDrawn(RailType rt)
|
||||
static inline bool HasRailCatenaryDrawn(RailType rt, RailType secondary = INVALID_RAILTYPE)
|
||||
{
|
||||
return HasRailCatenary(rt) && !IsInvisibilitySet(TO_CATENARY) && !_settings_game.vehicle.disable_elrails;
|
||||
return !IsInvisibilitySet(TO_CATENARY) && !_settings_game.vehicle.disable_elrails && (HasRailCatenary(rt) || (secondary != INVALID_RAILTYPE && HasRailCatenary(secondary)));
|
||||
}
|
||||
|
||||
void DrawRailCatenary(const TileInfo *ti);
|
||||
|
@@ -173,7 +173,9 @@ public:
|
||||
td.airport_name = STR_NULL;
|
||||
td.airport_tile_name = STR_NULL;
|
||||
td.railtype = STR_NULL;
|
||||
td.railtype2 = STR_NULL;
|
||||
td.rail_speed = 0;
|
||||
td.rail_speed2 = 0;
|
||||
td.road_speed = 0;
|
||||
|
||||
td.grf = NULL;
|
||||
@@ -295,6 +297,20 @@ public:
|
||||
line_nr++;
|
||||
}
|
||||
|
||||
/* 2nd Rail type name */
|
||||
if (td.railtype2 != STR_NULL) {
|
||||
SetDParam(0, td.railtype2);
|
||||
GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_TYPE, lastof(this->landinfo_data[line_nr]));
|
||||
line_nr++;
|
||||
}
|
||||
|
||||
/* 2nd Rail speed limit */
|
||||
if (td.rail_speed2 != 0) {
|
||||
SetDParam(0, td.rail_speed2);
|
||||
GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr]));
|
||||
line_nr++;
|
||||
}
|
||||
|
||||
/* Road speed limit */
|
||||
if (td.road_speed != 0) {
|
||||
SetDParam(0, td.road_speed);
|
||||
|
@@ -609,7 +609,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
|
||||
case 0x4A: {
|
||||
if (v->type != VEH_TRAIN) return 0;
|
||||
if (Train::From(v)->IsVirtual()) return 0x1FF;
|
||||
RailType rt = GetTileRailType(v->tile);
|
||||
RailType rt = GetTileRailTypeByTrackBit(v->tile, Train::From(v)->track);
|
||||
return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile);
|
||||
}
|
||||
|
||||
@@ -707,7 +707,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
|
||||
if (u->IsVirtual()) {
|
||||
has_power = true;
|
||||
} else {
|
||||
RailType railtype = GetRailType(v->tile);
|
||||
RailType railtype = GetRailTypeByTrackBit(v->tile, t->track);
|
||||
has_power = HasPowerOnRail(u->railtype, railtype);
|
||||
}
|
||||
|
||||
|
@@ -355,7 +355,7 @@ protected:
|
||||
|
||||
/* rail transport is possible only on compatible rail types */
|
||||
if (IsRailTT()) {
|
||||
RailType rail_type = GetTileRailType(m_new_tile);
|
||||
RailType rail_type = GetTileRailTypeByEntryDir(m_new_tile, m_exitdir);
|
||||
if (!HasBit(m_railtypes, rail_type)) {
|
||||
/* incompatible rail type */
|
||||
m_err = EC_RAIL_TYPE;
|
||||
@@ -481,7 +481,7 @@ public:
|
||||
}
|
||||
/* Check for speed limit imposed by railtype */
|
||||
if (IsRailTT()) {
|
||||
uint16 rail_speed = GetRailTypeInfo(GetRailType(m_old_tile))->max_speed;
|
||||
uint16 rail_speed = GetRailTypeInfo(GetRailTypeByTrack(m_old_tile, TrackdirToTrack(m_old_td)))->max_speed;
|
||||
if (rail_speed > 0) max_speed = min(max_speed, rail_speed);
|
||||
}
|
||||
|
||||
|
@@ -788,7 +788,7 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user
|
||||
|
||||
/* check correct rail type (mono, maglev, etc) */
|
||||
if (user->type == TRANSPORT_RAIL) {
|
||||
RailType rail_type = GetTileRailType(tile);
|
||||
RailType rail_type = GetTileRailTypeByEntryDir(tile, dir);
|
||||
if (!HasBit(user->railtypes, rail_type)) return false;
|
||||
}
|
||||
|
||||
|
@@ -46,7 +46,7 @@ protected:
|
||||
this->tile = tile;
|
||||
this->td = td;
|
||||
this->tile_type = GetTileType(tile);
|
||||
this->rail_type = GetTileRailType(tile);
|
||||
this->rail_type = GetTileRailTypeByTrack(tile, TrackdirToTrack(td));
|
||||
}
|
||||
|
||||
TILE(const TILE &src)
|
||||
|
96
src/rail.cpp
96
src/rail.cpp
@@ -179,6 +179,102 @@ RailType GetTileRailType(TileIndex tile)
|
||||
return INVALID_RAILTYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rail type of tile and track piece, or INVALID_RAILTYPE if this is no rail tile and return_invalid is true.
|
||||
*/
|
||||
RailType GenericGetRailTypeByTrack(TileIndex t, Track track, bool return_invalid)
|
||||
{
|
||||
if (IsPlainRailTile(t)) {
|
||||
TrackBits bits = GetTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (TrackToTrackBits(track) & TRACK_BIT_RT_1) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else if (IsRailTunnelBridgeTile(t)) {
|
||||
TrackBits bits = GetTunnelBridgeTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (TrackToTrackBits(track) & GetAcrossBridgePossibleTrackBits(t)) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else {
|
||||
return return_invalid ? GetTileRailType(t) : GetRailType(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rail type of tile and track piece, or INVALID_RAILTYPE if this is no rail tile and return_invalid is true.
|
||||
*/
|
||||
RailType GenericGetRailTypeByTrackBit(TileIndex t, TrackBits tb, bool return_invalid)
|
||||
{
|
||||
if (IsPlainRailTile(t)) {
|
||||
TrackBits bits = GetTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (tb & TRACK_BIT_RT_1) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else if (IsRailTunnelBridgeTile(t)) {
|
||||
TrackBits bits = GetTunnelBridgeTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (tb & GetAcrossBridgePossibleTrackBits(t)) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else {
|
||||
return return_invalid ? GetTileRailType(t) : GetRailType(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rail type of tile and entrance direction, or INVALID_RAILTYPE if this is no rail tile and return_invalid is true.
|
||||
*/
|
||||
RailType GenericGetRailTypeByEntryDir(TileIndex t, DiagDirection enterdir, bool return_invalid)
|
||||
{
|
||||
if (IsPlainRailTile(t)) {
|
||||
TrackBits bits = GetTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (bits & DiagdirReachesTracks(enterdir) & TRACK_BIT_RT_1) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else if (IsRailTunnelBridgeTile(t)) {
|
||||
TrackBits bits = GetTunnelBridgeTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return (bits & DiagdirReachesTracks(enterdir) & GetAcrossBridgePossibleTrackBits(t)) ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
} else {
|
||||
return GetRailType(t);
|
||||
}
|
||||
} else {
|
||||
return return_invalid ? GetTileRailType(t) : GetRailType(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the secondary rail type of tile, or INVALID_RAILTYPE if this tile has no secondary rail type
|
||||
*/
|
||||
RailType GetTileSecondaryRailTypeIfValid(TileIndex t)
|
||||
{
|
||||
if (IsPlainRailTile(t)) {
|
||||
TrackBits bits = GetTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return GetSecondaryRailType(t);
|
||||
} else {
|
||||
return INVALID_RAILTYPE;
|
||||
}
|
||||
} else if (IsRailTunnelBridgeTile(t)) {
|
||||
TrackBits bits = GetTunnelBridgeTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return GetSecondaryRailType(t);
|
||||
} else {
|
||||
return INVALID_RAILTYPE;
|
||||
}
|
||||
} else {
|
||||
return INVALID_RAILTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out if a company has a certain railtype available
|
||||
* @param company the company in question
|
||||
|
@@ -296,7 +296,7 @@ public:
|
||||
static inline const RailtypeInfo *GetRailTypeInfo(RailType railtype)
|
||||
{
|
||||
extern RailtypeInfo _railtypes[RAILTYPE_END];
|
||||
assert(railtype < RAILTYPE_END);
|
||||
assert_msg(railtype < RAILTYPE_END, "%u", railtype);
|
||||
return &_railtypes[railtype];
|
||||
}
|
||||
|
||||
|
346
src/rail_cmd.cpp
346
src/rail_cmd.cpp
@@ -242,10 +242,12 @@ static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track)
|
||||
* Check that the new track bits may be built.
|
||||
* @param tile %Tile to build on.
|
||||
* @param to_build New track bits.
|
||||
* @param railtype New rail type.
|
||||
* @param disable_dual_rail_type Whether dual rail types are disabled.
|
||||
* @param flags Flags of the operation.
|
||||
* @return Succeeded or failed command.
|
||||
*/
|
||||
static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
|
||||
static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, RailType railtype, bool disable_dual_rail_type, DoCommandFlag flags)
|
||||
{
|
||||
if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
|
||||
@@ -257,7 +259,25 @@ static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uin
|
||||
/* Are we really building something new? */
|
||||
if (current == future) {
|
||||
/* Nothing new is being built */
|
||||
if (IsCompatibleRail(GetTileRailTypeByTrackBit(tile, to_build), railtype)) {
|
||||
return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||
} else {
|
||||
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
}
|
||||
}
|
||||
|
||||
/* These combinations are always allowed, unless disable_dual_rail_type is set */
|
||||
if ((future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT) && !disable_dual_rail_type) {
|
||||
if (flags & DC_EXEC) {
|
||||
if (to_build & TRACK_BIT_RT_1) {
|
||||
RailType current_rt = GetRailType(tile);
|
||||
SetRailType(tile, railtype);
|
||||
SetSecondaryRailType(tile, current_rt);
|
||||
} else {
|
||||
SetSecondaryRailType(tile, railtype);
|
||||
}
|
||||
}
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/* Let's see if we may build this */
|
||||
@@ -268,8 +288,73 @@ static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uin
|
||||
return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
|
||||
}
|
||||
}
|
||||
/* Normally, we may overlap and any combination is valid */
|
||||
return CommandCost();
|
||||
|
||||
RailType rt = INVALID_RAILTYPE;
|
||||
if (current == TRACK_BIT_HORZ || current == TRACK_BIT_VERT) {
|
||||
RailType rt1 = GetRailType(tile);
|
||||
if (!IsCompatibleRail(rt1, railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
|
||||
RailType rt2 = GetSecondaryRailType(tile);
|
||||
if (!IsCompatibleRail(rt2, railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
|
||||
if (rt1 != rt2) {
|
||||
/* Two different railtypes present */
|
||||
if ((railtype == rt1 || HasPowerOnRail(rt1, railtype)) && (railtype == rt2 || HasPowerOnRail(rt2, railtype))) {
|
||||
rt = railtype;
|
||||
} else if ((railtype == rt1 || HasPowerOnRail(railtype, rt1)) && HasPowerOnRail(rt2, rt1)) {
|
||||
rt = railtype = rt1;
|
||||
} else if ((railtype == rt2 || HasPowerOnRail(railtype, rt2)) && HasPowerOnRail(rt1, rt2)) {
|
||||
rt = railtype = rt2;
|
||||
} else {
|
||||
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
}
|
||||
} else if (railtype == rt1) {
|
||||
/* Nothing to do */
|
||||
rt = INVALID_RAILTYPE;
|
||||
} else if (HasPowerOnRail(railtype, rt1)) {
|
||||
/* Try to keep existing railtype */
|
||||
railtype = rt1;
|
||||
rt = INVALID_RAILTYPE;
|
||||
} else if (HasPowerOnRail(rt1, railtype)) {
|
||||
rt = railtype;
|
||||
} else {
|
||||
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
}
|
||||
} else {
|
||||
rt = GetRailType(tile);
|
||||
|
||||
if (railtype == rt) {
|
||||
/* Nothing to do */
|
||||
rt = INVALID_RAILTYPE;
|
||||
} else if (!IsCompatibleRail(rt, railtype)) {
|
||||
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
} else if (HasPowerOnRail(railtype, rt)) {
|
||||
/* Try to keep existing railtype */
|
||||
railtype = rt;
|
||||
rt = INVALID_RAILTYPE;
|
||||
} else if (HasPowerOnRail(rt, railtype)) {
|
||||
rt = railtype;
|
||||
} else {
|
||||
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
}
|
||||
}
|
||||
|
||||
CommandCost ret;
|
||||
if (rt != INVALID_RAILTYPE) {
|
||||
ret = DoCommand(tile, tile, rt, flags, CMD_CONVERT_RAIL);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
|
||||
if (HasSignalOnTrack(tile, TRACK_UPPER) || HasSignalOnTrack(tile, TRACK_LOWER)) {
|
||||
return_cmd_error(STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SetRailType(tile, railtype);
|
||||
SetSecondaryRailType(tile, railtype);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -462,6 +547,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
RailType railtype = Extract<RailType, 0, 6>(p1);
|
||||
Track track = Extract<Track, 0, 3>(p2);
|
||||
bool disable_custom_bridge_heads = HasBit(p2, 4);
|
||||
bool disable_dual_rail_type = HasBit(p2, 5);
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
|
||||
_rail_track_endtile = INVALID_TILE;
|
||||
@@ -478,10 +564,11 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
|
||||
if (!IsPlainRail(tile)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
|
||||
if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
|
||||
ret = CheckTrackCombination(tile, trackbit, flags);
|
||||
if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
|
||||
ret = CheckTrackCombination(tile, trackbit, railtype, disable_dual_rail_type, flags);
|
||||
if (ret.Succeeded()) {
|
||||
cost.AddCost(ret);
|
||||
ret = EnsureNoTrainOnTrack(tile, track);
|
||||
}
|
||||
if (ret.Failed()) {
|
||||
if (ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) _rail_track_endtile = tile;
|
||||
return ret;
|
||||
@@ -491,31 +578,23 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret);
|
||||
|
||||
/* If the rail types don't match, try to convert only if engines of
|
||||
* the new rail type are not powered on the present rail type and engines of
|
||||
* the present rail type are powered on the new rail type. */
|
||||
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
|
||||
if (HasPowerOnRail(GetRailType(tile), railtype)) {
|
||||
ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret);
|
||||
} else {
|
||||
return CMD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SetRailGroundType(tile, RAIL_GROUND_BARREN);
|
||||
TrackBits bits = GetTrackBits(tile);
|
||||
SetTrackBits(tile, bits | trackbit);
|
||||
TrackBits newbits = bits | trackbit;
|
||||
SetTrackBits(tile, newbits);
|
||||
if (newbits == TRACK_BIT_HORZ || newbits == TRACK_BIT_VERT) {
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetPlainRailParallelTrackRailTypeByTrackBit(tile, trackbit)]++;
|
||||
} else {
|
||||
/* Subtract old infrastructure count. */
|
||||
uint pieces = CountBits(bits);
|
||||
if (TracksOverlap(bits)) pieces *= pieces;
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
|
||||
/* Add new infrastructure count. */
|
||||
pieces = CountBits(bits | trackbit);
|
||||
if (TracksOverlap(bits | trackbit)) pieces *= pieces;
|
||||
pieces = CountBits(newbits);
|
||||
if (TracksOverlap(newbits)) pieces *= pieces;
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
|
||||
}
|
||||
break;
|
||||
@@ -527,14 +606,22 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
|
||||
if (disable_custom_bridge_heads || !_settings_game.construction.rail_custom_bridge_heads || !IsFlatRailBridgeHeadTile(tile)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
|
||||
if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) return_cmd_error(STR_ERROR_CAN_T_CONVERT_RAIL);
|
||||
|
||||
const DiagDirection entrance_dir = GetTunnelBridgeDirection(tile);
|
||||
const TrackBits axial_track = DiagDirToDiagTrackBits(entrance_dir);
|
||||
const TrackBits existing = GetCustomBridgeHeadTrackBits(tile);
|
||||
const TrackBits future = existing | trackbit;
|
||||
|
||||
const bool secondary_piece = ((future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT) && (future != existing));
|
||||
|
||||
if (!secondary_piece && !disable_dual_rail_type) {
|
||||
if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) return_cmd_error(STR_ERROR_CAN_T_CONVERT_RAIL);
|
||||
if (GetSecondaryTunnelBridgeTrackBits(tile) != TRACK_BIT_NONE) {
|
||||
if (!IsCompatibleRail(GetSecondaryRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetSecondaryRailType(tile))) return_cmd_error(STR_ERROR_CAN_T_CONVERT_RAIL);
|
||||
}
|
||||
}
|
||||
|
||||
if (existing == future) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||
|
||||
if (flags & DC_NO_RAIL_OVERLAP || IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
@@ -555,12 +642,18 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
}
|
||||
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (!secondary_piece) {
|
||||
ret = TunnelBridgeIsFree(tile, other_end);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SubtractRailTunnelBridgeInfrastructure(tile, other_end);
|
||||
SetCustomBridgeHeadTrackBits(tile, future);
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(existing);
|
||||
if (secondary_piece) {
|
||||
SetSecondaryRailType(tile, railtype);
|
||||
}
|
||||
AddRailTunnelBridgeInfrastructure(tile, other_end);
|
||||
DirtyCompanyInfrastructureWindows(_current_company);
|
||||
}
|
||||
|
||||
@@ -741,7 +834,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
|
||||
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)));
|
||||
cost.AddCost(RailClearCost(GetTileRailTypeByTrackBit(tile, trackbit)));
|
||||
|
||||
/* Charge extra to remove signals on the track, if they are there */
|
||||
if (HasSignalOnTrack(tile, track)) {
|
||||
@@ -757,6 +850,11 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
|
||||
owner = GetTileOwner(tile);
|
||||
|
||||
if (present == TRACK_BIT_HORZ || present == TRACK_BIT_VERT) {
|
||||
Company::Get(owner)->infrastructure.rail[GetTileRailTypeByTrackBit(tile, trackbit)]--;
|
||||
present ^= trackbit;
|
||||
SetRailType(tile, GetTileRailTypeByTrackBit(tile, present));
|
||||
} else {
|
||||
/* Subtract old infrastructure count. */
|
||||
uint pieces = CountBits(present);
|
||||
if (TracksOverlap(present)) pieces *= pieces;
|
||||
@@ -766,6 +864,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
pieces = CountBits(present);
|
||||
if (TracksOverlap(present)) pieces *= pieces;
|
||||
Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
|
||||
if (present == 0) {
|
||||
@@ -802,12 +901,17 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
if ((GetAcrossBridgePossibleTrackBits(tile) & future) == 0) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (present == TRACK_BIT_HORZ || present == TRACK_BIT_VERT) {
|
||||
ret = EnsureNoTrainOnTrack(tile, track);
|
||||
} else {
|
||||
ret = TunnelBridgeIsFree(tile, other_end);
|
||||
}
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)));
|
||||
cost.AddCost(RailClearCost(GetTileRailTypeByTrackBit(tile, trackbit)));
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SubtractRailTunnelBridgeInfrastructure(tile, other_end);
|
||||
owner = GetTileOwner(tile);
|
||||
|
||||
if (HasReservedTracks(tile, trackbit)) {
|
||||
@@ -816,7 +920,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
}
|
||||
|
||||
SetCustomBridgeHeadTrackBits(tile, future);
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(present) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future);
|
||||
AddRailTunnelBridgeInfrastructure(tile, other_end);
|
||||
DirtyCompanyInfrastructureWindows(_current_company);
|
||||
}
|
||||
|
||||
@@ -983,6 +1087,7 @@ static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint3
|
||||
bool remove = HasBit(p2, 9);
|
||||
bool fail_if_obstacle = HasBit(p2, 10);
|
||||
bool no_custom_bridge_heads = HasBit(p2, 11);
|
||||
bool no_dual_rail_type = HasBit(p2, 12);
|
||||
|
||||
_rail_track_endtile = INVALID_TILE;
|
||||
|
||||
@@ -998,7 +1103,7 @@ static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint3
|
||||
CommandCost last_error = CMD_ERROR;
|
||||
for (;;) {
|
||||
TileIndex last_endtile = _rail_track_endtile;
|
||||
CommandCost ret = DoCommand(tile, remove ? 0 : railtype, TrackdirToTrack(trackdir) | (no_custom_bridge_heads ? 1 << 4 : 0), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
|
||||
CommandCost ret = DoCommand(tile, remove ? 0 : railtype, TrackdirToTrack(trackdir) | (no_custom_bridge_heads ? 1 << 4 : 0) | (no_dual_rail_type ? 1 << 5 : 0), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
|
||||
|
||||
if (ret.Failed()) {
|
||||
last_error = ret;
|
||||
@@ -1924,10 +2029,13 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
|
||||
/* Original railtype we are converting from */
|
||||
RailType type = GetRailType(tile);
|
||||
const RailType type = GetRailType(tile);
|
||||
const RailType raw_secondary_type = GetTileSecondaryRailTypeIfValid(tile);
|
||||
const RailType secondary_type = (raw_secondary_type == INVALID_RAILTYPE) ? type : raw_secondary_type;
|
||||
|
||||
/* Converting to the same type or converting 'hidden' elrail -> rail */
|
||||
if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
|
||||
if ((type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC))
|
||||
&& (secondary_type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && secondary_type == RAILTYPE_ELECTRIC))) continue;
|
||||
|
||||
/* Trying to convert other's rail */
|
||||
CommandCost ret = CheckTileOwnership(tile);
|
||||
@@ -1959,7 +2067,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
/* Vehicle on the tile when not converting Rail <-> ElRail
|
||||
* Tunnels and bridges have special check later */
|
||||
if (tt != MP_TUNNELBRIDGE) {
|
||||
if (!IsCompatibleRail(type, totype)) {
|
||||
if (!IsCompatibleRail(type, totype) || !IsCompatibleRail(secondary_type, totype)) {
|
||||
CommandCost ret = IsPlainRailTile(tile) ? EnsureNoTrainOnTrackBits(tile, GetTrackBits(tile)) : EnsureNoVehicleOnGround(tile);
|
||||
if (ret.Failed()) {
|
||||
error = ret;
|
||||
@@ -1975,15 +2083,22 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
|
||||
if (IsPlainRailTile(tile)) {
|
||||
TrackBits bits = GetTrackBits(tile);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
c->infrastructure.rail[secondary_type]--;
|
||||
c->infrastructure.rail[totype]++;
|
||||
} else {
|
||||
num_pieces = CountBits(bits);
|
||||
if (TracksOverlap(bits)) num_pieces *= num_pieces;
|
||||
}
|
||||
}
|
||||
c->infrastructure.rail[type] -= num_pieces;
|
||||
c->infrastructure.rail[totype] += num_pieces;
|
||||
DirtyCompanyInfrastructureWindows(c->index);
|
||||
}
|
||||
|
||||
SetRailType(tile, totype);
|
||||
if (IsPlainRailTile(tile)) SetSecondaryRailType(tile, totype);
|
||||
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
/* update power of train on this tile */
|
||||
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
|
||||
@@ -2010,7 +2125,12 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
/* notify YAPF about the track layout change */
|
||||
yapf_notify_track_change(tile, GetTrackBits(tile));
|
||||
}
|
||||
if (raw_secondary_type != INVALID_RAILTYPE) {
|
||||
cost.AddCost(RailConvertCost(type, totype));
|
||||
cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
||||
} else {
|
||||
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -2029,7 +2149,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
|
||||
/* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
|
||||
if (!IsCompatibleRail(GetRailType(tile), totype)) {
|
||||
if (!IsCompatibleRail(type, totype) || !IsCompatibleRail(secondary_type, totype)) {
|
||||
CommandCost ret = TunnelBridgeIsFree(tile, endtile);
|
||||
if (ret.Failed()) {
|
||||
error = ret;
|
||||
@@ -2037,22 +2157,22 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
}
|
||||
|
||||
uint middle_len = GetTunnelBridgeLength(tile, endtile);
|
||||
uint num_raw_pieces = middle_len + CountBits(GetTunnelBridgeTrackBits(tile)) + CountBits(GetTunnelBridgeTrackBits(endtile));
|
||||
uint num_primary_pieces = GetTunnelBridgeLength(tile, endtile) + CountBits(GetPrimaryTunnelBridgeTrackBits(tile)) + CountBits(GetPrimaryTunnelBridgeTrackBits(endtile));
|
||||
cost.AddCost(num_primary_pieces * RailConvertCost(type, totype));
|
||||
RailType end_secondary_type = GetTileSecondaryRailTypeIfValid(endtile);
|
||||
if (raw_secondary_type != INVALID_RAILTYPE) cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
||||
if (end_secondary_type != INVALID_RAILTYPE) cost.AddCost(RailConvertCost(end_secondary_type, totype));
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SubtractRailTunnelBridgeInfrastructure(tile, endtile);
|
||||
|
||||
find_train_reservations(tile, GetTunnelBridgeReservationTrackBits(tile));
|
||||
find_train_reservations(endtile, GetTunnelBridgeReservationTrackBits(endtile));
|
||||
|
||||
/* Update the company infrastructure counters. */
|
||||
uint num_infra_pieces = (middle_len* TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
|
||||
Company *c = Company::Get(GetTileOwner(tile));
|
||||
c->infrastructure.rail[GetRailType(tile)] -= num_infra_pieces;
|
||||
c->infrastructure.rail[totype] += num_infra_pieces;
|
||||
DirtyCompanyInfrastructureWindows(c->index);
|
||||
|
||||
SetRailType(tile, totype);
|
||||
SetRailType(endtile, totype);
|
||||
SetSecondaryRailType(tile, totype);
|
||||
SetSecondaryRailType(endtile, totype);
|
||||
|
||||
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
|
||||
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
|
||||
@@ -2067,9 +2187,10 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
MarkTileDirtyByTile(endtile, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
cost.AddCost(num_raw_pieces * RailConvertCost(type, totype));
|
||||
AddRailTunnelBridgeInfrastructure(tile, endtile);
|
||||
DirtyCompanyInfrastructureWindows(Company::Get(GetTileOwner(tile))->index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2455,24 +2576,13 @@ static RailGroundType GetRailOrBridgeGroundType(TileInfo *ti) {
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
|
||||
static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti, RailGroundType rgt, bool is_bridge, Corner halftile_corner, Corner draw_half_tile)
|
||||
{
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||
Corner halftile_corner = CORNER_INVALID;
|
||||
|
||||
if (IsNonContinuousFoundation(f)) {
|
||||
/* Save halftile corner */
|
||||
halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
|
||||
/* Draw lower part first */
|
||||
track &= ~CornerToTrackBits(halftile_corner);
|
||||
f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
|
||||
}
|
||||
|
||||
DrawFoundation(ti, f);
|
||||
/* DrawFoundation modifies ti */
|
||||
const SubSprite *sub = NULL;
|
||||
if (draw_half_tile != CORNER_INVALID) sub = &(_halftile_sub_sprite[draw_half_tile]);
|
||||
if (halftile_corner != CORNER_INVALID) track &= ~CornerToTrackBits(halftile_corner);
|
||||
|
||||
if (halftile_corner != CORNER_INVALID || draw_half_tile == CORNER_INVALID) {
|
||||
/* Draw ground */
|
||||
if (rgt == RAIL_GROUND_WATER) {
|
||||
if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
|
||||
@@ -2493,7 +2603,8 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
||||
|
||||
image += SlopeToSpriteOffset(ti->tileh);
|
||||
|
||||
DrawGroundSprite(image, PAL_NONE);
|
||||
DrawGroundSprite(image, PAL_NONE, sub);
|
||||
}
|
||||
}
|
||||
|
||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||
@@ -2568,7 +2679,7 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
||||
if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
|
||||
}
|
||||
|
||||
if (IsValidCorner(halftile_corner)) {
|
||||
if (IsValidCorner(halftile_corner) && (draw_half_tile == halftile_corner || draw_half_tile == CORNER_INVALID)) {
|
||||
DrawFoundation(ti, HalftileFoundation(halftile_corner));
|
||||
overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
|
||||
ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
|
||||
@@ -2610,39 +2721,31 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
||||
* Draw ground sprite and track bits
|
||||
* @param ti TileInfo
|
||||
* @param track TrackBits to draw
|
||||
* @param rt Rail type
|
||||
* @param half_tile Half tile corner
|
||||
*/
|
||||
void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
void DrawTrackBits(TileInfo *ti, TrackBits track, RailType rt, RailGroundType rgt, bool is_bridge, Corner halftile_corner, Corner draw_half_tile)
|
||||
{
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
|
||||
if (rti->UsesOverlay()) {
|
||||
DrawTrackBitsOverlay(ti, track, rti);
|
||||
DrawTrackBitsOverlay(ti, track, rti, rgt, is_bridge, halftile_corner, draw_half_tile);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||
Corner halftile_corner = CORNER_INVALID;
|
||||
|
||||
if (IsNonContinuousFoundation(f)) {
|
||||
/* Save halftile corner */
|
||||
halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
|
||||
/* Draw lower part first */
|
||||
track &= ~CornerToTrackBits(halftile_corner);
|
||||
f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
|
||||
}
|
||||
|
||||
DrawFoundation(ti, f);
|
||||
/* DrawFoundation modifies ti */
|
||||
|
||||
SpriteID image;
|
||||
PaletteID pal = PAL_NONE;
|
||||
const SubSprite *sub = NULL;
|
||||
bool junction = false;
|
||||
|
||||
if (halftile_corner != CORNER_INVALID) track &= ~CornerToTrackBits(halftile_corner);
|
||||
|
||||
if (draw_half_tile != CORNER_INVALID) sub = &(_halftile_sub_sprite[draw_half_tile]);
|
||||
|
||||
/* Select the sprite to use. */
|
||||
if (track == 0) {
|
||||
if (track == 0 && draw_half_tile != CORNER_INVALID) {
|
||||
image = 0;
|
||||
} else if (track == 0) {
|
||||
/* Clear ground (only track on halftile foundation) */
|
||||
if (rgt == RAIL_GROUND_WATER) {
|
||||
if (IsSteepSlope(ti->tileh)) {
|
||||
@@ -2734,7 +2837,7 @@ void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
|
||||
}
|
||||
|
||||
if (IsValidCorner(halftile_corner)) {
|
||||
if (IsValidCorner(halftile_corner) && (draw_half_tile == halftile_corner || draw_half_tile == CORNER_INVALID)) {
|
||||
DrawFoundation(ti, HalftileFoundation(halftile_corner));
|
||||
|
||||
/* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
|
||||
@@ -2756,6 +2859,62 @@ void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
{
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||
Corner halftile_corner = CORNER_INVALID;
|
||||
|
||||
if (IsNonContinuousFoundation(f)) {
|
||||
/* Save halftile corner */
|
||||
halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
|
||||
/* Draw lower part first */
|
||||
f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
|
||||
}
|
||||
|
||||
DrawFoundation(ti, f);
|
||||
/* DrawFoundation modifies ti */
|
||||
|
||||
RailType rt1 = GetRailType(ti->tile);
|
||||
RailType rt2 = GetTileSecondaryRailTypeIfValid(ti->tile);
|
||||
if (rt2 == INVALID_RAILTYPE || rt1 == rt2) {
|
||||
DrawTrackBits(ti, track, rt1, rgt, is_bridge, halftile_corner, CORNER_INVALID);
|
||||
} else {
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
TrackBits primary_track = track & (is_bridge ? GetAcrossBridgePossibleTrackBits(ti->tile) : TRACK_BIT_RT_1);
|
||||
TrackBits secondary_track = track ^ primary_track;
|
||||
assert((primary_track & (TRACK_BIT_HORZ | TRACK_BIT_VERT)) == primary_track);
|
||||
assert((primary_track & (primary_track - 1)) == 0);
|
||||
Track primary = FindFirstTrack(primary_track);
|
||||
|
||||
// TRACK_UPPER 2 -> CORNER_N 3
|
||||
// TRACK_LOWER 3 -> CORNER_S 1
|
||||
// TRACK_LEFT 4 -> CORNER_W 0
|
||||
// TRACK_RIGHT 5 -> CORNER_E 2
|
||||
Corner primary_corner = (Corner) ((0x870 >> (primary * 2)) & 3);
|
||||
if (halftile_corner == primary_corner) {
|
||||
std::swap(primary_track, secondary_track);
|
||||
std::swap(rt1, rt2);
|
||||
primary_corner = OppositeCorner(primary_corner);
|
||||
}
|
||||
if (halftile_corner == CORNER_INVALID) {
|
||||
// draw ground sprite
|
||||
SpriteID image;
|
||||
|
||||
switch (rgt) {
|
||||
case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
|
||||
case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
|
||||
default: image = SPR_FLAT_GRASS_TILE; break;
|
||||
}
|
||||
image += SlopeToSpriteOffset(ti->tileh);
|
||||
DrawGroundSprite(image, PAL_NONE);
|
||||
}
|
||||
DrawTrackBits(ti, primary_track, rt1, rgt, is_bridge, halftile_corner, primary_corner);
|
||||
DrawTrackBits(ti, secondary_track, rt2, rgt, is_bridge, halftile_corner, OppositeCorner(primary_corner));
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSignals(TileIndex tile, TrackBits rails, const RailtypeInfo *rti)
|
||||
{
|
||||
#define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, rti, t, GetSingleSignalState(tile, x), y, z)
|
||||
@@ -2801,7 +2960,7 @@ static void DrawTile_Track(TileInfo *ti)
|
||||
|
||||
if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
|
||||
|
||||
if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti);
|
||||
if (HasRailCatenaryDrawn(GetRailType(ti->tile), GetTileSecondaryRailTypeIfValid(ti->tile))) DrawRailCatenary(ti);
|
||||
|
||||
if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti);
|
||||
} else {
|
||||
@@ -3178,9 +3337,16 @@ static bool ClickTile_Track(TileIndex tile)
|
||||
|
||||
static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
|
||||
{
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
|
||||
RailType rt = GetRailType(tile);
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
td->rail_speed = rti->max_speed;
|
||||
td->railtype = rti->strings.name;
|
||||
RailType secondary_rt = GetTileSecondaryRailTypeIfValid(tile);
|
||||
if (secondary_rt != rt && secondary_rt != INVALID_RAILTYPE) {
|
||||
const RailtypeInfo *secondary_rti = GetRailTypeInfo(secondary_rt);
|
||||
td->rail_speed2 = secondary_rti->max_speed;
|
||||
td->railtype2 = secondary_rti->strings.name;
|
||||
}
|
||||
td->owner[0] = GetTileOwner(tile);
|
||||
switch (GetRailTileType(tile)) {
|
||||
case RAIL_TILE_NORMAL:
|
||||
@@ -3298,9 +3464,15 @@ static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_own
|
||||
uint num_pieces = 1;
|
||||
if (IsPlainRail(tile)) {
|
||||
TrackBits bits = GetTrackBits(tile);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
RailType secondary_rt = GetSecondaryRailType(tile);
|
||||
Company::Get(old_owner)->infrastructure.rail[secondary_rt]--;
|
||||
Company::Get(new_owner)->infrastructure.rail[secondary_rt]++;
|
||||
} else {
|
||||
num_pieces = CountBits(bits);
|
||||
if (TracksOverlap(bits)) num_pieces *= num_pieces;
|
||||
}
|
||||
}
|
||||
RailType rt = GetRailType(tile);
|
||||
Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
|
||||
Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
|
||||
|
@@ -129,6 +129,35 @@ static inline void SetRailType(TileIndex t, RailType r)
|
||||
SB(_me[t].m8, 0, 6, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second rail type of the given tile
|
||||
* @param t the tile to get the rail type from
|
||||
* @return the rail type of the tile
|
||||
*/
|
||||
static inline RailType GetSecondaryRailType(TileIndex t)
|
||||
{
|
||||
return (RailType)GB(_me[t].m8, 6, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the second rail type of the given tile
|
||||
* @param t the tile to set the rail type of
|
||||
* @param r the new rail type for the tile
|
||||
*/
|
||||
static inline void SetSecondaryRailType(TileIndex t, RailType r)
|
||||
{
|
||||
SB(_me[t].m8, 6, 6, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second rail type of the given tile
|
||||
* @param t the tile to get the rail type from
|
||||
* @return the rail type of the tile
|
||||
*/
|
||||
static inline RailType GetPlainRailParallelTrackRailTypeByTrackBit(TileIndex t, TrackBits b)
|
||||
{
|
||||
return b & TRACK_BIT_RT_1 ? GetRailType(t) : GetSecondaryRailType(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the track bits of the given tile
|
||||
@@ -513,6 +542,18 @@ static inline void SetRestrictedSignal(TileIndex tile, bool is_restricted)
|
||||
|
||||
|
||||
RailType GetTileRailType(TileIndex tile);
|
||||
RailType GenericGetRailTypeByTrack(TileIndex t, Track track, bool return_invalid);
|
||||
RailType GenericGetRailTypeByTrackBit(TileIndex t, TrackBits track, bool return_invalid);
|
||||
RailType GenericGetRailTypeByEntryDir(TileIndex t, DiagDirection enterdir, bool return_invalid);
|
||||
RailType GetTileSecondaryRailTypeIfValid(TileIndex t);
|
||||
|
||||
static inline RailType GetTileRailTypeByTrack(TileIndex t, Track track) { return GenericGetRailTypeByTrack(t, track, true); }
|
||||
static inline RailType GetTileRailTypeByTrackBit(TileIndex t, TrackBits track) { return GenericGetRailTypeByTrackBit(t, track, true); }
|
||||
static inline RailType GetTileRailTypeByEntryDir(TileIndex t, DiagDirection enterdir) { return GenericGetRailTypeByEntryDir(t, enterdir, true); }
|
||||
|
||||
static inline RailType GetRailTypeByTrack(TileIndex t, Track track) { return GenericGetRailTypeByTrack(t, track, false); }
|
||||
static inline RailType GetRailTypeByTrackBit(TileIndex t, TrackBits track) { return GenericGetRailTypeByTrackBit(t, track, false); }
|
||||
static inline RailType GetRailTypeByEntryDir(TileIndex t, DiagDirection enterdir) { return GenericGetRailTypeByEntryDir(t, enterdir, false); }
|
||||
|
||||
/** The ground 'under' the rail */
|
||||
enum RailGroundType {
|
||||
|
@@ -1410,6 +1410,15 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeatureMissing(XSLFI_DUAL_RAIL_TYPES)) {
|
||||
/* Introduced dual rail types. */
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsPlainRailTile(t) || (IsRailTunnelBridgeTile(t) && IsBridge(t))) {
|
||||
SetSecondaryRailType(t, GetRailType(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeaturePresent(XSLFI_SIG_TUNNEL_BRIDGE, 1, 6)) {
|
||||
/* m2 signal state bit allocation has shrunk */
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
|
@@ -116,9 +116,13 @@ void AfterLoadCompanyStats()
|
||||
uint pieces = 1;
|
||||
if (IsPlainRail(tile)) {
|
||||
TrackBits bits = GetTrackBits(tile);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
c->infrastructure.rail[GetSecondaryRailType(tile)]++;
|
||||
} else {
|
||||
pieces = CountBits(bits);
|
||||
if (TracksOverlap(bits)) pieces *= pieces;
|
||||
}
|
||||
}
|
||||
c->infrastructure.rail[GetRailType(tile)] += pieces;
|
||||
|
||||
if (HasSignals(tile)) c->infrastructure.signal += CountBits(GetPresentSignals(tile));
|
||||
@@ -205,13 +209,7 @@ void AfterLoadCompanyStats()
|
||||
|
||||
switch (GetTunnelBridgeTransportType(tile)) {
|
||||
case TRANSPORT_RAIL:
|
||||
c = Company::GetIfValid(GetTileOwner(tile));
|
||||
if (c != NULL) {
|
||||
c->infrastructure.rail[GetRailType(tile)] += middle_len + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(other_end);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
c->infrastructure.signal += GetTunnelBridgeSignalSimulationSignalCount(tile, other_end);
|
||||
}
|
||||
}
|
||||
AddRailTunnelBridgeInfrastructure(tile, other_end);
|
||||
break;
|
||||
|
||||
case TRANSPORT_ROAD: {
|
||||
|
@@ -90,6 +90,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_ST_LAST_VEH_TYPE, XSCF_NULL, 1, 1, "station_last_veh_type", NULL, NULL, NULL },
|
||||
{ XSLFI_SELL_AT_DEPOT_ORDER, XSCF_NULL, 1, 1, "sell_at_depot_order", NULL, NULL, NULL },
|
||||
{ XSLFI_BUY_LAND_RATE_LIMIT, XSCF_NULL, 1, 1, "buy_land_rate_limit", NULL, NULL, NULL },
|
||||
{ XSLFI_DUAL_RAIL_TYPES, XSCF_NULL, 1, 1, "dual_rail_types", NULL, NULL, NULL },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
||||
};
|
||||
|
||||
|
@@ -64,6 +64,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_ST_LAST_VEH_TYPE, ///< Per-cargo station last vehicle type
|
||||
XSLFI_SELL_AT_DEPOT_ORDER, ///< Sell vehicle on arrival at depot orders
|
||||
XSLFI_BUY_LAND_RATE_LIMIT, ///< Buy land rate limit
|
||||
XSLFI_DUAL_RAIL_TYPES, ///< Two rail-types per tile
|
||||
|
||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
||||
|
@@ -63,7 +63,9 @@ struct TileDesc {
|
||||
const char *grf; ///< newGRF used for the tile contents
|
||||
uint64 dparam[2]; ///< Parameters of the \a str string
|
||||
StringID railtype; ///< Type of rail on the tile.
|
||||
StringID railtype2; ///< Type of second rail on the tile.
|
||||
uint16 rail_speed; ///< Speed limit of rail (bridges and track)
|
||||
uint16 rail_speed2; ///< Speed limit of second rail (bridges and track)
|
||||
uint16 road_speed; ///< Speed limit of road (bridges)
|
||||
};
|
||||
|
||||
|
@@ -54,6 +54,8 @@ enum TrackBits {
|
||||
TRACK_BIT_3WAY_SW = TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_LEFT, ///< "Arrow" to the south-west
|
||||
TRACK_BIT_3WAY_NW = TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_LEFT, ///< "Arrow" to the north-west
|
||||
TRACK_BIT_ALL = TRACK_BIT_CROSS | TRACK_BIT_HORZ | TRACK_BIT_VERT, ///< All possible tracks
|
||||
TRACK_BIT_RT_1 = TRACK_BIT_UPPER | TRACK_BIT_LEFT, ///< Track bits using the primary rail type, if the total track bits are TRACK_BIT_HORZ or TRACK_BIT_VERT
|
||||
TRACK_BIT_RT_2 = TRACK_BIT_LOWER | TRACK_BIT_RIGHT, ///< Track bits using the secondary rail type, if the total track bits are TRACK_BIT_HORZ or TRACK_BIT_VERT
|
||||
TRACK_BIT_MASK = 0x3FU, ///< Bitmask for the first 6 bits
|
||||
TRACK_BIT_WORMHOLE = 0x40U, ///< Bitflag for a wormhole (used for tunnels)
|
||||
TRACK_BIT_DEPOT = 0x80U, ///< Bitflag for a depot
|
||||
|
@@ -247,7 +247,7 @@ protected: // These functions should not be called outside acceleration code.
|
||||
inline uint16 GetPower() const
|
||||
{
|
||||
/* Power is not added for articulated parts */
|
||||
if (!this->IsArticulatedPart() && (this->IsVirtual() || HasPowerOnRail(this->railtype, GetRailType(this->tile)))) {
|
||||
if (!this->IsArticulatedPart() && (this->IsVirtual() || HasPowerOnRail(this->railtype, GetRailTypeByTrackBit(this->tile, this->track)))) {
|
||||
uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
|
||||
/* Halve power for multiheaded parts */
|
||||
if (this->IsMultiheaded()) power /= 2;
|
||||
@@ -264,7 +264,7 @@ protected: // These functions should not be called outside acceleration code.
|
||||
inline uint16 GetPoweredPartPower(const Train *head) const
|
||||
{
|
||||
/* For powered wagons the engine defines the type of engine (i.e. railtype) */
|
||||
if (HasBit(this->flags, VRF_POWEREDWAGON) && (head->IsVirtual() || HasPowerOnRail(head->railtype, GetRailType(this->tile)))) {
|
||||
if (HasBit(this->flags, VRF_POWEREDWAGON) && (head->IsVirtual() || HasPowerOnRail(head->railtype, GetRailTypeByTrackBit(this->tile, this->track)))) {
|
||||
return RailVehInfo(this->gcache.first_engine)->pow_wag_power;
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ protected: // These functions should not be called outside acceleration code.
|
||||
*/
|
||||
inline uint16 GetMaxTrackSpeed() const
|
||||
{
|
||||
return GetRailTypeInfo(GetRailType(this->tile))->max_speed;
|
||||
return GetRailTypeInfo(GetRailTypeByTrackBit(this->tile, this->track))->max_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -53,7 +53,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
|
||||
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse);
|
||||
static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
|
||||
static bool TrainCanLeaveTile(const Train *v);
|
||||
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile);
|
||||
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile, DiagDirection enterdir);
|
||||
bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
|
||||
static TileIndex TrainApproachingCrossingTile(const Train *v);
|
||||
static void CheckIfTrainNeedsService(Train *v);
|
||||
@@ -469,7 +469,7 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *st
|
||||
bits &= ~TrackCrossesTracks(FindFirstTrack(front->track));
|
||||
}
|
||||
|
||||
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(front, tile) || IsRailDepotTile(tile) ||
|
||||
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(front, tile, dir) || IsRailDepotTile(tile) ||
|
||||
(KillFirstBit(trackdirbits) == TRACKDIR_BIT_NONE && HasOnewaySignalBlockingTrackdir(tile, FindFirstTrackdir(trackdirbits)))) {
|
||||
/* next tile is an effective dead end */
|
||||
int current_platform_remaining = *station_ahead - TILE_SIZE + GetTileMarginInFrontOfTrain(v);
|
||||
@@ -3405,10 +3405,10 @@ static void TrainEnterStation(Train *v, StationID station)
|
||||
}
|
||||
|
||||
/* Check if the vehicle is compatible with the specified tile */
|
||||
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
|
||||
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile, DiagDirection enterdir)
|
||||
{
|
||||
return IsInfraTileUsageAllowed(VEH_TRAIN, v->owner, tile) &&
|
||||
(!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailType(tile)));
|
||||
(!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailTypeByEntryDir(tile, enterdir)));
|
||||
}
|
||||
|
||||
/** Data structure for storing engine speed changes of an acceleration type. */
|
||||
@@ -3937,7 +3937,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
/* Check if the new tile constrains tracks that are compatible
|
||||
* with the current train, if not, bail out. */
|
||||
if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
|
||||
if (!CheckCompatibleRail(v, gp.new_tile, enterdir)) goto invalid_rail;
|
||||
|
||||
TrackBits chosen_track;
|
||||
if (prev == NULL) {
|
||||
@@ -4109,7 +4109,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
v->tile = gp.new_tile;
|
||||
|
||||
if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
|
||||
if (GetTileRailTypeByTrackBit(gp.new_tile, chosen_track) != GetTileRailTypeByTrackBit(gp.old_tile, v->track)) {
|
||||
v->First()->ConsistChanged(CCF_TRACK);
|
||||
}
|
||||
|
||||
@@ -4682,7 +4682,7 @@ static TileIndex TrainApproachingCrossingTile(const Train *v)
|
||||
|
||||
/* not a crossing || wrong axis || unusable rail (wrong type or owner) */
|
||||
if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
|
||||
!CheckCompatibleRail(v, tile)) {
|
||||
!CheckCompatibleRail(v, tile, dir)) {
|
||||
return INVALID_TILE;
|
||||
}
|
||||
|
||||
@@ -4730,7 +4730,7 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse)
|
||||
}
|
||||
|
||||
/* no suitable trackbits at all || unusable rail (wrong type or owner) */
|
||||
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
|
||||
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile, dir)) {
|
||||
return TrainApproachingLineEnd(v, false, reverse);
|
||||
}
|
||||
|
||||
|
@@ -571,10 +571,11 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
||||
Company *c = Company::GetIfValid(company);
|
||||
switch (transport_type) {
|
||||
case TRANSPORT_RAIL:
|
||||
if (is_upgrade) SubtractRailTunnelBridgeInfrastructure(tile_start, tile_end);
|
||||
/* Add to company infrastructure count if required. */
|
||||
MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype, is_upgrade);
|
||||
MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype, is_upgrade);
|
||||
if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_start) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_end);
|
||||
AddRailTunnelBridgeInfrastructure(tile_start, tile_end);
|
||||
break;
|
||||
|
||||
case TRANSPORT_ROAD: {
|
||||
@@ -1145,7 +1146,9 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
if (rail) {
|
||||
tile_tracks = GetCustomBridgeHeadTrackBits(tile);
|
||||
endtile_tracks = GetCustomBridgeHeadTrackBits(endtile);
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)) * (CountBits(tile_tracks) + CountBits(endtile_tracks) - 2));
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)) * (CountBits(GetPrimaryTunnelBridgeTrackBits(tile)) + CountBits(GetPrimaryTunnelBridgeTrackBits(endtile)) - 2));
|
||||
if (GetSecondaryTunnelBridgeTrackBits(tile)) cost.AddCost(RailClearCost(GetSecondaryRailType(tile)));
|
||||
if (GetSecondaryTunnelBridgeTrackBits(endtile)) cost.AddCost(RailClearCost(GetSecondaryRailType(endtile)));
|
||||
}
|
||||
|
||||
Money base_cost = (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) ? _price[PR_CLEAR_BRIDGE] : _price[PR_CLEAR_AQUEDUCT];
|
||||
@@ -1178,12 +1181,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
|
||||
/* Update company infrastructure counts. */
|
||||
if (rail) {
|
||||
if (Company::IsValidID(owner)) {
|
||||
Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= (middle_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) { // handle tunnel/bridge signals.
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, endtile);
|
||||
}
|
||||
}
|
||||
SubtractRailTunnelBridgeInfrastructure(tile, endtile);
|
||||
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
||||
SubtractRoadTunnelBridgeInfrastructure(tile, endtile);
|
||||
} else { // Aqueduct
|
||||
@@ -1638,7 +1636,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
||||
}
|
||||
if (transport_type == TRANSPORT_RAIL && IsRailCustomBridgeHead(ti->tile)) {
|
||||
DrawTrackBits(ti, GetCustomBridgeHeadTrackBits(ti->tile));
|
||||
if (HasRailCatenaryDrawn(GetRailType(ti->tile))) {
|
||||
if (HasRailCatenaryDrawn(GetRailType(ti->tile), GetTileSecondaryRailTypeIfValid(ti->tile))) {
|
||||
DrawRailCatenary(ti);
|
||||
}
|
||||
|
||||
@@ -2103,9 +2101,16 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
|
||||
}
|
||||
|
||||
if (tt == TRANSPORT_RAIL) {
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
|
||||
RailType rt = GetRailType(tile);
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
td->rail_speed = rti->max_speed;
|
||||
td->railtype = rti->strings.name;
|
||||
RailType secondary_rt = GetTileSecondaryRailTypeIfValid(tile);
|
||||
if (secondary_rt != rt && secondary_rt != INVALID_RAILTYPE) {
|
||||
const RailtypeInfo *secondary_rti = GetRailTypeInfo(secondary_rt);
|
||||
td->rail_speed2 = secondary_rti->max_speed;
|
||||
td->railtype2 = secondary_rti->strings.name;
|
||||
}
|
||||
|
||||
if (!IsTunnel(tile)) {
|
||||
uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;
|
||||
@@ -2238,6 +2243,56 @@ void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||
UpdateRoadTunnelBridgeInfrastructure(begin, end, false);
|
||||
}
|
||||
|
||||
static void UpdateRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end, bool add) {
|
||||
const uint middle_len = 2 * GetTunnelBridgeLength(begin, end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
|
||||
if (c != NULL) {
|
||||
uint primary_count = middle_len + GetTunnelBridgeHeadOnlyPrimaryRailInfrastructureCount(begin) + GetTunnelBridgeHeadOnlyPrimaryRailInfrastructureCount(end);
|
||||
if (add) {
|
||||
c->infrastructure.rail[GetRailType(begin)] += primary_count;
|
||||
} else {
|
||||
c->infrastructure.rail[GetRailType(begin)] -= primary_count;
|
||||
}
|
||||
|
||||
auto add_secondary_railtype = [&](TileIndex t) {
|
||||
uint secondary_count = GetTunnelBridgeHeadOnlySecondaryRailInfrastructureCount(t);
|
||||
if (secondary_count) {
|
||||
if (add) {
|
||||
c->infrastructure.rail[GetSecondaryRailType(t)] += secondary_count;
|
||||
} else {
|
||||
c->infrastructure.rail[GetSecondaryRailType(t)] -= secondary_count;
|
||||
}
|
||||
}
|
||||
};
|
||||
add_secondary_railtype(begin);
|
||||
add_secondary_railtype(end);
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(begin)) {
|
||||
if (add) {
|
||||
c->infrastructure.signal += GetTunnelBridgeSignalSimulationSignalCount(begin, end);
|
||||
} else {
|
||||
c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(begin, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end) {
|
||||
UpdateRailTunnelBridgeInfrastructure(c, begin, end, true);
|
||||
}
|
||||
|
||||
void SubtractRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end) {
|
||||
UpdateRailTunnelBridgeInfrastructure(c, begin, end, false);
|
||||
}
|
||||
|
||||
void AddRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||
UpdateRailTunnelBridgeInfrastructure(Company::GetIfValid(GetTileOwner(begin)), begin, end, true);
|
||||
}
|
||||
|
||||
void SubtractRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||
UpdateRailTunnelBridgeInfrastructure(Company::GetIfValid(GetTileOwner(begin)), begin, end, false);
|
||||
}
|
||||
|
||||
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
||||
{
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
@@ -2266,13 +2321,12 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner
|
||||
* No need to dirty windows here, we'll redraw the whole screen anyway. */
|
||||
|
||||
Company *old = Company::Get(old_owner);
|
||||
if (tt == TRANSPORT_RAIL) {
|
||||
/* Set number of middle pieces to zero if it's the southern tile as we
|
||||
* don't want to update the infrastructure counts twice. */
|
||||
const uint num_pieces = GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + (tile < other_end ? GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0);
|
||||
old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
|
||||
} else if (tt == TRANSPORT_WATER) {
|
||||
if (tt == TRANSPORT_RAIL && tile < other_end) {
|
||||
/* Only execute this for one of the two ends */
|
||||
SubtractRailTunnelBridgeInfrastructure(old, tile, other_end);
|
||||
if (new_owner != INVALID_OWNER) AddRailTunnelBridgeInfrastructure(Company::Get(new_owner), tile, other_end);
|
||||
}
|
||||
if (tt == TRANSPORT_WATER) {
|
||||
/* Set number of pieces to zero if it's the southern tile as we
|
||||
* don't want to update the infrastructure counts twice. */
|
||||
const uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
|
||||
@@ -2280,12 +2334,6 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner
|
||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
|
||||
}
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile) && tile < other_end) {
|
||||
uint num_sigs = GetTunnelBridgeSignalSimulationSignalCount(tile, other_end);
|
||||
Company::Get(old_owner)->infrastructure.signal -= num_sigs;
|
||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.signal += num_sigs;
|
||||
}
|
||||
|
||||
if (new_owner != INVALID_OWNER) {
|
||||
SetTileOwner(tile, new_owner);
|
||||
} else {
|
||||
|
@@ -116,6 +116,46 @@ static inline TrackBits GetTunnelBridgeTrackBits(TileIndex t)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary railtype track bits for a rail tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline TrackBits GetPrimaryTunnelBridgeTrackBits(TileIndex t)
|
||||
{
|
||||
if (IsTunnel(t)) {
|
||||
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||
} else {
|
||||
TrackBits bits = GetCustomBridgeHeadTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return bits & GetAcrossBridgePossibleTrackBits(t);
|
||||
} else {
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the secondary railtype track bits for a rail tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline TrackBits GetSecondaryTunnelBridgeTrackBits(TileIndex t)
|
||||
{
|
||||
if (IsTunnel(t)) {
|
||||
return TRACK_BIT_NONE;
|
||||
} else {
|
||||
TrackBits bits = GetCustomBridgeHeadTrackBits(t);
|
||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
|
||||
return bits & (~GetAcrossBridgePossibleTrackBits(t));
|
||||
} else {
|
||||
return TRACK_BIT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the track bits for a rail tunnel/bridge onto/across the tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
@@ -189,14 +229,25 @@ static inline uint GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(T
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rail infrastructure count of a rail tunnel/bridge head tile (excluding the tunnel/bridge middle)
|
||||
* Get the primary railtype rail infrastructure count of a rail tunnel/bridge head tile (excluding the tunnel/bridge middle)
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return rail infrastructure count
|
||||
*/
|
||||
static inline uint GetTunnelBridgeHeadOnlyRailInfrastructureCount(TileIndex t)
|
||||
static inline uint GetTunnelBridgeHeadOnlyPrimaryRailInfrastructureCount(TileIndex t)
|
||||
{
|
||||
return IsBridge(t) ? GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(GetTunnelBridgeTrackBits(t)) : TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
return IsBridge(t) ? GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(GetPrimaryTunnelBridgeTrackBits(t)) : TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the secondary railtype rail infrastructure count of a rail tunnel/bridge head tile (excluding the tunnel/bridge middle)
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return rail infrastructure count
|
||||
*/
|
||||
static inline uint GetTunnelBridgeHeadOnlySecondaryRailInfrastructureCount(TileIndex t)
|
||||
{
|
||||
return IsBridge(t) ? GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(GetSecondaryTunnelBridgeTrackBits(t)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,6 +480,10 @@ static inline void SetTunnelBridgePBS(TileIndex t, bool is_pbs)
|
||||
SB(_me[t].m6, 6, 1, is_pbs ? 1 : 0);
|
||||
}
|
||||
|
||||
void AddRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end);
|
||||
void SubtractRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end);
|
||||
void AddRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||
void SubtractRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||
void AddRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||
void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||
|
||||
|
@@ -3336,7 +3336,7 @@ void Vehicle::ShowVisualEffect() const
|
||||
IsDepotTile(v->tile) ||
|
||||
IsTunnelTile(v->tile) ||
|
||||
(v->type == VEH_TRAIN &&
|
||||
!HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
|
||||
!HasPowerOnRail(Train::From(v)->railtype, GetTileRailTypeByTrackBit(v->tile, Train::From(v)->track)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user