diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 549586626c..49910151bf 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -114,14 +114,15 @@ 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: + All properties which are mapped by this 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. + 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.
+ Note that each use of the mapped property ID is followed by Num-info iterations of the size and data pair above. See: Action 0 Specification.

Example NFO:

 // Map station property "sample_station_property" to property id 0xF8, and set bit 4 of global variable 0x8D if successful
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index d3219bb1b3..83fef234f6 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -991,7 +991,7 @@ enum ChangeInfoResult {
 	CIR_INVALID_ID, ///< Attempt to modify an invalid ID
 };
 
-typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader *buf);
+typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf);
 
 static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
 {
@@ -1003,14 +1003,26 @@ static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
 		case A0RPI_UNKNOWN_ERROR:
 			return CIR_DISABLED;
 
-		case A0RPI_SKIPPED_IGNORE:
-			return CIR_SUCCESS;
-
 		default:
 			return CIR_UNKNOWN;
 	}
 }
 
+static bool MappedPropertyLengthMismatch(ByteReader *buf, uint expected_size, const GRFFilePropertyRemapEntry *mapping_entry)
+{
+	uint length = buf->ReadExtendedByte();
+	if (length != expected_size) {
+		if (mapping_entry != NULL) {
+			grfmsg(2, "Ignoring use of mapped property: %s, feature: %X, mapped to: %X, with incorrect data size: %u instead of %u",
+					mapping_entry->name, mapping_entry->feature, mapping_entry->property_id, length, expected_size);
+		}
+		buf->Skip(length);
+		return true;
+	} else {
+		return false;
+	}
+}
+
 /**
  * Define properties common to all vehicles
  * @param ei Engine info.
@@ -1018,7 +1030,7 @@ static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader *buf)
+static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	switch (prop) {
 		case 0x00: // Introduction date
@@ -1061,7 +1073,7 @@ static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteRe
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -1339,7 +1351,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop
 			}
 
 			default:
-				ret = CommonVehicleChangeInfo(ei, prop, buf);
+				ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
 				break;
 		}
 	}
@@ -1355,7 +1367,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -1527,7 +1539,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop
 			}
 
 			default:
-				ret = CommonVehicleChangeInfo(ei, prop, buf);
+				ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
 				break;
 		}
 	}
@@ -1543,7 +1555,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -1699,7 +1711,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop
 			}
 
 			default:
-				ret = CommonVehicleChangeInfo(ei, prop, buf);
+				ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
 				break;
 		}
 	}
@@ -1715,7 +1727,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -1853,7 +1865,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int
 				break;
 
 			default:
-				ret = CommonVehicleChangeInfo(ei, prop, buf);
+				ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
 				break;
 		}
 	}
@@ -1869,7 +1881,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -2116,7 +2128,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -2154,7 +2166,7 @@ static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteRead
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -2327,7 +2339,7 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader *buf)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -2600,7 +2612,7 @@ static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	/* Properties which are handled as a whole */
 	switch (prop) {
@@ -2815,7 +2827,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By
 	return ret;
 }
 
-static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	/* Properties which are handled as a whole */
 	switch (prop) {
@@ -2886,7 +2898,7 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -3025,7 +3037,7 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -3120,7 +3132,7 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader *buf)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -3384,7 +3396,7 @@ static void CleanIndustryTileTable(IndustrySpec *ind)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -3804,7 +3816,7 @@ static void DuplicateTileTable(AirportSpec *as)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -4022,7 +4034,7 @@ static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader *buf)
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -4153,7 +4165,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea
  * @param buf The property value.
  * @return ChangeInfoResult.
  */
-static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -4283,7 +4295,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR
 	return ret;
 }
 
-static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -4363,7 +4375,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte
 	return ret;
 }
 
-static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader *buf)
+static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
 {
 	ChangeInfoResult ret = CIR_SUCCESS;
 
@@ -4482,7 +4494,15 @@ static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uin
 	}
 }
 
-static int ReadAction0PropertyID(ByteReader *buf, uint8 feature)
+struct GRFFilePropertyDescriptor {
+	int prop;
+	const GRFFilePropertyRemapEntry *entry;
+
+	GRFFilePropertyDescriptor(int prop, const GRFFilePropertyRemapEntry *entry)
+			: prop(prop), entry(entry) {}
+};
+
+static GRFFilePropertyDescriptor ReadAction0PropertyID(ByteReader *buf, uint8 feature)
 {
 	uint8 raw_prop = buf->ReadByte();
 	const GRFFilePropertyRemapSet &remap = _cur.grffile->action0_property_remaps[feature];
@@ -4499,22 +4519,10 @@ static int ReadAction0PropertyID(ByteReader *buf, uint8 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;
+		return GRFFilePropertyDescriptor(prop, &def);
 	} else {
-		return raw_prop;
+		return GRFFilePropertyDescriptor(raw_prop, NULL);
 	}
 }
 
