v1.3.0: improved how the game handles seeds and PRNG internally

This commit is contained in:
Evan Debenham
2022-04-26 16:00:37 -04:00
parent ede0439ab8
commit 23fd824789
6 changed files with 26 additions and 7 deletions

View File

@@ -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(){

View File

@@ -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();

View File

@@ -109,7 +109,8 @@ public class YogDzewa extends Mob {
private ArrayList<Class> fistSummons = new ArrayList<>();
private ArrayList<Class> 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);

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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"));
}