diff --git a/SPD-classes/src/main/java/com/watabou/utils/Random.java b/SPD-classes/src/main/java/com/watabou/utils/Random.java index 25a5b417a..f427cf14c 100644 --- a/SPD-classes/src/main/java/com/watabou/utils/Random.java +++ b/SPD-classes/src/main/java/com/watabou/utils/Random.java @@ -49,7 +49,20 @@ public class Random { } public static synchronized void pushGenerator( long seed ){ - generators.push( new java.util.Random( seed ) ); + generators.push( new java.util.Random( scrambleSeed(seed) ) ); + } + + //scrambles a given seed, this helps eliminate patterns between the outputs of similar seeds + //Algorithm used is MX3 by Jon Maiga (jonkagstrom.com), CC0 license. + private static synchronized long scrambleSeed( long seed ){ + seed ^= seed >>> 32; + seed *= 0xbea225f9eb34556dL; + seed ^= seed >>> 29; + seed *= 0xbea225f9eb34556dL; + seed ^= seed >>> 32; + seed *= 0xbea225f9eb34556dL; + seed ^= seed >>> 29; + return seed; } public static synchronized void popGenerator(){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index a97e86b5f..bce97b5e3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -190,8 +190,9 @@ public class Dungeon { Actor.clear(); Actor.resetNextID(); - - Random.pushGenerator( seed ); + + //offset seed slightly to avoid output patterns + Random.pushGenerator( seed+1 ); Scroll.initLabels(); Potion.initColors(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java index 395a75d7b..2b9893ad2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java @@ -109,7 +109,8 @@ public class YogDzewa extends Mob { private ArrayList fistSummons = new ArrayList<>(); private ArrayList challengeSummons = new ArrayList<>(); { - Random.pushGenerator(Dungeon.seedCurDepth()); + //offset seed slightly to avoid output patterns + Random.pushGenerator(Dungeon.seedCurDepth()+1); fistSummons.add(Random.Int(2) == 0 ? YogFist.BurningFist.class : YogFist.SoiledFist.class); fistSummons.add(Random.Int(2) == 0 ? YogFist.RottingFist.class : YogFist.RustedFist.class); fistSummons.add(Random.Int(2) == 0 ? YogFist.BrightFist.class : YogFist.DarkFist.class); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java index 85523caac..534c46260 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java @@ -387,7 +387,8 @@ public abstract class RegularLevel extends Level { } //use a separate generator for this to prevent held items, meta progress, and talents from affecting levelgen - Random.pushGenerator( Dungeon.seedCurDepth() ); + //we can use a random long for the seed as it will be the same long every time + Random.pushGenerator( Random.Long() ); Item item = Bones.get(); if (item != null) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/ShopRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/ShopRoom.java index e806d3d63..0be7b5345 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/ShopRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/ShopRoom.java @@ -270,10 +270,12 @@ public class ShopRoom extends SpecialRoom { itemsToSpawn.add( rare ); //hard limit is 63 items + 1 shopkeeper, as shops can't be bigger than 8x8=64 internally - if (itemsToSpawn.size() > 63) + if (itemsToSpawn.size() > 63) { throw new RuntimeException("Shop attempted to carry more than 63 items!"); + } //use a new generator here to prevent items in shop stock affecting levelgen RNG (e.g. sandbags) + //we can use a random long for the seed as it will be the same long every time Random.pushGenerator(Random.Long()); Random.shuffle(itemsToSpawn); Random.popGenerator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index a56d25932..28ec4a32f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -526,7 +526,8 @@ public class GameScene extends PixelScene { } //50%/75% chance, use level's seed so that we get the same result for the same level - Random.pushGenerator(Dungeon.seedCurDepth()); + //offset seed slightly to avoid output patterns + Random.pushGenerator(Dungeon.seedCurDepth()+1); if (reqSecrets <= 0 && Random.Int(4) <= Dungeon.hero.pointsInTalent(Talent.ROGUES_FORESIGHT)){ GLog.p(Messages.get(this, "secret_hint")); }