@@ -4571,10 +4579,10 @@ static void FeatureChangeInfo(ByteReader *buf)
 	SetBit(_cur.grffile->grf_features, feature);
 
 	while (numprops-- && buf->HasData()) {
-		int prop = ReadAction0PropertyID(buf, feature);
+		GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
 
-		ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf);
-		if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return;
+		ChangeInfoResult cir = handler[feature](engine, numinfo, desc.prop, desc.entry, buf);
+		if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, desc.prop)) return;
 	}
 }
 
@@ -4587,14 +4595,14 @@ static void SafeChangeInfo(ByteReader *buf)
 	buf->ReadExtendedByte(); // id
 
 	if (feature == GSF_BRIDGES && numprops == 1) {
-		int prop = ReadAction0PropertyID(buf, feature);
+		GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
 		/* Bridge property 0x0D is redefinition of sprite layout tables, which
 		 * is considered safe. */
-		if (prop == 0x0D) return;
+		if (desc.prop == 0x0D) return;
 	} else if (feature == GSF_GLOBALVAR && numprops == 1) {
-		int prop = ReadAction0PropertyID(buf, feature);
+		GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
 		/* Engine ID Mappings are safe, if the source is static */
-		if (prop == 0x11) {
+		if (desc.prop == 0x11) {
 			bool is_safe = true;
 			for (uint i = 0; i < numinfo; i++) {
 				uint32 s = buf->ReadDWord();
@@ -4627,25 +4635,25 @@ static void ReserveChangeInfo(ByteReader *buf)
 	uint8 index    = buf->ReadExtendedByte();
 
 	while (numprops-- && buf->HasData()) {
-		int prop = ReadAction0PropertyID(buf, feature);
+		GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
 		ChangeInfoResult cir = CIR_SUCCESS;
 
 		switch (feature) {
 			default: NOT_REACHED();
 			case GSF_CARGOES:
-				cir = CargoChangeInfo(index, numinfo, prop, buf);
+				cir = CargoChangeInfo(index, numinfo, desc.prop, desc.entry, buf);
 				break;
 
 			case GSF_GLOBALVAR:
-				cir = GlobalVarReserveInfo(index, numinfo, prop, buf);
+				cir = GlobalVarReserveInfo(index, numinfo, desc.prop, desc.entry, buf);
 				break;
 
 			case GSF_RAILTYPES:
-				cir = RailTypeReserveInfo(index, numinfo, prop, buf);
+				cir = RailTypeReserveInfo(index, numinfo, desc.prop, desc.entry, buf);
 				break;
 		}
 
-		if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return;
+		if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, desc.prop)) return;
 	}
 }
 
@@ -8074,11 +8082,7 @@ struct GRFPropertyMapAction {
 				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;
-				}
+				entry.property_id = this->prop_id;
 				success = true;
 				break;
 			}
@@ -8102,7 +8106,7 @@ struct GRFPropertyMapAction {
 				entry.name = str_store;
 				entry.id = (this->fallback_mode == A0REM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR;
 				entry.feature = this->feature;
-				entry.flags = 0;
+				entry.property_id = this->prop_id;
 			}
 		}
 	}
diff --git a/src/newgrf.h b/src/newgrf.h
index 5255ea915f..a56537703a 100644
--- a/src/newgrf.h
+++ b/src/newgrf.h
@@ -106,7 +106,6 @@ enum Action0RemapPropertyIds {
 	A0RPI_CHECK_PROPERTY_LENGTH = 0x10000,
 	A0RPI_UNKNOWN_IGNORE = 0x200,
 	A0RPI_UNKNOWN_ERROR,
-	A0RPI_SKIPPED_IGNORE,
 };
 
 enum Action0RemapFallbackMode {
@@ -120,34 +119,26 @@ 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)
+		feature(0)
 	{}
 
-	GRFPropertyMapDefinition(uint8 feature, int id, const char *name, int expected_size = -1) :
+	GRFPropertyMapDefinition(uint8 feature, int id, const char *name) :
 		name(name),
 		id(id),
-		feature(feature),
-		expected_size(expected_size)
+		feature(feature)
 	{}
 };
 
-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;
+	uint8 property_id = 0;
 };
 
 struct GRFFilePropertyRemapSet {