changeset 17844:91d7b400b453 draft

(svn r22635) -Fix: Correctly reseed random bits of industries and industry tiles.
author frosch <frosch@openttd.org>
date Mon, 04 Jul 2011 20:37:20 +0000
parents 2d62fee43556
children 178f1e9c0277
files src/newgrf_engine.cpp src/newgrf_house.cpp src/newgrf_industrytiles.cpp src/newgrf_spritegroup.cpp src/newgrf_spritegroup.h
diffstat 5 files changed, 74 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -1070,8 +1070,9 @@
 	if (group == NULL) return;
 
 	new_random_bits = Random();
-	v->random_bits &= ~object.reseed;
-	v->random_bits |= (first ? new_random_bits : base_random_bits) & object.reseed;
+	uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding
+	v->random_bits &= ~reseed;
+	v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
 
 	switch (trigger) {
 		case VEHICLE_TRIGGER_NEW_CARGO:
--- a/src/newgrf_house.cpp
+++ b/src/newgrf_house.cpp
@@ -606,8 +606,9 @@
 
 	byte new_random_bits = Random();
 	byte random_bits = GetHouseRandomBits(tile);
-	random_bits &= ~object.reseed;
-	random_bits |= (first ? new_random_bits : base_random) & object.reseed;
+	uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding
+	random_bits &= ~reseed;
+	random_bits |= (first ? new_random_bits : base_random) & reseed;
 	SetHouseRandomBits(tile, random_bits);
 
 	switch (trigger) {
--- a/src/newgrf_industrytiles.cpp
+++ b/src/newgrf_industrytiles.cpp
@@ -369,7 +369,14 @@
 	return ret;
 }
 
-static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, Industry *ind)
+/**
+ * Trigger random triggers for an industry tile and reseed its random bits.
+ * @param tile Industry tile to trigger.
+ * @param trigger Trigger to trigger.
+ * @param ind Industry of the tile.
+ * @param [in,out] reseed_industry Collects bits to reseed for the industry.
+ */
+static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, Industry *ind, uint32 &reseed_industry)
 {
 	ResolverObject object;
 
@@ -390,24 +397,55 @@
 
 	byte new_random_bits = Random();
 	byte random_bits = GetIndustryRandomBits(tile);
-	random_bits &= ~object.reseed;
-	random_bits |= new_random_bits & object.reseed;
+	random_bits &= ~object.reseed[VSG_SCOPE_SELF];
+	random_bits |= new_random_bits & object.reseed[VSG_SCOPE_SELF];
 	SetIndustryRandomBits(tile, random_bits);
 	MarkTileDirtyByTile(tile);
+
+	reseed_industry |= object.reseed[VSG_SCOPE_PARENT];
 }
 
+/**
+ * Reseeds the random bits of an industry.
+ * @param ind Industry.
+ * @param reseed Bits to reseed.
+ */
+static void DoReseedIndustry(Industry *ind, uint32 reseed)
+{
+	if (reseed == 0 || ind == NULL) return;
+
+	uint16 random_bits = Random();
+	ind->random &= reseed;
+	ind->random |= random_bits & reseed;
+}
+
+/**
+ * Trigger a random trigger for a single industry tile.
+ * @param tile Industry tile to trigger.
+ * @param trigger Trigger to trigger.
+ */
 void TriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger)
 {
-	DoTriggerIndustryTile(tile, trigger, Industry::GetByTile(tile));
+	uint32 reseed_industry = 0;
+	Industry *ind = Industry::GetByTile(tile);
+	DoTriggerIndustryTile(tile, trigger, ind, reseed_industry);
+	DoReseedIndustry(ind, reseed_industry);
 }
 
+/**
+ * Trigger a random trigger for all industry tiles.
+ * @param ind Industry to trigger.
+ * @param trigger Trigger to trigger.
+ */
 void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger)
 {
+	uint32 reseed_industry = 0;
 	TILE_AREA_LOOP(tile, ind->location) {
 		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) {
-			DoTriggerIndustryTile(tile, trigger, ind);
+			DoTriggerIndustryTile(tile, trigger, ind, reseed_industry);
 		}
 	}
+	DoReseedIndustry(ind, reseed_industry);
 }
 
 /**
--- a/src/newgrf_spritegroup.cpp
+++ b/src/newgrf_spritegroup.cpp
@@ -207,7 +207,7 @@
 
 		if (res) {
 			waiting_triggers &= ~match;
-			object->reseed |= (this->num_groups - 1) << this->lowest_randbit;
+			object->reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit;
 		} else {
 			waiting_triggers |= object->trigger;
 		}
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -122,12 +122,15 @@
 
 /* Shared by deterministic and random groups. */
 enum VarSpriteGroupScope {
-	VSG_SCOPE_SELF,
-	/* Engine of consists for vehicles, city for stations. */
-	VSG_SCOPE_PARENT,
-	/* Any vehicle in the consist (vehicles only) */
-	VSG_SCOPE_RELATIVE,
+	VSG_BEGIN,
+
+	VSG_SCOPE_SELF = VSG_BEGIN, ///< Resolved object itself
+	VSG_SCOPE_PARENT,           ///< Related object of the resolved one
+	VSG_SCOPE_RELATIVE,         ///< Relative position (vehicles only)
+
+	VSG_END
 };
+DECLARE_POSTFIX_INCREMENT(VarSpriteGroupScope)
 
 enum DeterministicSpriteGroupSize {
 	DSG_SIZE_BYTE,
@@ -309,7 +312,7 @@
 	byte trigger;
 
 	uint32 last_value;          ///< Result of most recent DeterministicSpriteGroup (including procedure calls)
-	uint32 reseed;              ///< Collects bits to rerandomise while triggering triggers.
+	uint32 reseed[VSG_END];     ///< Collects bits to rerandomise while triggering triggers.
 
 	VarSpriteGroupScope scope;  ///< Scope of currently resolved DeterministicSpriteGroup resp. RandomizedSpriteGroup
 	byte count;                 ///< Additional scope for RandomizedSpriteGroup
@@ -383,6 +386,20 @@
 	void (*StorePSA)(struct ResolverObject*, uint, int32);
 
 	/**
+	 * Returns the OR-sum of all bits that need reseeding
+	 * independent of the scope they were accessed with.
+	 * @return OR-sum of the bits.
+	 */
+	uint32 GetReseedSum() const
+	{
+		uint32 sum = 0;
+		for (VarSpriteGroupScope vsg = VSG_BEGIN; vsg < VSG_END; vsg++) {
+			sum |= this->reseed[vsg];
+		}
+		return sum;
+	}
+
+	/**
 	 * Resets the dynamic state of the resolver object.
 	 * To be called before resolving an Action-1-2-3 chain.
 	 */
@@ -390,7 +407,7 @@
 	{
 		this->last_value = 0;
 		this->trigger    = 0;
-		this->reseed     = 0;
+		memset(this->reseed, 0, sizeof(this->reseed));
 	}
 };