diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 312461f61c..af29569eb1 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -81,8 +81,21 @@ If the test is successful, the bit is set (to 1), otherwise the bit is cleared (to 0).
The bit number MUST be in the range: 4 ≤ bit number ≤ 31. These bits can be assumed to be 0 on implementations which do not support this feature test mechanism.
Global variable 0x9D can then be tested by using a standard Action 7 or 9, or a standard Variational Action 2.
- If this field is omitted, no bit is set or cleared, and the test is not observable. -

+ If this field is omitted, no bit is set or cleared, and the test is not observable (unless the SVAL chunk is used). +

+

Feature Set Global Variable 0x91 Success Test Value: C "FTST" -> B "SVAL"

+

Within an FTST chunk, the SVAL binary (type B) field contains a 32 bit value which can be tested using the mechanism below. This is 4 bytes.
+ If the test is successful, the value is added to a list of successful result values which can be checked using the mechanism below.
+ If the test is unsuccessful, no action is taken.
+ The value must be > 0, a value of 0 has no effect.

+

To check if the test succeeded (the value has been added to the list of successful result values), use Action 7 or 9.
+ The parameter to test is global variable 0x91 (this always has a value of 0, equivalent to the case where the test has failed, if this feature test mechanism is not present).
+ The condition-type to use is: 02 (\7=, equality) to jump if the value is in the list (the test succeeded), or 03 (\7!, inequality) to jump if the value is not in the list (the test did not succeed).
+ The value in the Action 7 or 9 must match the value specified in this SVAL chunk. +

+

If this field is omitted, the test is not observable (unless the SETP chunk is used).

+

This chunk and the associated test mechanism requires the feature name: feature_test, version 2.
+ Using this chunk instead or as well as SETP allows observing the result of more than 28 feature tests.


Example NFO:

@@ -134,6 +147,9 @@
 	Global variable 0x8D can then be tested by using a standard Action 7 or 9, or a standard Variational Action 2.
If this field is omitted, no bit is set or cleared.

+

Success Indicator Global Variable 0x91 Test Value: C "A0PM" -> B "SVAL"

+

This behaves identically to the C "FTST" -> B "SVAL" case, above

+

This chunk and the associated test mechanism requires the feature name: property_mapping, version 2.

Fallback Mode: C "A0PM" -> B "FLBK"

Within an A0PM chunk, the FLBK binary (type B) field contains the fallback mode. This is 1 byte.
The fallback mode may take the following values: @@ -656,6 +672,9 @@ If this is not specified, a value of 0 is assumed.

Success Indicator Global Variable 0x8D Bit: C "A2VM" -> B "SETT"

This behaves identically to the C "A0PM" -> B "SETT" case, above

+

Success Indicator Global Variable 0x91 Test Value: C "A2VM" -> B "SVAL"

+

This behaves identically to the C "FTST" -> B "SVAL" case, above

+

This chunk and the associated test mechanism requires the feature name: variable_mapping, version 3.

Replacement parameter: C "A2VM" -> B "VPRM"

Within an A2VM chunk, the VPRM binary (type B) field contains the Variational Action 2 parameter value (as in 60+X variables) to use on the mapped variable. This is 4 bytes.
If this is not specified, a value of 0 is assumed.
@@ -805,6 +824,9 @@ It is possible to override existing type IDs, however this use is not recommended.

Success Indicator Global Variable 0x8D Bit: C "A5TM" -> B "SETT"

This behaves identically to the C "A0PM" -> B "SETT" case, above

+

Success Indicator Global Variable 0x91 Test Value: C "A5TM" -> B "SVAL"

+

This behaves identically to the C "FTST" -> B "SVAL" case, above

+

This chunk and the associated test mechanism requires the feature name: action5_type_id_mapping, version 2.

Fallback Mode: C "A5TM" -> B "FLBK"

This behaves identically to the C "A0PM" -> B "FLBK" case, above

Example NFO:

@@ -879,6 +901,9 @@ At the time of writing known existing feature IDs include the values: 0x00 - 0x13 (inclusive) and 0x48.

Success Indicator Global Variable 0x8D Bit: C "FIDM" -> B "SETT"

This behaves identically to the C "A0PM" -> B "SETT" case, above

+

Success Indicator Global Variable 0x91 Test Value: C "FIDM" -> B "SVAL"

+

This behaves identically to the C "FTST" -> B "SVAL" case, above

+

This chunk and the associated test mechanism requires the feature name: feature_id_mapping, version 2.

Fallback Mode: C "FIDM" -> B "FLBK"

This behaves identically to the C "A0PM" -> B "FLBK" case, above

Example NFO:

