diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html
index d6d4ae864d..e550e59376 100644
--- a/docs/newgrf-additions.html
+++ b/docs/newgrf-additions.html
@@ -466,7 +466,7 @@
See Action 14 Specification and Variational Action 2 Specification for background information.
-The variable mapping mechanism has the feature name: variable_mapping, this document describes version 1.
+The variable mapping mechanism has the feature name: variable_mapping, this document describes version 1 (and where indicated, version 2).
Unlike property mappings, it is not necessary to perform a feature test or check a mapping success variable before using a mapped variable.
Remapped variables are accessed by reading from variable 0x11 using a varadjust shift-num and and-mask which exactly matches that specified in the variable mapping.
In the absence of any successful variable mapping, variable 0x11 has all bits set to 0 and attempting to read from it with any shift-num and and-mask value
@@ -474,6 +474,9 @@
Reading a mapped variable on a version of OpenTTD which does not support this variable mapping mechanism or which does not support the requested variable, returns a value of 0.
If more than one variable mapping is made for the same combination of feature ID, shift-num and and-mask, it is implementation-defined which mapping is used.
Each variable mapping SHOULD use a unique combination of feature ID, shift-num and and-mask.
From version 2 of the variable_mapping feature name, variable remapping can also be used with variable 0x7B.
+ In this case the parameter of variable 0x7B should be set to 0x11, and the shift and mask fields set the same way in the direct 0x11 variable case.
+ The "VPRM" parameter field is ignored, and the parameter used is the accumulator of the previous adjust part in the usual way for variable 0x7B.
Each A2VM chunk (type C) describes an individual variable mapping.
Sub-chunks within each A2VM chunk may appear in any order, however each sub-chunk SHOULD only appear ONCE within an individual A2VM chunk.
This behaves identically to the C "A0PM" -> B "SETT" case, above
+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.
+ Support for this field is indicated by the feature name variable_mapping, version 2.
// Map station variable "sample_station_variable" with a shift-num of 4 and an and-mask of 0xFF, to reads of variable 0x11 with a shift-num of 1 and an and-mask of 0x2, and set bit 4 of global variable 0x8D if successful diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 1c0cfe1d22..05b22ecd27 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5414,6 +5414,16 @@ static void NewSpriteGroup(ByteReader *buf) adjust.variable = remap.id; adjust.shift_num = remap.output_shift; adjust.and_mask = remap.output_mask; + adjust.parameter = remap.output_param; + break; + } + } + } else if (adjust.variable == 0x7B && adjust.parameter == 0x11) { + for (const GRFVariableMapEntry &remap : _cur.grffile->grf_variable_remaps) { + if (remap.feature == feature && remap.input_shift == adjust.shift_num && remap.input_mask == adjust.and_mask) { + adjust.parameter = remap.id; + adjust.shift_num = remap.output_shift; + adjust.and_mask = remap.output_mask; break; } } @@ -8799,6 +8809,7 @@ struct GRFPropertyMapAction { uint8 output_shift; uint input_mask; uint output_mask; + uint output_param; void Reset(const char *tag, const char *desc) { @@ -8814,6 +8825,7 @@ struct GRFPropertyMapAction { this->output_shift = 0; this->input_mask = 0; this->output_mask = 0; + this->output_param = 0; } void ExecuteFeatureIDRemapping() @@ -8930,7 +8942,7 @@ struct GRFPropertyMapAction { extern const GRFVariableMapDefinition _grf_action2_remappable_variables[]; for (const GRFVariableMapDefinition *info = _grf_action2_remappable_variables; info->name != nullptr; info++) { if (info->feature == this->feature && strcmp(info->name, str) == 0) { - _cur.grffile->grf_variable_remaps.push_back({ (uint16)info->id, (uint8)this->feature, this->input_shift, this->output_shift, this->input_mask, this->output_mask }); + _cur.grffile->grf_variable_remaps.push_back({ (uint16)info->id, (uint8)this->feature, this->input_shift, this->output_shift, this->input_mask, this->output_mask, this->output_param }); success = true; break; } @@ -9162,8 +9174,7 @@ static bool ChangePropertyRemapSetOutputParam(size_t len, ByteReader *buf) grfmsg(2, "Action 14 %s mapping: expected 4 bytes for '%s'->'VPRM' but got " PRINTF_SIZE ", ignoring this field", action.descriptor, action.tag_name, len); buf->Skip(len); } else { - buf->ReadDWord(); - /* This is not implemented yet, so just do nothing, but still validate that the format is correct */ + action.output_param = buf->ReadDWord(); } return true; } diff --git a/src/newgrf.h b/src/newgrf.h index 7c77d80f48..fb1a70b8f5 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -211,6 +211,7 @@ struct GRFVariableMapEntry { uint8 output_shift = 0; uint32 input_mask = 0; uint32 output_mask = 0; + uint32 output_param = 0; }; /** The type of action 5 type. */ diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 79116ff74c..9112ad4078 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -18,7 +18,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("feature_test", 1), GRFFeatureInfo("property_mapping", 1), - GRFFeatureInfo("variable_mapping", 1), + GRFFeatureInfo("variable_mapping", 2), GRFFeatureInfo("feature_id_mapping", 1), GRFFeatureInfo("action5_type_id_mapping", 1), GRFFeatureInfo("action0_station_prop1B", 1), diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index e40f093577..84f6f3b556 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -595,7 +595,7 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint } } } - if (adjust.variable >= 0x60 && adjust.variable <= 0x7F) p += seprintf(p, lastof(this->buffer), " (parameter: %X)", adjust.parameter); + if ((adjust.variable >= 0x60 && adjust.variable <= 0x7F) || adjust.parameter != 0) p += seprintf(p, lastof(this->buffer), " (parameter: %X)", adjust.parameter); p += seprintf(p, lastof(this->buffer), ", shift: %X, and: %X", adjust.shift_num, adjust.and_mask); switch (adjust.type) { case DSGA_TYPE_DIV: p += seprintf(p, lastof(this->buffer), ", add: %X, div: %X", adjust.add_val, adjust.divmod_val); break;