diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 71e4545625..0e76cf7813 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -25,7 +25,7 @@

See Action 14 Specification for background information.

Feature Test: C "FTST"

Each FTST chunk (type C) describes an individual feature test.
- Sub-chunks with each FTST chunk may appear in any order, however each sub-chunk SHOULD only appear ONCE within an individual FTST chunk.

+ Sub-chunks within each FTST chunk may appear in any order, however each sub-chunk SHOULD only appear ONCE within an individual FTST chunk.

Feature tests can be safely used on implementations which do not implement the described feature test mechanism because unknown Action 14 blocks are ignored, and the observable result (in global variable 0x9D) is equivalent to the case where all feature tests have failed, indicating that the feature is not present.

Feature Name: C "FTST" -> T "NAME"

@@ -58,7 +58,6 @@ "B" "MINV" \w2 \w4 "B" "SETP" \w1 04 00 - 00 "C" "FTST" "T" "NAME" 00 "sample_feature_2" 00 "B" "MINV" \w2 \w5 @@ -70,6 +69,75 @@ // Skip 1 sprite if bit 4 of global variable 0x9D is not set (indicating that sample_feature_1 with a version of at least 4 is NOT present) -1 * -1 07 9D 01 \70 04 01 +
+

Action 14 - Property Mapping for Action 0

+

See Action 14 Specification and Action 0 Specification for background information.

+

The property mapping mechanism has the feature name: property_mapping, this document describes version 1.

+

Users of this mechanism SHOULD at minimum use test for the presence of the feature above or test variable 8D, below.

+

Property Mapping: C "A0PM"

+

Each A0PM chunk (type C) describes an individual property mapping.
+ Sub-chunks within each A0PM chunk may appear in any order, however except where otherwise noted each sub-chunk SHOULD only appear ONCE within an individual A0PM chunk.

+

Property mapping can be safely used on implementations which do not implement the property mapping mechanism if Action 0 sprites which use mapped property IDs are skipped if one or more of: +

+ Unknown Action 14 blocks are ignored, and do not need to be skipped.

+

Property Name: C "A0PM" -> T "NAME"

+

Within an A0PM chunk, the NAME text (type T) field contains the name of the property to map. The value of the language ID byte is ignored.

+

Action 0 Feature ID: C "A0PM" -> B "FEAT"

+

Within an A0PM chunk, the FEAT binary (type B) field contains the Action 0 feature ID. This is 1 byte.

+

Property ID: C "A0PM" -> B "PROP"

+

Within an A0PM chunk, the PROP binary (type B) field contains the property ID to allocate to the named property, this value can used in Action 0 sprites. This is 1 byte.
+ It is possible to override existing properties, however this use is not recommended.

+

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

+

Within an A0PM chunk, the SETT binary (type B) field contains the bit number to set/clear in + global variable 0x8D (TTD version) to store whether the mapping operation was successful. This is 1 byte.
+ If the operation 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 property mapping mechanism.
+ 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. +

+

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: + + + + + +
ValueBehaviour
0Attempts to map an unknown property name are ignored. Use of the mapped property in an Action 0 is ignored. This is the default.
1Attempts to map an unknown property name are ignored. Use of the mapped property in an Action 0 is an error.
2Attempting to map an unknown property name is an error.
+ Attempts to set a fallback mode other than those listed above are silently ignored. More fallback modes MAY be added in future versions of this mechanism.
+ This chunk MAY be specified more than once, in which case the last specified valid value is used.
+ Note that even when using fallback mode 0, above, if the property mapping feature is not present, then use of the mapped property ID in an Action 0 is an error. +

+

Format of remapped properties

+ All properties which are mapped by the mechanism have the format: + + + + +
SizeNameMeaning
B*numSize of the data in bytes
VdataProperty data
+ Note that num is an extended byte, see GRFActionsDetailed.
+ If the size of the data does provided is not valid for the given property, the attempt to set the property MAY be ignored or partially applied. +

Example NFO:

+
+// Map station property "sample_station_property" to property id 0xF8, and set bit 4 of global variable 0x8D if successful
+-1 * -1 14
+	"C" "A0PM"
+		"T" "NAME" 00 "sample_station_property" 00
+		"B" "FEAT" \w1 04
+		"B" "PROP" \w1 F8
+		"B" "SETT" \w1 4
+		00
+	00
+....
+// Skip 1 sprite if bit 4 of global variable 0x8D is not set (indicating that station property sample_station_property is NOT present)
+-1 * -1  07 8D 01 \70 04 01
+// Set sample_station_property for station ID 10 to 2 byte value: AB CD
+-1 * -1  00 04 01 01 10 F8 02 AB CD
+	
+

Action 0 - Stations

Minimum bridge height (1B)

This is indicated by the feature name: action0_station_prop1B, version 1

diff --git a/os/debian/changelog b/os/debian/changelog index ce2582128c..bb57ca39e8 100644 --- a/os/debian/changelog +++ b/os/debian/changelog @@ -1,3 +1,15 @@ +openttd (1.8.0-0) unstable; urgency=low + + * New upstream release 1.8.0 + + -- OpenTTD Sun, 01 Apr 2018 14:00:00 +0200 + +openttd (1.8.0~RC1-0) unstable; urgency=low + + * New upstream release 1.8.0-RC1 + + -- OpenTTD Wed, 21 Mar 2018 21:00:00 +0100 + openttd (1.7.2-0) unstable; urgency=low * New upstream release 1.7.2 @@ -1002,4 +1014,3 @@ openttd (0.3.5-1) unstable; urgency=low * Initial Release. -- Matthijs Kooijman Fri, 24 Dec 2004 02:58:47 +0100 - diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 29a9f0f073..7bdb9309d8 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -3064,6 +3064,8 @@ STR_NEWGRF_ERROR_READ_BOUNDS :Pročitaj nakon STR_NEWGRF_ERROR_GRM_FAILED :Zatraženi GRF resursi nisu dostupni (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} je isključen od strane {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Pogrešan/nepoznat format raspored sprite-a (sprite {3:NUM}) +STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG :Previše elemenata na listi postavki varijabli (sprite {3:NUM}, postavka {4:HEX}) +STR_NEWGRF_ERROR_INDPROD_CALLBACK :Pogrešna callback funkcija za industrijsku proizvodnju (sprite {3:NUM}, "{1:STRING}") # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Oprez! diff --git a/src/lang/english.txt b/src/lang/english.txt index b000c535b1..0248a52797 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3457,7 +3457,7 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_ST STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{RAW_STRING} -STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING5} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING7} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:RAW_STRING} will not work with the TTDPatch version reported by OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:RAW_STRING} is for the {RAW_STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:RAW_STRING} is designed to be used with {RAW_STRING} @@ -3470,6 +3470,7 @@ STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Too many NewGRF STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Loading {1:RAW_STRING} as static NewGRF with {RAW_STRING} could cause desyncs STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Unexpected sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Unknown Action 0 property {4:HEX} (sprite {3:NUM}) +STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY :Unimplemented remapped Action 0 property feature: {4:HEX}, name: {2:RAW_STRING}, mapped to: {5:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Attempt to use invalid ID (sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{RAW_STRING} contains a corrupt sprite. All corrupt sprites will be shown as a red question mark (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 9429a8368e..91be1f8f67 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -998,6 +998,24 @@ enum ChangeInfoResult { typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader *buf); +static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop) +{ + switch (prop) { + case A0RPI_UNKNOWN_IGNORE: + buf->Skip(buf->ReadExtendedByte()); + return CIR_SUCCESS; + + case A0RPI_UNKNOWN_ERROR: + return CIR_DISABLED; + + case A0RPI_SKIPPED_IGNORE: + return CIR_SUCCESS; + + default: + return CIR_UNKNOWN; + } +} + /** * Define properties common to all vehicles * @param ei Engine info. @@ -1034,7 +1052,7 @@ static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteRe break; default: - return CIR_UNKNOWN; + return HandleAction0PropertyDefault(buf, prop); } return CIR_SUCCESS; @@ -2094,7 +2112,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -2132,7 +2150,7 @@ static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteRead break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -2249,7 +2267,7 @@ static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteR break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -2312,7 +2330,7 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader *buf) } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } return ret; @@ -2544,7 +2562,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -2806,7 +2824,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -2868,7 +2886,7 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -3007,7 +3025,7 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -3065,7 +3083,7 @@ static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, B } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -3105,7 +3123,7 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader *buf) break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } return ret; @@ -3243,7 +3261,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -3336,7 +3354,7 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader *buf) } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } return ret; @@ -3761,7 +3779,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -3964,7 +3982,7 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -4009,7 +4027,7 @@ static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader *buf) break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } @@ -4139,7 +4157,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -4277,7 +4295,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -4357,7 +4375,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -4447,7 +4465,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro break; default: - ret = CIR_UNKNOWN; + ret = HandleAction0PropertyDefault(buf, prop); break; } } @@ -4455,7 +4473,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro return ret; } -static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8 feature, uint8 property) +static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8 feature, int property) { switch (cir) { default: NOT_REACHED(); @@ -4484,6 +4502,42 @@ static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uin } } +static int ReadAction0PropertyID(ByteReader *buf, uint8 feature) +{ + uint8 raw_prop = buf->ReadByte(); + const GRFFilePropertyRemapSet &remap = _cur.grffile->action0_property_remaps[feature]; + if (remap.remapped_ids[raw_prop]) { + auto iter = remap.mapping.find(raw_prop); + assert(iter != remap.mapping.end()); + const GRFFilePropertyRemapEntry &def = iter->second; + int prop = def.id; + if (prop == A0RPI_UNKNOWN_ERROR) { + grfmsg(0, "Error: Unimplemented mapped property: %s, feature: %X, mapped to: %X", def.name, def.feature, raw_prop); + GRFError *error = DisableGrf(STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY); + error->data = stredup(def.name); + error->param_value[1] = def.feature; + error->param_value[2] = raw_prop; + } else if (prop == A0RPI_UNKNOWN_IGNORE) { + grfmsg(2, "Ignoring unimplemented mapped property: %s, feature: %X, mapped to: %X", def.name, def.feature, raw_prop); + } else { + if (HasBit(def.flags, GFPRE_CHECK_SIZE)) { + uint length = buf->ReadExtendedByte(); + if (length != def.expected_size) { + grfmsg(2, "Ignoring use of mapped property: %s, feature: %X, mapped to: %X, with incorrect data size: %u instead of %u", + def.name, def.feature, raw_prop, length, def.expected_size); + buf->Skip(length); + prop = A0RPI_SKIPPED_IGNORE; + } + } else { + prop |= A0RPI_CHECK_PROPERTY_LENGTH; + } + } + return prop; + } else { + return raw_prop; + } +} + /* Action 0x00 */ static void FeatureChangeInfo(ByteReader *buf) { @@ -4518,6 +4572,7 @@ static void FeatureChangeInfo(ByteReader *buf) /* GSF_RAILTYPES */ RailTypeChangeInfo, /* GSF_AIRPORTTILES */ AirportTilesChangeInfo, }; + static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps)); uint8 feature = buf->ReadByte(); uint8 numprops = buf->ReadByte(); @@ -4536,7 +4591,7 @@ static void FeatureChangeInfo(ByteReader *buf) SetBit(_cur.grffile->grf_features, feature); while (numprops-- && buf->HasData()) { - uint8 prop = buf->ReadByte(); + int prop = ReadAction0PropertyID(buf, feature); ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf); if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return; @@ -4552,12 +4607,12 @@ static void SafeChangeInfo(ByteReader *buf) buf->ReadExtendedByte(); // id if (feature == GSF_BRIDGES && numprops == 1) { - uint8 prop = buf->ReadByte(); + int prop = ReadAction0PropertyID(buf, feature); /* Bridge property 0x0D is redefinition of sprite layout tables, which * is considered safe. */ if (prop == 0x0D) return; } else if (feature == GSF_GLOBALVAR && numprops == 1) { - uint8 prop = buf->ReadByte(); + int prop = ReadAction0PropertyID(buf, feature); /* Engine ID Mappings are safe, if the source is static */ if (prop == 0x11) { bool is_safe = true; @@ -4592,7 +4647,7 @@ static void ReserveChangeInfo(ByteReader *buf) uint8 index = buf->ReadExtendedByte(); while (numprops-- && buf->HasData()) { - uint8 prop = buf->ReadByte(); + int prop = ReadAction0PropertyID(buf, feature); ChangeInfoResult cir = CIR_SUCCESS; switch (feature) { @@ -5963,7 +6018,7 @@ bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile) } case 0x0D: // TTD Version, 00=DOS, 01=Windows - *value = _cur.grfconfig->palette & GRFP_USE_MASK; + *value = (_cur.grfconfig->palette & GRFP_USE_MASK) | grffile->var8D_overlay; return true; case 0x0E: // Y-offset for train sprites @@ -7891,6 +7946,7 @@ struct GRFFeatureInfo { /** Action14 feature list */ static const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("feature_test", 1), + GRFFeatureInfo("property_mapping", 1), GRFFeatureInfo("action0_station_prop1B", 1), GRFFeatureInfo("varaction2_station_var42", 1), GRFFeatureInfo("more_bridge_types", 1), @@ -7967,7 +8023,7 @@ static bool ChangeGRFFeatureMaxVersion(size_t len, ByteReader *buf) return true; } -/** Callback function for 'FTST'->'SETP' to set the maximum version of the feature being tested. */ +/** Callback function for 'FTST'->'SETP' to set the bit number of global variable 9D (platform version) to set/unset with the result of the feature test. */ static bool ChangeGRFFeatureSetPlatformVarBit(size_t len, ByteReader *buf) { if (len != 1) { @@ -8004,10 +8060,177 @@ static bool HandleFeatureTestInfo(ByteReader *buf) return true; } +/** Action14 Action0 remappable property list */ +static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { + GRFPropertyMapDefinition(), +}; + +/** Action14 Action0 property map action instance */ +struct GRFPropertyMapAction { + int feature; + int prop_id; + std::string name; + Action0RemapFallbackMode fallback_mode; + uint8 ttd_ver_var_bit; + + void Reset() + { + this->feature = -1; + this->prop_id = -1; + this->name.clear(); + this->fallback_mode = A0REM_IGNORE; + this->ttd_ver_var_bit = 0; + } + + void Execute() + { + if (this->feature < 0) { + grfmsg(2, "Action 14 property remapping: no feature defined, doing nothing"); + return; + } + if (this->prop_id < 0) { + grfmsg(2, "Action 14 property remapping: no property ID defined, doing nothing"); + return; + } + if (this->name.empty()) { + grfmsg(2, "Action 14 property remapping: no name defined, doing nothing"); + return; + } + bool success = false; + const char *str = this->name.c_str(); + for (const GRFPropertyMapDefinition *info = _grf_action0_remappable_properties; info->name != NULL; info++) { + if (info->feature == this->feature && strcmp(info->name, str) == 0) { + GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id); + entry.name = info->name; + entry.id = info->id; + entry.feature = this->feature; + entry.flags = 0; + if (info->expected_size >= 0) { + SetBit(entry.flags, GFPRE_CHECK_SIZE); + entry.expected_size = info->expected_size; + } + success = true; + break; + } + } + if (this->ttd_ver_var_bit > 0) { + SB(_cur.grffile->var8D_overlay, this->ttd_ver_var_bit, 1, success ? 1 : 0); + } + if (!success) { + if (this->fallback_mode == A0REM_ERROR_ON_DEFINITION) { + grfmsg(0, "Error: Unimplemented mapped property: %s, feature: %X, mapped to: %X", str, this->feature, this->prop_id); + GRFError *error = DisableGrf(STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY); + error->data = stredup(str); + error->param_value[1] = this->feature; + error->param_value[2] = this->prop_id; + } else { + const char *str_store = stredup(str); + grfmsg(2, "Unimplemented mapped property: %s, feature: %X, mapped to: %X, %s on use", + str, this->feature, this->prop_id, (this->fallback_mode == A0REM_IGNORE) ? "ignoring" : "error"); + *(_cur.grffile->action0_unknown_property_names.Append()) = str_store; + GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id); + entry.name = str_store; + entry.id = (this->fallback_mode == A0REM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR; + entry.feature = this->feature; + entry.flags = 0; + } + } + } +}; + +static GRFPropertyMapAction _current_grf_property_map_action; + +/** Callback function for 'A0PM'->'NAME' to set the name of the property to be mapped. */ +static bool ChangePropertyRemapName(byte langid, const char *str) +{ + _current_grf_property_map_action.name = str; + return true; +} + +/** Callback function for 'A0PM'->'FEAT' to set which feature this property mapping applies to. */ +static bool ChangePropertyRemapFeature(size_t len, ByteReader *buf) +{ + if (len != 1) { + grfmsg(2, "Action 14 property mapping: expected 1 byte for 'A0PM'->'FEAT' but got " PRINTF_SIZE ", ignoring this field", len); + buf->Skip(len); + } else { + uint8 feature = buf->ReadByte(); + if (feature >= GSF_END) { + grfmsg(2, "Action 14 property mapping: invalid feature ID: %u, in 'A0PM'->'FEAT', ignoring this field", feature); + } else { + _current_grf_property_map_action.feature = feature; + } + } + return true; +} + +/** Callback function for 'A0PM'->'PROP' to set the property ID to which this property is being mapped. */ +static bool ChangePropertyRemapPropertyId(size_t len, ByteReader *buf) +{ + if (len != 1) { + grfmsg(2, "Action 14 property mapping: expected 1 byte for 'A0PM'->'PROP' but got " PRINTF_SIZE ", ignoring this field", len); + buf->Skip(len); + } else { + _current_grf_property_map_action.prop_id = buf->ReadByte(); + } + return true; +} + +/** Callback function for 'A0PM'->'FLBK' to set the maximum version of the feature being tested. */ +static bool ChangePropertyRemapSetFallbackMode(size_t len, ByteReader *buf) +{ + if (len != 1) { + grfmsg(2, "Action 14 property mapping: expected 1 byte for 'A0PM'->'FLBK' but got " PRINTF_SIZE ", ignoring this field", len); + buf->Skip(len); + } else { + Action0RemapFallbackMode mode = (Action0RemapFallbackMode) buf->ReadByte(); + if (mode < A0REM_END) _current_grf_property_map_action.fallback_mode = mode; + } + return true; +} +/** Callback function for 'A0PM'->'SETT' to set the bit number of global variable 8D (TTD version) to set/unset with whether the remapping was successful. */ +static bool ChangePropertyRemapSetTTDVerVarBit(size_t len, ByteReader *buf) +{ + if (len != 1) { + grfmsg(2, "Action 14 property mapping: expected 1 byte for 'A0PM'->'SETT' but got " PRINTF_SIZE ", ignoring this field", len); + buf->Skip(len); + } else { + uint8 bit_number = buf->ReadByte(); + if (bit_number >= 4 && bit_number <= 31) { + _current_grf_property_map_action.ttd_ver_var_bit = bit_number; + } else { + grfmsg(2, "Action 14 property mapping: expected a bit number >= 4 and <= 32 for 'A0PM'->'SETT' but got %u, ignoring this field", bit_number); + } + } + return true; +} + +/** Action14 tags for the A0PM node */ +AllowedSubtags _tags_a0pm[] = { + AllowedSubtags('NAME', ChangePropertyRemapName), + AllowedSubtags('FEAT', ChangePropertyRemapFeature), + AllowedSubtags('PROP', ChangePropertyRemapPropertyId), + AllowedSubtags('FLBK', ChangePropertyRemapSetFallbackMode), + AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit), + AllowedSubtags() +}; + +/** + * Callback function for 'A0PM' (action 0 property mapping) + */ +static bool HandleAction0PropertyMap(ByteReader *buf) +{ + _current_grf_property_map_action.Reset(); + HandleNodes(buf, _tags_a0pm); + _current_grf_property_map_action.Execute(); + return true; +} + /** Action14 root tags */ AllowedSubtags _tags_root_static[] = { AllowedSubtags('INFO', _tags_info), AllowedSubtags('FTST', SkipInfoChunk), + AllowedSubtags('A0PM', SkipInfoChunk), AllowedSubtags() }; @@ -8015,6 +8238,7 @@ AllowedSubtags _tags_root_static[] = { AllowedSubtags _tags_root_feature_tests[] = { AllowedSubtags('INFO', SkipInfoChunk), AllowedSubtags('FTST', HandleFeatureTestInfo), + AllowedSubtags('A0PM', HandleAction0PropertyMap), AllowedSubtags() }; diff --git a/src/newgrf.h b/src/newgrf.h index 0261b30ae5..797aba5f1c 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -19,6 +19,8 @@ #include "core/bitmath_func.hpp" #include "core/alloc_type.hpp" #include "core/smallvec_type.hpp" +#include "3rdparty/cpp-btree/btree_map.h" +#include /** * List of different canal 'features'. @@ -101,6 +103,65 @@ struct GRFLabel { struct GRFLabel *next; }; +enum Action0RemapPropertyIds { + A0RPI_CHECK_PROPERTY_LENGTH = 0x10000, + A0RPI_UNKNOWN_IGNORE = 0x200, + A0RPI_UNKNOWN_ERROR, + A0RPI_SKIPPED_IGNORE, +}; + +enum Action0RemapFallbackMode { + A0REM_IGNORE, + A0REM_ERROR_ON_USE, + A0REM_ERROR_ON_DEFINITION, + A0REM_END, +}; + +struct GRFPropertyMapDefinition { + const char *name; // NULL indicates the end of the list + int id; + uint8 feature; + int expected_size; + + /** Create empty object used to identify the end of a list. */ + GRFPropertyMapDefinition() : + name(NULL), + id(0), + feature(0), + expected_size(0) + {} + + GRFPropertyMapDefinition(uint8 feature, int id, const char *name, int expected_size = -1) : + name(name), + id(id), + feature(feature), + expected_size(expected_size) + {} +}; + +enum GFPRE_Flags { + GFPRE_CHECK_SIZE, +}; + +struct GRFFilePropertyRemapEntry { + const char *name = nullptr; + int id = 0; + uint8 feature = 0; + uint8 flags = 0; + uint16 expected_size = 0; +}; + +struct GRFFilePropertyRemapSet { + std::bitset<256> remapped_ids; + btree::btree_map mapping; + + GRFFilePropertyRemapEntry &Entry(uint8 property) + { + this->remapped_ids.set(property); + return this->mapping[property]; + } +}; + /** Dynamic data of a loaded NewGRF */ struct GRFFile : ZeroedMemoryAllocator { char *filename; @@ -118,6 +179,9 @@ struct GRFFile : ZeroedMemoryAllocator { struct AirportSpec **airportspec; struct AirportTileSpec **airtspec; + GRFFilePropertyRemapSet action0_property_remaps[GSF_END]; + AutoFreeSmallVector action0_unknown_property_names; + uint32 param[0x80]; uint param_end; ///< one more than the highest set parameter @@ -139,6 +203,7 @@ struct GRFFile : ZeroedMemoryAllocator { uint32 grf_features; ///< Bitset of GrfSpecFeature the grf uses PriceMultipliers price_base_multipliers; ///< Price base multipliers as set by the grf. + uint32 var8D_overlay; ///< Overlay for global variable 8D (action 0x14) uint32 var9D_overlay; ///< Overlay for global variable 9D (action 0x14) GRFFile(const struct GRFConfig *config); diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 90a88ccc65..def7843db8 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -109,7 +109,7 @@ struct GRFError : ZeroedMemoryAllocator { char *data; ///< Additional data for message and custom_message StringID message; ///< Default message StringID severity; ///< Info / Warning / Error / Fatal - uint32 param_value[2]; ///< Values of GRF parameters to show for message and custom_message + uint64 param_value[4]; ///< Values of GRF parameters to show for message and custom_message }; /** The possible types of a newgrf parameter. */ diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index ecb015ed4d..03e9831a11 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -23,7 +23,7 @@ * * \b 1.8.0 * - * 1.8.0 is not yet released. The following changes are not set in stone yet. + * No changes * * \b 1.7.0 - 1.7.2 *