From a3c003546bc98701781cb3dbafc742a30a47d3ef Mon Sep 17 00:00:00 2001
From: Jonathan G Rennison 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. 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. From version 2 of the variable_mapping feature name, variable remapping can also be used with variable 0x7B. Each A2VM chunk (type C) describes an individual variable mapping.
Action 14 - Variable Mapping for Variational Action 2
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 @@
Each variable mapping SHOULD use a unique combination of feature ID, shift-num and and-mask.
+ 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.Variable Mapping: C "A2VM"
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;