GRF: Initial support for > 255 road stop specs per GRF

Add new variable for road stop info of nearby tiles
Bump roadstops version
This commit is contained in:
Jonathan G Rennison
2023-02-12 12:14:48 +00:00
parent cfbd6406e1
commit dceafaf2db
16 changed files with 133 additions and 53 deletions

View File

@@ -43,7 +43,10 @@
<h3 id="roadstop_ids">Road Stop IDs</h3> <h3 id="roadstop_ids">Road Stop IDs</h3>
<p> <p>
Road stop IDs are NewGRF-local and can therefore freely be chosen in the 0..255 range. A road stop is allocated by setting the 'class'-property, which should therefore be set first. A road stop is allocated by setting the 'class'-property, which should therefore be set first.<br />
Road stop IDs are NewGRF-local and can be freely chosen in the 0..63999 range, as of version 7 of the <span class="code">road_stops</span> feature.<br />
When loaded into a version of OpenTTD with versions 1 to 6 of the <span class="code">road_stops</span> feature, IDs are limited to the range: 0..254.
Any road stops with IDs outside this range will be skipped.
</p> </p>
<h3 id="roadstop_properties">Road Stop Properties</h3> <h3 id="roadstop_properties">Road Stop Properties</h3>
@@ -172,6 +175,7 @@
<tr><td>nearby_tile_road_piece</td><td>x, y offset (-8..7)</td><td>0..18 | 0xFF</td><td>Present road piece and slope in <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Roadtypes#Road_underlay_.2802.29">sprite order</a>, or 0xFF if none</td></tr> <tr><td>nearby_tile_road_piece</td><td>x, y offset (-8..7)</td><td>0..18 | 0xFF</td><td>Present road piece and slope in <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Roadtypes#Road_underlay_.2802.29">sprite order</a>, or 0xFF if none</td></tr>
<tr><td>nearby_tile_tram_piece</td><td>x, y offset (-8..7)</td><td>0..18 | 0xFF</td><td>Present tram piece and slope in <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Roadtypes#Road_underlay_.2802.29">sprite order</a>, or 0xFF if none</td></tr> <tr><td>nearby_tile_tram_piece</td><td>x, y offset (-8..7)</td><td>0..18 | 0xFF</td><td>Present tram piece and slope in <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Roadtypes#Road_underlay_.2802.29">sprite order</a>, or 0xFF if none</td></tr>
<tr><td>nearby_tile_road_stop_info</td><td>x, y offset (-8..7)</td><td></td><td>Above nearby road tile variables in one variable (all of variable 0x6B)</td></tr> <tr><td>nearby_tile_road_stop_info</td><td>x, y offset (-8..7)</td><td></td><td>Above nearby road tile variables in one variable (all of variable 0x6B)</td></tr>
<tr><td>nearby_tile_road_stop_info_v2</td><td>x, y offset (-8..7)</td><td></td><td>Above nearby road tile variables in one variable (all of variable roadstop_road_stop_info_nearby_tiles_v2)</td></tr>
</table> </table>
<h3 id="roadstop_callbacks">Road Stop Callbacks</h3> <h3 id="roadstop_callbacks">Road Stop Callbacks</h3>

View File

