mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 07:35:42 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cc6ea9a02 |
+10
-3
@@ -297,10 +297,14 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
gs: GameState,
|
||||
fr: FunctionalRandom
|
||||
): RandomState[Vector[(ProvinceId, HeroC, NameInfo)]] = {
|
||||
// Collect nameTextIds of all existing heroes to avoid duplicates
|
||||
val existingNameTextIds = gs.heroes.values.map(_.nameTextId).toSet
|
||||
|
||||
def go(
|
||||
toCheck: Iterable[ProvinceId],
|
||||
nextHid: HeroId,
|
||||
currentGenerator: HeroGenerator,
|
||||
usedNameTextIds: Set[String],
|
||||
acc: RandomState[Vector[(ProvinceId, HeroC, NameInfo)]]
|
||||
): RandomState[Vector[(ProvinceId, HeroC, NameInfo)]] =
|
||||
acc.continue {
|
||||
@@ -310,12 +314,13 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
fr.nextDouble match {
|
||||
case RandomState(d, nextFr) =>
|
||||
if d >= NewHeroChance.doubleValue then
|
||||
go(toCheck.drop(1), nextHid, currentGenerator, RandomState(innerAcc, nextFr))
|
||||
go(toCheck.drop(1), nextHid, currentGenerator, usedNameTextIds, RandomState(innerAcc, nextFr))
|
||||
else
|
||||
currentGenerator
|
||||
.getHero(
|
||||
.getHeroExcluding(
|
||||
random = nextFr,
|
||||
hid = nextHid
|
||||
hid = nextHid,
|
||||
usedNameTextIds = usedNameTextIds
|
||||
)
|
||||
.continue {
|
||||
case ((HeroGenerationResponse(hero, nameInfo), newGenerator), fr2) =>
|
||||
@@ -323,6 +328,7 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
toCheck.drop(1),
|
||||
nextHid + 1,
|
||||
newGenerator,
|
||||
usedNameTextIds + hero.nameTextId,
|
||||
RandomState(
|
||||
innerAcc :+ (toCheck.head, hero.copy(id = nextHid), nameInfo),
|
||||
fr2
|
||||
@@ -336,6 +342,7 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
toCheck = gs.provinces.keys,
|
||||
nextHid = gs.heroes.values.map(_.id).max + 1,
|
||||
currentGenerator = heroGenerator,
|
||||
usedNameTextIds = existingNameTextIds,
|
||||
acc = RandomState(Vector(), fr)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,19 +44,37 @@ class HeroGenerator private (
|
||||
final def getHero(
|
||||
random: FunctionalRandom,
|
||||
hid: HeroId
|
||||
): RandomState[(HeroGenerationResponse, HeroGenerator)] =
|
||||
getHeroExcluding(random, hid, Set.empty)
|
||||
|
||||
/**
|
||||
* Get a hero, skipping any whose nameTextId is in the usedNameTextIds set. This prevents duplicate heroes when the
|
||||
* generator state isn't properly preserved between rounds.
|
||||
*
|
||||
* Cost: O(k) where k is the number of duplicates to skip (usually 0).
|
||||
*/
|
||||
final def getHeroExcluding(
|
||||
random: FunctionalRandom,
|
||||
hid: HeroId,
|
||||
usedNameTextIds: Set[String]
|
||||
): RandomState[(HeroGenerationResponse, HeroGenerator)] = {
|
||||
if remainingPregeneratedHeroes.isEmpty then
|
||||
// Find the first hero not already used
|
||||
val (skipped, remaining) = remainingPregeneratedHeroes.span(h => usedNameTextIds.contains(h.hero.nameTextId))
|
||||
|
||||
if remaining.isEmpty then
|
||||
throw new EagleInternalException(
|
||||
s"Pregenerated heroes exhausted, no hero with id $hid"
|
||||
s"No pregenerated heroes available (skipped ${skipped.size} duplicates, no hero with id $hid)"
|
||||
)
|
||||
val nextHero = remainingPregeneratedHeroes.head
|
||||
.copy(hero = remainingPregeneratedHeroes.head.hero.copy(id = hid))
|
||||
|
||||
val nextHero = remaining.head
|
||||
.copy(hero = remaining.head.hero.copy(id = hid))
|
||||
internalRequire(
|
||||
nextHero.hero.backstoryVersions.nonEmpty,
|
||||
s"Pregenerated hero ${nextHero.name} has no backstory text"
|
||||
)
|
||||
val response = HeroGenerationResponse(hero = nextHero.hero, nameInfo = NoNameRequest)
|
||||
val newGenerator = new HeroGenerator(remainingPregeneratedHeroes.tail)
|
||||
// Remove the used hero and any skipped ones from the pool
|
||||
val newGenerator = new HeroGenerator(remaining.tail)
|
||||
RandomState((response, newGenerator), random)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user