diff --git a/src/newgrf.cpp b/src/newgrf.cpp index ab725bc9fa..60a7d5c447 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -7643,6 +7643,13 @@ static void SkipIf(ByteReader *buf) default: grfmsg(1, "SkipIf: Unsupported GRF condition type %02X. Ignoring", condtype); return; } + } else if (param == 0x91 && (condtype == 0x02 || condtype == 0x03) && cond_val > 0) { + const std::vector &values = _cur.grffile->var91_values; + /* condtype 0x02: skip if test result found + * condtype 0x03: skip if test result not found + */ + bool found = std::find(values.begin(), values.end(), cond_val) != values.end(); + result = (found == (condtype == 0x02)); } else { /* Tests that use 'param' and are not GRF ID checks. */ uint32 param_val = GetParamVal(param, &cond_val); // cond_val is modified for param == 0x85 @@ -9212,6 +9219,7 @@ struct GRFFeatureTest { uint16 min_version; uint16 max_version; uint8 platform_var_bit; + uint32 test_91_value; void Reset() { @@ -9219,6 +9227,7 @@ struct GRFFeatureTest { this->min_version = 1; this->max_version = UINT16_MAX; this->platform_var_bit = 0; + this->test_91_value = 0; } void ExecuteTest() @@ -9228,7 +9237,16 @@ struct GRFFeatureTest { if (this->platform_var_bit > 0) { SB(_cur.grffile->var9D_overlay, this->platform_var_bit, 1, has_feature ? 1 : 0); grfmsg(2, "Action 14 feature test: feature test: setting bit %u of var 0x9D to %u, %u", platform_var_bit, has_feature ? 1 : 0, _cur.grffile->var9D_overlay); - } else { + } + if (this->test_91_value > 0) { + if (has_feature) { + grfmsg(2, "Action 14 feature test: feature test: adding test value 0x%X to var 0x91", this->test_91_value); + include(_cur.grffile->var91_values, this->test_91_value); + } else { + grfmsg(2, "Action 14 feature test: feature test: not adding test value 0x%X to var 0x91", this->test_91_value); + } + } + if (this->platform_var_bit == 0 && this->test_91_value == 0) { grfmsg(2, "Action 14 feature test: feature test: doing nothing: %u", has_feature ? 1 : 0); } if (this->feature != nullptr && this->feature->observation_flag != GFTOF_INVALID) { @@ -9296,12 +9314,25 @@ static bool ChangeGRFFeatureSetPlatformVarBit(size_t len, ByteReader *buf) return true; } +/** Callback function for 'FTST'->'SVAL' to add a test success result value for checking using global variable 91. */ +static bool ChangeGRFFeatureTestSuccessResultValue(size_t len, ByteReader *buf) +{ + if (len != 4) { + grfmsg(2, "Action 14 feature test: expected 4 bytes for 'FTST'->'SVAL' but got " PRINTF_SIZE ", ignoring this field", len); + buf->Skip(len); + } else { + _current_grf_feature_test.test_91_value = buf->ReadDWord(); + } + return true; +} + /** Action14 tags for the FTST node */ AllowedSubtags _tags_ftst[] = { AllowedSubtags('NAME', ChangeGRFFeatureTestName), AllowedSubtags('MINV', ChangeGRFFeatureMinVersion), AllowedSubtags('MAXV', ChangeGRFFeatureMaxVersion), AllowedSubtags('SETP', ChangeGRFFeatureSetPlatformVarBit), + AllowedSubtags('SVAL', ChangeGRFFeatureTestSuccessResultValue), AllowedSubtags() }; @@ -9326,6 +9357,7 @@ struct GRFPropertyMapAction { std::string name; GRFPropertyMapFallbackMode fallback_mode; uint8 ttd_ver_var_bit; + uint32 test_91_value; uint8 input_shift; uint8 output_shift; uint input_mask; @@ -9342,6 +9374,7 @@ struct GRFPropertyMapAction { this->name.clear(); this->fallback_mode = GPMFM_IGNORE; this->ttd_ver_var_bit = 0; + this->test_91_value = 0; this->input_shift = 0; this->output_shift = 0; this->input_mask = 0; @@ -9376,6 +9409,9 @@ struct GRFPropertyMapAction { if (this->ttd_ver_var_bit > 0) { SB(_cur.grffile->var8D_overlay, this->ttd_ver_var_bit, 1, success ? 1 : 0); } + if (this->test_91_value > 0 && success) { + include(_cur.grffile->var91_values, this->test_91_value); + } if (!success) { if (this->fallback_mode == GPMFM_ERROR_ON_DEFINITION) { grfmsg(0, "Error: Unimplemented mapped %s: %s, mapped to: 0x%02X", this->descriptor, str, this->prop_id); @@ -9427,6 +9463,9 @@ struct GRFPropertyMapAction { if (this->ttd_ver_var_bit > 0) { SB(_cur.grffile->var8D_overlay, this->ttd_ver_var_bit, 1, success ? 1 : 0); } + if (this->test_91_value > 0 && success) { + include(_cur.grffile->var91_values, this->test_91_value); + } if (!success) { if (this->fallback_mode == GPMFM_ERROR_ON_DEFINITION) { grfmsg(0, "Error: Unimplemented mapped %s: %s, feature: %s, mapped to: %X", this->descriptor, str, GetFeatureString(this->feature), this->prop_id); @@ -9471,6 +9510,9 @@ struct GRFPropertyMapAction { if (this->ttd_ver_var_bit > 0) { SB(_cur.grffile->var8D_overlay, this->ttd_ver_var_bit, 1, success ? 1 : 0); } + if (this->test_91_value > 0 && success) { + include(_cur.grffile->var91_values, this->test_91_value); + } if (!success) { grfmsg(2, "Unimplemented mapped %s: %s, feature: %s, mapped to 0", this->descriptor, str, GetFeatureString(this->feature)); } @@ -9502,6 +9544,9 @@ struct GRFPropertyMapAction { if (this->ttd_ver_var_bit > 0) { SB(_cur.grffile->var8D_overlay, this->ttd_ver_var_bit, 1, success ? 1 : 0); } + if (this->test_91_value > 0 && success) { + include(_cur.grffile->var91_values, this->test_91_value); + } if (!success) { if (this->fallback_mode == GPMFM_ERROR_ON_DEFINITION) { grfmsg(0, "Error: Unimplemented mapped %s: %s, mapped to: %X", this->descriptor, str, this->prop_id); @@ -9625,6 +9670,19 @@ static bool ChangePropertyRemapSetTTDVerVarBit(size_t len, ByteReader *buf) return true; } +/** Callback function for >'SVAL' to add a success result value for checking using global variable 91. */ +static bool ChangePropertyRemapSuccessResultValue(size_t len, ByteReader *buf) +{ + GRFPropertyMapAction &action = _current_grf_property_map_action; + if (len != 4) { + grfmsg(2, "Action 14 %s mapping: expected 4 bytes for '%s'->'SVAL' but got " PRINTF_SIZE ", ignoring this field", action.descriptor, action.tag_name, len); + buf->Skip(len); + } else { + action.test_91_value = buf->ReadDWord(); + } + return true; +} + /** Callback function for ->'RSFT' to set the input shift value for variable remapping. */ static bool ChangePropertyRemapSetInputShift(size_t len, ByteReader *buf) { @@ -9706,6 +9764,7 @@ AllowedSubtags _tags_fidm[] = { AllowedSubtags('FTID', ChangePropertyRemapFeatureId), AllowedSubtags('FLBK', ChangePropertyRemapSetFallbackMode), AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit), + AllowedSubtags('SVAL', ChangePropertyRemapSuccessResultValue), AllowedSubtags() }; @@ -9727,6 +9786,7 @@ AllowedSubtags _tags_a0pm[] = { AllowedSubtags('PROP', ChangePropertyRemapPropertyId), AllowedSubtags('FLBK', ChangePropertyRemapSetFallbackMode), AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit), + AllowedSubtags('SVAL', ChangePropertyRemapSuccessResultValue), AllowedSubtags() }; @@ -9751,6 +9811,7 @@ AllowedSubtags _tags_a2vm[] = { AllowedSubtags('VMSK', ChangePropertyRemapSetOutputMask), AllowedSubtags('VPRM', ChangePropertyRemapSetOutputParam), AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit), + AllowedSubtags('SVAL', ChangePropertyRemapSuccessResultValue), AllowedSubtags() }; @@ -9771,6 +9832,7 @@ AllowedSubtags _tags_a5tm[] = { AllowedSubtags('TYPE', ChangePropertyRemapTypeId), AllowedSubtags('FLBK', ChangePropertyRemapSetFallbackMode), AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit), + AllowedSubtags('SVAL', ChangePropertyRemapSuccessResultValue), AllowedSubtags() }; diff --git a/src/newgrf.h b/src/newgrf.h index 93b1e06c0b..0e5588e97b 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -357,6 +357,7 @@ struct GRFFile : ZeroedMemoryAllocator { uint32 var8D_overlay; ///< Overlay for global variable 8D (action 0x14) uint32 var9D_overlay; ///< Overlay for global variable 9D (action 0x14) + std::vector var91_values; ///< Test result values for global variable 91 (action 0x14, only testable using action 7/9) uint32 observed_feature_tests; ///< Observed feature test bits (see: GRFFeatureTestObservationFlag) diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 8e3e7edf92..b26d8e90c5 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -16,11 +16,11 @@ /** Action14 feature list */ extern const GRFFeatureInfo _grf_feature_list[] = { - GRFFeatureInfo("feature_test", 1), - GRFFeatureInfo("property_mapping", 1), - GRFFeatureInfo("variable_mapping", 2), - GRFFeatureInfo("feature_id_mapping", 1), - GRFFeatureInfo("action5_type_id_mapping", 1), + GRFFeatureInfo("feature_test", 2), + GRFFeatureInfo("property_mapping", 2), + GRFFeatureInfo("variable_mapping", 3), + GRFFeatureInfo("feature_id_mapping", 2), + GRFFeatureInfo("action5_type_id_mapping", 2), GRFFeatureInfo("action0_station_prop1B", 1), GRFFeatureInfo("action0_station_disallowed_bridge_pillars", 1), GRFFeatureInfo("varaction2_station_var42", 1),