@@ -323,7 +323,10 @@
<table> <table>
<tr><th>Bits</th><th>Meaning</th></tr> <tr><th>Bits</th><th>Meaning</th></tr>
<tr><td>0 - 7</td><td>If the tile is defined in the current GRF, this is the setID used in the definition. Otherwise, the content is undefined. </td></tr> <tr><td>0 - 7</td><td>
If the tile is defined in the current GRF, this is the lower 8 bits of the setID used in the definition. Otherwise, the content is undefined.<br />
Note that if this GRF has any road stop setIDs greater than 255, bits 24 - 31 need to be used as well.
</td></tr>
<tr><td>8 - 9</td><td> <tr><td>8 - 9</td><td>
0 - The tile uses original TTD graphics<br /> 0 - The tile uses original TTD graphics<br />
1 - The tile is defined in the current GRF<br /> 1 - The tile is defined in the current GRF<br />
@@ -344,6 +347,43 @@
1 - North-bound only<br /> 1 - North-bound only<br />
2 - South-bound only<br /> 2 - South-bound only<br />
3 - No entry 3 - No entry
</td></tr>
<tr><td>24 - 31</td><td>
If the tile is defined in the current GRF, this is the upper 8 bits of the setID used in the definition. Otherwise, the content is undefined.<br />
This can be ignored if this GRF does not have any road stop setIDs greater than 255 (does not define more than 256 road stop types).<br />
This requires <font face="monospace">road_stops</font>, version 7.
</td></tr>
</table>
<br />
The remaining bits are reserved for future use and should be masked.
</p>
<h4 id="roadstop_road_stop_info_nearby_tiles">Road stop of nearby tile v2 (mappable variable: roadstop_road_stop_info_nearby_tiles_v2)</h4>
<p>This has a similar value to <a href="#roadstop_road_stop_info_nearby_tiles">68</a>/<a href="#roadstop_road_stop_info_nearby_tiles">roadstop_road_stop_info_nearby_tiles</a>, above.<br />
<table>
<tr><th>Bits</th><th>Meaning</th></tr>
<tr><td>0 - 15</td><td>If the tile is defined in the current GRF, this is the setID used in the definition. Otherwise, the content is undefined. </td></tr>
<tr><td>16 - 17</td><td>
0 - The tile uses original TTD graphics<br />
1 - The tile is defined in the current GRF<br />
2 - The tile is defined in another GRF
</td></tr>
<tr><td>18</td><td>Set if the selected tile belongs to the current station, clear otherwise</td></tr>
<tr><td>19</td><td>Clear if the selected tile has the same view/rotation, set if a different view/rotation</td></tr>
<tr><td>20 - 23</td><td>View/rotation of the selected tile</td></tr>
<tr><td>24 - 27</td><td>
0 - Passenger/bus stop<br />
1 - Freight/lorry stop<br />
2 - Road waypoint
</td></tr>
<tr><td>28</td><td>Set if the stop type (passenger/bus, freight/lorry or road waypoint) is the same as the current tile</td></tr>
<tr><td>29 - 30</td><td>
One-way road information of the selected tile:<br />
0 - Two-way traffic<br />
1 - North-bound only<br />
2 - South-bound only<br />
3 - No entry
</table> </table>
<br /> <br />
The remaining bits are reserved for future use and should be masked. The remaining bits are reserved for future use and should be masked.
@@ -415,6 +455,10 @@
<p>Road stops have the same Action 3 cargo-type values as feature 4 (station).</p> <p>Road stops have the same Action 3 cargo-type values as feature 4 (station).</p>
<p>In feature name <font face="monospace">road_stops</font> version 7 and later, the Action 3 ID field is an extended byte; GRFs may define more than 255 road stop types.<br />
In versions 1 to 6 (inclusive), only 255 road stop types may be defined per GRF, and the extended byte format may not be used.</p>
<br />
<h3 id="erata">Erata</h3> <h3 id="erata">Erata</h3>
<p>In feature name <font face="monospace">road_stops</font> versions 1 to 5 (inclusive), mapped Action 0 properties which are unknown and should be ignored, instead generate an error on use.</p> <p>In feature name <font face="monospace">road_stops</font> versions 1 to 5 (inclusive), mapped Action 0 properties which are unknown and should be ignored, instead generate an error on use.</p>

View File

