v1.3.0: improved item drop consistency for seeded runs

This commit is contained in:
Evan Debenham
2022-05-16 15:44:41 -04:00
parent e031a3db51
commit 7de072c2a7
9 changed files with 70 additions and 29 deletions

View File

@@ -220,10 +220,10 @@ public class Eye extends Mob {
}
break;
case 2:
loot = Generator.random(Generator.Category.SEED);
loot = Generator.randomUsingDefaults(Generator.Category.SEED);
break;
case 3:
loot = Generator.random(Generator.Category.STONE);
loot = Generator.randomUsingDefaults(Generator.Category.STONE);
break;
}
return loot;

View File

@@ -789,7 +789,7 @@ public abstract class Mob extends Char {
Item item;
if (loot instanceof Generator.Category) {
item = Generator.random( (Generator.Category)loot );
item = Generator.randomUsingDefaults( (Generator.Category)loot );
} else if (loot instanceof Class<?>) {

View File

@@ -140,11 +140,11 @@ public class Warlock extends Mob implements Callback {
Dungeon.LimitedDrops.WARLOCK_HP.count++;
return new PotionOfHealing();
} else {
Item i = Generator.random(Generator.Category.POTION);
Item i = Generator.randomUsingDefaults(Generator.Category.POTION);
int healingTried = 0;
while (i instanceof PotionOfHealing){
healingTried++;
i = Generator.random(Generator.Category.POTION);
i = Generator.randomUsingDefaults(Generator.Category.POTION);
}
//return the attempted healing potion drops to the pool

View File

@@ -215,9 +215,14 @@ public class Generator {
//Artifacts in particular don't reset, no duplicates!
public float[] probs;
public float[] defaultProbs = null;
//These variables are used as a part of the deck system, to ensure that drops are consistent
// regardless of when they occur (either as part of seeded levelgen, or random item drops)
public Long seed = null;
public int dropped = 0;
//game has two decks of 35 items for overall category probs
//one deck has a ring and extra armor, the other has an artifact and extra thrown weapon
//Note that pure random drops only happen as part of levelgen atm, so no seed is needed here
public float firstProb;
public float secondProb;
public Class<? extends Item> superClass;
@@ -480,6 +485,10 @@ public class Generator {
generalReset();
for (Category cat : Category.values()) {
reset(cat);
if (cat.defaultProbs != null) {
cat.seed = Random.Long();
cat.dropped = 0;
}
}
}
@@ -501,7 +510,15 @@ public class Generator {
cat = Random.chances( categoryProbs );
}
categoryProbs.put( cat, categoryProbs.get( cat ) - 1);
return random( cat );
if (cat == Category.SEED) {
//We specifically use defaults for seeds here because, unlike other item categories
// their predominant source of drops is grass, not levelgen. This way the majority
// of seed drops still use a deck, but the few that are spawned by levelgen are consistent
return randomUsingDefaults(cat);
} else {
return random(cat);
}
}
public static Item random( Category cat ) {
@@ -517,20 +534,32 @@ public class Generator {
//if we're out of artifacts, return a ring instead.
return item != null ? item : random(Category.RING);
default:
if (cat.defaultProbs != null && cat.seed != null){
Random.pushGenerator(cat.seed);
for (int i = 0; i < cat.dropped; i++) Random.Long();
}
int i = Random.chances(cat.probs);
if (i == -1) {
reset(cat);
i = Random.chances(cat.probs);
}
if (cat.defaultProbs != null) cat.probs[i]--;
if (cat.defaultProbs != null && cat.seed != null){
Random.popGenerator();
cat.dropped++;
}
return ((Item) Reflection.newInstance(cat.classes[i])).random();
}
}
//overrides any deck systems and always uses default probs
// except for artifacts, which must always use a deck
public static Item randomUsingDefaults( Category cat ){
if (cat.defaultProbs == null) {
return random(cat); //currently covers weapons/armor/missiles
if (cat.defaultProbs == null || cat == Category.ARTIFACT) {
return random(cat);
} else {
return ((Item) Reflection.newInstance(cat.classes[Random.chances(cat.defaultProbs)])).random();
}
@@ -601,8 +630,19 @@ public class Generator {
public static Artifact randomArtifact() {
Category cat = Category.ARTIFACT;
if (cat.defaultProbs != null && cat.seed != null){
Random.pushGenerator(cat.seed);
for (int i = 0; i < cat.dropped; i++) Random.Long();
}
int i = Random.chances( cat.probs );
if (cat.defaultProbs != null && cat.seed != null){
Random.popGenerator();
cat.dropped++;
}
//if no artifacts are left, return null
if (i == -1){
return null;
@@ -627,7 +667,9 @@ public class Generator {
private static final String FIRST_DECK = "first_deck";
private static final String GENERAL_PROBS = "general_probs";
private static final String CATEGORY_PROBS = "_probs";
private static final String CATEGORY_SEED = "_seed";
private static final String CATEGORY_DROPPED = "_dropped";
public static void storeInBundle(Bundle bundle) {
bundle.put(FIRST_DECK, usingFirstDeck);
@@ -640,16 +682,11 @@ public class Generator {
for (Category cat : Category.values()){
if (cat.defaultProbs == null) continue;
boolean needsStore = false;
for (int i = 0; i < cat.probs.length; i++){
if (cat.probs[i] != cat.defaultProbs[i]){
needsStore = true;
break;
}
}
if (needsStore){
bundle.put(cat.name().toLowerCase() + CATEGORY_PROBS, cat.probs);
bundle.put(cat.name().toLowerCase() + CATEGORY_PROBS, cat.probs);
if (cat.seed != null) {
bundle.put(cat.name().toLowerCase() + CATEGORY_SEED, cat.seed);
bundle.put(cat.name().toLowerCase() + CATEGORY_DROPPED, cat.dropped);
}
}
}
@@ -672,6 +709,10 @@ public class Generator {
if (cat.defaultProbs != null && probs.length == cat.defaultProbs.length){
cat.probs = probs;
}
if (bundle.contains(cat.name().toLowerCase() + CATEGORY_SEED)){
cat.seed = bundle.getLong(cat.name().toLowerCase() + CATEGORY_SEED);
cat.dropped = bundle.getInt(cat.name().toLowerCase() + CATEGORY_DROPPED);
}
}
}

View File

@@ -56,7 +56,7 @@ public class Berry extends Food {
super.satisfy(hero);
SeedCounter counter = Buff.count(hero, SeedCounter.class, 1);
if (counter.count() >= 2){
Dungeon.level.drop(Generator.random(Generator.Category.SEED), hero.pos).sprite.drop();
Dungeon.level.drop(Generator.randomUsingDefaults(Generator.Category.SEED), hero.pos).sprite.drop();
counter.detach();
}
}

View File

@@ -197,11 +197,11 @@ public class RingOfWealth extends Ring {
Item i = new Gold().random();
return i.quantity(i.quantity()/2);
case 1:
return Generator.random(Generator.Category.STONE);
return Generator.randomUsingDefaults(Generator.Category.STONE);
case 2:
return Generator.random(Generator.Category.POTION);
return Generator.randomUsingDefaults(Generator.Category.POTION);
case 3:
return Generator.random(Generator.Category.SCROLL);
return Generator.randomUsingDefaults(Generator.Category.SCROLL);
}
}

View File

@@ -266,7 +266,7 @@ public class ScrollOfTransmutation extends InventoryScroll {
Plant.Seed n;
do {
n = (Plant.Seed)Generator.random( Generator.Category.SEED );
n = (Plant.Seed)Generator.randomUsingDefaults( Generator.Category.SEED );
} while (n.getClass() == s.getClass());
return n;
@@ -277,7 +277,7 @@ public class ScrollOfTransmutation extends InventoryScroll {
Runestone n;
do {
n = (Runestone) Generator.random( Generator.Category.STONE );
n = (Runestone) Generator.randomUsingDefaults( Generator.Category.STONE );
} while (n.getClass() == r.getClass());
return n;

View File

@@ -64,19 +64,19 @@ public class Recycle extends InventorySpell {
Item result;
do {
if (item instanceof Potion) {
result = Generator.random(Generator.Category.POTION);
result = Generator.randomUsingDefaults(Generator.Category.POTION);
if (item instanceof ExoticPotion){
result = Reflection.newInstance(ExoticPotion.regToExo.get(result.getClass()));
}
} else if (item instanceof Scroll) {
result = Generator.random(Generator.Category.SCROLL);
result = Generator.randomUsingDefaults(Generator.Category.SCROLL);
if (item instanceof ExoticScroll){
result = Reflection.newInstance(ExoticScroll.regToExo.get(result.getClass()));
}
} else if (item instanceof Plant.Seed) {
result = Generator.random(Generator.Category.SEED);
result = Generator.randomUsingDefaults(Generator.Category.SEED);
} else if (item instanceof Runestone) {
result = Generator.random(Generator.Category.STONE);
result = Generator.randomUsingDefaults(Generator.Category.STONE);
} else {
result = TippedDart.randomTipped(1);
}

View File

@@ -379,7 +379,7 @@ public class WandOfRegrowth extends Wand {
for (int i = 0; i < nSeeds && !candidates.isEmpty(); i++){
Integer c = Random.element(candidates);
Dungeon.level.drop(Generator.random(Generator.Category.SEED), c).sprite.drop(pos);
Dungeon.level.drop(Generator.randomUsingDefaults(Generator.Category.SEED), c).sprite.drop(pos);
candidates.remove(c);
}