@@ -30,7 +30,7 @@ struct StationSpecList {
struct RoadStopSpecList { struct RoadStopSpecList {
const RoadStopSpec *spec; const RoadStopSpec *spec;
uint32 grfid; ///< GRF ID of this custom road stop uint32 grfid; ///< GRF ID of this custom road stop
uint8 localidx; ///< Station ID within GRF of road stop uint16 localidx; ///< Station ID within GRF of road stop
}; };
struct RoadStopTileData { struct RoadStopTileData {

View File

@@ -5056,12 +5056,14 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
{ {
ChangeInfoResult ret = CIR_SUCCESS; ChangeInfoResult ret = CIR_SUCCESS;
if (id + numinfo > 255) { if (id + numinfo > NUM_ROADSTOPS_PER_GRF) {
grfmsg(1, "RoadStopChangeInfo: RoadStop %u is invalid, max %u, ignoring", id + numinfo, 255); grfmsg(1, "RoadStopChangeInfo: RoadStop %u is invalid, max %u, ignoring", id + numinfo, NUM_ROADSTOPS_PER_GRF);
return CIR_INVALID_ID; return CIR_INVALID_ID;
} }
if (_cur.grffile->roadstops == nullptr) _cur.grffile->roadstops = CallocT<RoadStopSpec*>(255); if (id + numinfo > _cur.grffile->roadstops.size()) {
_cur.grffile->roadstops.resize(id + numinfo);
}
for (int i = 0; i < numinfo; i++) { for (int i = 0; i < numinfo; i++) {
RoadStopSpec *rs = _cur.grffile->roadstops[id + i]; RoadStopSpec *rs = _cur.grffile->roadstops[id + i];
@@ -6701,9 +6703,9 @@ static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount)
static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount) static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount)
{ {
uint8 *roadstops = AllocaM(uint8, idcount); uint16 *roadstops = AllocaM(uint16, idcount);
for (uint i = 0; i < idcount; i++) { for (uint i = 0; i < idcount; i++) {
roadstops[i] = buf->ReadByte(); roadstops[i] = buf->ReadExtendedByte();
} }
uint8 cidcount = buf->ReadByte(); uint8 cidcount = buf->ReadByte();
@@ -6716,7 +6718,7 @@ static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount)
if (ctype == CT_INVALID) continue; if (ctype == CT_INVALID) continue;
for (uint i = 0; i < idcount; i++) { for (uint i = 0; i < idcount; i++) {
RoadStopSpec *roadstopspec = _cur.grffile->roadstops == nullptr ? nullptr : _cur.grffile->roadstops[roadstops[i]]; RoadStopSpec *roadstopspec = (roadstops[i] >= _cur.grffile->roadstops.size()) ? nullptr : _cur.grffile->roadstops[roadstops[i]];
if (roadstopspec == nullptr) { if (roadstopspec == nullptr) {
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping", roadstops[i]); grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping", roadstops[i]);
@@ -6730,13 +6732,13 @@ static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount)
uint16 groupid = buf->ReadWord(); uint16 groupid = buf->ReadWord();
if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return; if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
if (_cur.grffile->roadstops == nullptr) { if (_cur.grffile->roadstops.empty()) {
grfmsg(0, "RoadStopMapSpriteGroup: No roadstops defined, skipping."); grfmsg(0, "RoadStopMapSpriteGroup: No roadstops defined, skipping.");
return; return;
} }
for (uint i = 0; i < idcount; i++) { for (uint i = 0; i < idcount; i++) {
RoadStopSpec *roadstopspec = _cur.grffile->roadstops == nullptr ? nullptr : _cur.grffile->roadstops[roadstops[i]]; RoadStopSpec *roadstopspec = (roadstops[i] >= _cur.grffile->roadstops.size()) ? nullptr : _cur.grffile->roadstops[roadstops[i]];
if (roadstopspec == nullptr) { if (roadstopspec == nullptr) {
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping.", roadstops[i]); grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping.", roadstops[i]);
@@ -10147,14 +10149,12 @@ static void ResetCustomObjects()
static void ResetCustomRoadStops() static void ResetCustomRoadStops()
{ {
for (auto file : _grf_files) { for (auto file : _grf_files) {
RoadStopSpec **&roadstopspec = file->roadstops; std::vector<RoadStopSpec *> &roadstops = file->roadstops;
if (roadstopspec == nullptr) continue; for (RoadStopSpec *spec : roadstops) {
for (uint i = 0; i < NUM_ROADSTOPS_PER_GRF; i++) { free(spec);
free(roadstopspec[i]);
} }
free(roadstopspec); roadstops.clear();
roadstopspec = nullptr;
} }
} }

View File

@@ -320,7 +320,7 @@ struct GRFFile : ZeroedMemoryAllocator {
std::vector<struct ObjectSpec *> objectspec; std::vector<struct ObjectSpec *> objectspec;
struct AirportSpec **airportspec; struct AirportSpec **airportspec;
struct AirportTileSpec **airtspec; struct AirportTileSpec **airtspec;
struct RoadStopSpec **roadstops; std::vector<struct RoadStopSpec *> roadstops;
GRFFeatureMapRemapSet feature_id_remaps; GRFFeatureMapRemapSet feature_id_remaps;
GRFFilePropertyRemapSet action0_property_remaps[GSF_END]; GRFFilePropertyRemapSet action0_property_remaps[GSF_END];

View File

@@ -63,7 +63,7 @@ public:
static bool IsClassIDValid(Tid cls_id); static bool IsClassIDValid(Tid cls_id);
static NewGRFClass *Get(Tid cls_id); static NewGRFClass *Get(Tid cls_id);
static const Tspec *GetByGrf(uint32 grfid, byte local_id, int *index); static const Tspec *GetByGrf(uint32 grfid, uint16 local_id, int *index);
}; };
#endif /* NEWGRF_CLASS_H */ #endif /* NEWGRF_CLASS_H */

View File

@@ -209,7 +209,7 @@ DEFINE_NEWGRF_CLASS_METHOD(int)::GetUIFromIndex(int index) const
* @param index Pointer to return the index of the spec in its class. If nullptr then not used. * @param index Pointer to return the index of the spec in its class. If nullptr then not used.
* @return The spec. * @return The spec.
*/ */
DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetByGrf(uint32 grfid, byte local_id, int *index) DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetByGrf(uint32 grfid, uint16 local_id, int *index)
{ {
uint j; uint j;
@@ -246,4 +246,4 @@ DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetByGrf(uint32 grfid, byte local_id,
template const Tspec *name::GetSpec(uint index) const; \ template const Tspec *name::GetSpec(uint index) const; \
template int name::GetUIFromIndex(int index) const; \ template int name::GetUIFromIndex(int index) const; \
template int name::GetIndexFromUI(int ui_index) const; \ template int name::GetIndexFromUI(int ui_index) const; \
template const Tspec *name::GetByGrf(uint32 grfid, byte localidx, int *index); template const Tspec *name::GetByGrf(uint32 grfid, uint16 localidx, int *index);

View File

@@ -55,7 +55,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_object_edge_foundation_mode", 2), GRFFeatureInfo("action0_object_edge_foundation_mode", 2),
GRFFeatureInfo("action0_object_flood_resistant", 1), GRFFeatureInfo("action0_object_flood_resistant", 1),
GRFFeatureInfo("action0_object_viewport_map_tile_type", 1), GRFFeatureInfo("action0_object_viewport_map_tile_type", 1),
GRFFeatureInfo("road_stops", 6), GRFFeatureInfo("road_stops", 7),
GRFFeatureInfo("new_landscape", 2), GRFFeatureInfo("new_landscape", 2),
GRFFeatureInfo("more_objects_per_grf", 1), GRFFeatureInfo("more_objects_per_grf", 1),
GRFFeatureInfo(), GRFFeatureInfo(),
@@ -150,6 +150,7 @@ extern const GRFVariableMapDefinition _grf_action2_remappable_variables[] = {
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x68, "roadstop_road_stop_info_nearby_tiles"), GRFVariableMapDefinition(GSF_ROADSTOPS, 0x68, "roadstop_road_stop_info_nearby_tiles"),
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x6A, "roadstop_road_stop_grfid_nearby_tiles"), GRFVariableMapDefinition(GSF_ROADSTOPS, 0x6A, "roadstop_road_stop_grfid_nearby_tiles"),
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x6B, "roadstop_road_info_nearby_tiles"), GRFVariableMapDefinition(GSF_ROADSTOPS, 0x6B, "roadstop_road_info_nearby_tiles"),
GRFVariableMapDefinition(GSF_ROADSTOPS, A2VRI_ROADSTOP_INFO_NEARBY_TILES_V2, "roadstop_road_stop_info_nearby_tiles_v2"),
GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_RESTRICTION_INFO, "railtype_signal_restriction_info"), GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_RESTRICTION_INFO, "railtype_signal_restriction_info"),
GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_CONTEXT, "railtype_signal_context"), GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_CONTEXT, "railtype_signal_context"),
GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "signals_signal_restriction_info"), GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "signals_signal_restriction_info"),

View File

@@ -77,6 +77,7 @@ enum Action2VariableRemapIds {
A2VRI_OBJECT_FOUNDATION_SLOPE = 0x100, A2VRI_OBJECT_FOUNDATION_SLOPE = 0x100,
A2VRI_OBJECT_FOUNDATION_SLOPE_CHANGE, A2VRI_OBJECT_FOUNDATION_SLOPE_CHANGE,
A2VRI_VEHICLE_CURRENT_SPEED_SCALED, A2VRI_VEHICLE_CURRENT_SPEED_SCALED,
A2VRI_ROADSTOP_INFO_NEARBY_TILES_V2,
A2VRI_RAILTYPE_SIGNAL_RESTRICTION_INFO, A2VRI_RAILTYPE_SIGNAL_RESTRICTION_INFO,
A2VRI_RAILTYPE_SIGNAL_CONTEXT, A2VRI_RAILTYPE_SIGNAL_CONTEXT,
A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO,

View File

@@ -24,6 +24,7 @@
#include "viewport_func.h" #include "viewport_func.h"
#include "newgrf_animation_base.h" #include "newgrf_animation_base.h"
#include "newgrf_sound.h" #include "newgrf_sound.h"
#include "newgrf_extension.h"
#include "safeguards.h" #include "safeguards.h"
@@ -66,6 +67,39 @@ uint32 RoadStopScopeResolver::GetTriggers() const
return this->st == nullptr ? 0 : this->st->waiting_triggers; return this->st == nullptr ? 0 : this->st->waiting_triggers;
} }
uint32 RoadStopScopeResolver::GetNearbyRoadStopsInfo(uint32 parameter, bool v2) const
{
if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
uint32 grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid;
bool same_orientation = GetStationGfx(this->tile) == GetStationGfx(nearby_tile);
bool same_station = GetStationIndex(nearby_tile) == this->st->index;
uint32 res = GetStationGfx(nearby_tile) << 12 | !same_orientation << 11 | !!same_station << 10;
StationType type = GetStationType(nearby_tile);
if (type == STATION_TRUCK) res |= (1 << 16);
if (type == STATION_ROADWAYPOINT) res |= (2 << 16);
if (type == this->type) SetBit(res, 20);
uint16 localidx = 0;
if (IsCustomRoadStopSpecIndex(nearby_tile)) {
const RoadStopSpecList ssl = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
localidx = ssl.localidx;
res |= 1 << (ssl.grfid != grfid ? 9 : 8);
}
if (IsDriveThroughStopTile(nearby_tile)) {
res |= (GetDriveThroughStopDisallowedRoadDirections(nearby_tile) << 21);
}
if (v2) {
return (res << 8) | localidx;
} else {
return res | (localidx & 0xFF) | ((localidx & 0xFF00) << 16);
}
}
uint32 RoadStopScopeResolver::GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const uint32 RoadStopScopeResolver::GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const
{ {
auto get_road_type_variable = [&](RoadTramType rtt) -> uint32 { auto get_road_type_variable = [&](RoadTramType rtt) -> uint32 {
@@ -151,28 +185,12 @@ uint32 RoadStopScopeResolver::GetVariable(uint16 variable, uint32 parameter, Get
/* Road stop info of nearby tiles */ /* Road stop info of nearby tiles */
case 0x68: { case 0x68: {
if (this->tile == INVALID_TILE) return 0xFFFFFFFF; return this->GetNearbyRoadStopsInfo(parameter, false);
TileIndex nearby_tile = GetNearbyTile(parameter, this->tile); }
if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF; /* Road stop info of nearby tiles: v2 */
case A2VRI_ROADSTOP_INFO_NEARBY_TILES_V2: {
uint32 grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid; return this->GetNearbyRoadStopsInfo(parameter, true);
bool same_orientation = GetStationGfx(this->tile) == GetStationGfx(nearby_tile);
bool same_station = GetStationIndex(nearby_tile) == this->st->index;
uint32 res = GetStationGfx(nearby_tile) << 12 | !same_orientation << 11 | !!same_station << 10;
StationType type = GetStationType(nearby_tile);
if (type == STATION_TRUCK) res |= (1 << 16);
if (type == STATION_ROADWAYPOINT) res |= (2 << 16);
if (type == this->type) SetBit(res, 20);
if (IsCustomRoadStopSpecIndex(nearby_tile)) {
const RoadStopSpecList ssl = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ssl.localidx;
}
if (IsDriveThroughStopTile(nearby_tile)) {
res |= (GetDriveThroughStopDisallowedRoadDirections(nearby_tile) << 21);
}
return res;
} }
/* GRFID of nearby road stop tiles */ /* GRFID of nearby road stop tiles */

View File

@@ -20,7 +20,7 @@
#include "road.h" #include "road.h"
/** The maximum amount of roadstops a single GRF is allowed to add */ /** The maximum amount of roadstops a single GRF is allowed to add */
static const int NUM_ROADSTOPS_PER_GRF = 255; static const int NUM_ROADSTOPS_PER_GRF = 64000;
enum RoadStopClassID : byte { enum RoadStopClassID : byte {
ROADSTOP_CLASS_BEGIN = 0, ///< The lowest valid value ROADSTOP_CLASS_BEGIN = 0, ///< The lowest valid value
@@ -98,6 +98,9 @@ struct RoadStopScopeResolver : public ScopeResolver {
uint32 GetTriggers() const override; uint32 GetTriggers() const override;
uint32 GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const override; uint32 GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const override;
private:
uint32 GetNearbyRoadStopsInfo(uint32 parameter, bool v2) const;
}; };
/** Road stop resolver. */ /** Road stop resolver. */

View File

@@ -62,8 +62,8 @@ struct RoadStopGUISettings {
DiagDirection orientation; // This replaces _road_station_picker_orientation DiagDirection orientation; // This replaces _road_station_picker_orientation
RoadStopClassID roadstop_class; RoadStopClassID roadstop_class;
byte roadstop_type; uint16 roadstop_type;
byte roadstop_count; uint16 roadstop_count;
}; };
static RoadStopGUISettings _roadstop_gui_settings; static RoadStopGUISettings _roadstop_gui_settings;
@@ -217,7 +217,7 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2,
bool connect_to_road = true; bool connect_to_road = true;
RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p3); RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p3);
byte spec_index = GB(p3, 8, 8); uint16 spec_index = GB(p3, 16, 16);
if ((uint)spec_class < RoadStopClass::GetClassCount() && spec_index < RoadStopClass::Get(spec_class)->GetSpecCount()) { if ((uint)spec_class < RoadStopClass::GetClassCount() && spec_index < RoadStopClass::Get(spec_class)->GetSpecCount()) {
const RoadStopSpec *roadstopspec = RoadStopClass::Get(spec_class)->GetSpec(spec_index); const RoadStopSpec *roadstopspec = RoadStopClass::Get(spec_class)->GetSpec(spec_index);
if (roadstopspec != nullptr && HasBit(roadstopspec->flags, RSF_NO_AUTO_ROAD_CONNECTION)) connect_to_road = false; if (roadstopspec != nullptr && HasBit(roadstopspec->flags, RSF_NO_AUTO_ROAD_CONNECTION)) connect_to_road = false;
@@ -256,7 +256,7 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u
TileArea ta(start_tile, end_tile); TileArea ta(start_tile, end_tile);
CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop); CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop);
cmdcont.p3 = (_roadstop_gui_settings.roadstop_type << 8) | _roadstop_gui_settings.roadstop_class; cmdcont.p3 = (_roadstop_gui_settings.roadstop_type << 16) | _roadstop_gui_settings.roadstop_class;
ShowSelectStationIfNeeded(cmdcont, ta); ShowSelectStationIfNeeded(cmdcont, ta);
} }

View File

@@ -171,7 +171,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr }, { XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr },
{ XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr }, { XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr },
{ XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr },
{ XSLFI_GRF_ROADSTOPS, XSCF_NULL, 2, 2, "grf_road_stops", nullptr, nullptr, nullptr }, { XSLFI_GRF_ROADSTOPS, XSCF_NULL, 3, 3, "grf_road_stops", nullptr, nullptr, nullptr },
{ XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr },
{ XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 2, 2, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 2, 2, "new_signal_styles", nullptr, nullptr, "XBST,NSID" },
{ XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr }, { XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr },

View File

@@ -243,6 +243,12 @@ static const SaveLoad _station_speclist_desc[] = {
SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, SLV_27, SL_MAX_VERSION), SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, SLV_27, SL_MAX_VERSION),
}; };
static const SaveLoad _roadstop_speclist_desc[] = {
SLE_CONDVAR(RoadStopSpecList, grfid, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION),
SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 0, 2)),
SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 3)),
};
CargoPacketList _packets; CargoPacketList _packets;
uint32 _num_dests; uint32 _num_dests;
@@ -504,6 +510,7 @@ std::vector<SaveLoad> _filtered_station_desc;
std::vector<SaveLoad> _filtered_waypoint_desc; std::vector<SaveLoad> _filtered_waypoint_desc;
std::vector<SaveLoad> _filtered_goods_desc; std::vector<SaveLoad> _filtered_goods_desc;
std::vector<SaveLoad> _filtered_station_speclist_desc; std::vector<SaveLoad> _filtered_station_speclist_desc;
std::vector<SaveLoad> _filtered_roadstop_speclist_desc;
static void SetupDescs_STNN() static void SetupDescs_STNN()
{ {
@@ -511,6 +518,7 @@ static void SetupDescs_STNN()
_filtered_waypoint_desc = SlFilterObject(_waypoint_desc); _filtered_waypoint_desc = SlFilterObject(_waypoint_desc);
_filtered_goods_desc = SlFilterObject(GetGoodsDesc()); _filtered_goods_desc = SlFilterObject(GetGoodsDesc());
_filtered_station_speclist_desc = SlFilterObject(_station_speclist_desc); _filtered_station_speclist_desc = SlFilterObject(_station_speclist_desc);
_filtered_roadstop_speclist_desc = SlFilterObject(_roadstop_speclist_desc);
} }
std::vector<SaveLoad> _filtered_roadstop_desc; std::vector<SaveLoad> _filtered_roadstop_desc;
@@ -584,7 +592,7 @@ static void RealSave_STNN(BaseStation *bst)
} }
for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { for (uint i = 0; i < bst->roadstop_speclist.size(); i++) {
SlObjectSaveFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc); SlObjectSaveFiltered(&bst->roadstop_speclist[i], _filtered_roadstop_speclist_desc);
} }
for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) {
@@ -727,7 +735,7 @@ static void Load_STNN()
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
bst->roadstop_speclist.resize(_num_roadstop_specs); bst->roadstop_speclist.resize(_num_roadstop_specs);
for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { for (uint i = 0; i < bst->roadstop_speclist.size(); i++) {
SlObjectLoadFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc); SlObjectLoadFiltered(&bst->roadstop_speclist[i], _filtered_roadstop_speclist_desc);
} }
} }

View File

@@ -2083,7 +2083,7 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio
* bit 5..10: The roadtype. * bit 5..10: The roadtype.
* bit 16..31: Station ID to join (NEW_STATION if build new one). * bit 16..31: Station ID to join (NEW_STATION if build new one).
* @param p3 bit 0..7: Roadstop class. * @param p3 bit 0..7: Roadstop class.
* bit 8..15: Roadstopspec index. * bit 16..31: Roadstopspec index.
* @param text Unused. * @param text Unused.
* @return The cost of this operation or an error. * @return The cost of this operation or an error.
*/ */
@@ -2102,7 +2102,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
uint8 length = (uint8)GB(p1, 8, 8); uint8 length = (uint8)GB(p1, 8, 8);
RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p3); RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p3);
byte spec_index = GB(p3, 8, 8); uint16 spec_index = GB(p3, 16, 16);
/* Check if the given station class is valid */ /* Check if the given station class is valid */
if ((uint)spec_class >= RoadStopClass::GetClassCount() || spec_class == ROADSTOP_CLASS_WAYP) return CMD_ERROR; if ((uint)spec_class >= RoadStopClass::GetClassCount() || spec_class == ROADSTOP_CLASS_WAYP) return CMD_ERROR;

View File

@@ -1846,6 +1846,7 @@ static const NIVariable _nif_roadstops[] = {
NIV(0x69, "information about cargo accepted in the past"), NIV(0x69, "information about cargo accepted in the past"),
NIV(0x6A, "GRFID of nearby road stop tiles"), NIV(0x6A, "GRFID of nearby road stop tiles"),
NIV(0x6B, "Road info of nearby plain road tiles"), NIV(0x6B, "Road info of nearby plain road tiles"),
NIV(A2VRI_ROADSTOP_INFO_NEARBY_TILES_V2, "road stop info of nearby tiles v2"),
NIV_END(), NIV_END(),
}; };