mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 20:55:44 +00:00
Prioritize valuable safe upgrade quests (#8705)
This commit is contained in:
+49
-10
@@ -1,6 +1,6 @@
|
||||
package net.eagle0.eagle.library.util.command_choice_helpers.quest_command_selectors
|
||||
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.library.settings.PortionOfCapacityForUpgradeBattalionQuest
|
||||
import net.eagle0.eagle.library.util.command_choice_helpers.{
|
||||
ImproveCommandSelector,
|
||||
@@ -33,6 +33,7 @@ import net.eagle0.eagle.model.state.command.selected.SelectedCommand.{
|
||||
VisitTownSelected
|
||||
}
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.hero.Profession.Mage
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.UpgradeBattalionQuest
|
||||
|
||||
@@ -45,10 +46,10 @@ object UpgradeBattalionQuestCommandChooser extends DeterministicQuestCommandChoo
|
||||
uhsWithQuests: Vector[UnaffiliatedHeroWithQuest]
|
||||
): Option[CommandSelection] =
|
||||
uhsWithQuests.collect {
|
||||
case UnaffiliatedHeroWithQuest(pid, _, q: UpgradeBattalionQuest) => (pid, q)
|
||||
case UnaffiliatedHeroWithQuest(pid, heroId, q: UpgradeBattalionQuest) => (pid, heroId, q)
|
||||
}.iterator.flatMap {
|
||||
case (questPid, quest) =>
|
||||
commandForQuest(actingFactionId, gameState, availableCommands, questPid, quest).iterator
|
||||
case (questPid, questHeroId, quest) =>
|
||||
commandForQuest(actingFactionId, gameState, availableCommands, questPid, questHeroId, quest).iterator
|
||||
}.nextOption()
|
||||
|
||||
private def commandForQuest(
|
||||
@@ -56,6 +57,7 @@ object UpgradeBattalionQuestCommandChooser extends DeterministicQuestCommandChoo
|
||||
gameState: GameState,
|
||||
availableCommands: Vector[AvailableCommand],
|
||||
questPid: ProvinceId,
|
||||
questHeroId: HeroId,
|
||||
quest: UpgradeBattalionQuest
|
||||
): Option[CommandSelection] = {
|
||||
val province = gameState.provinces(questPid)
|
||||
@@ -83,15 +85,52 @@ object UpgradeBattalionQuestCommandChooser extends DeterministicQuestCommandChoo
|
||||
)
|
||||
.orElse(trainCompletes(actingFactionId, availableCommands, province, quest, full))
|
||||
.orElse(marchPrequalified(actingFactionId, gameState, availableCommands, questPid, quest, bt, full))
|
||||
.orElse(organizeInQuestProvince(actingFactionId, gameState, availableCommands, province, quest, matching))
|
||||
.orElse(marchUnqualified(actingFactionId, gameState, availableCommands, questPid, quest, bt, full))
|
||||
.orElse(developForBattalionType(actingFactionId, gameState, availableCommands, province, quest, bt, matching))
|
||||
.orElse(trainProgress(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
.orElse(developInfrastructure(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
.orElse(armProgress(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
.orElse {
|
||||
Option
|
||||
.when(
|
||||
isHighValueQuestGiver(gameState, questHeroId) &&
|
||||
isSafeForLongPreparation(actingFactionId, gameState, province)
|
||||
) {
|
||||
organizeInQuestProvince(actingFactionId, gameState, availableCommands, province, quest, matching)
|
||||
.orElse(marchUnqualified(actingFactionId, gameState, availableCommands, questPid, quest, bt, full))
|
||||
.orElse(
|
||||
developForBattalionType(
|
||||
actingFactionId,
|
||||
gameState,
|
||||
availableCommands,
|
||||
province,
|
||||
quest,
|
||||
bt,
|
||||
matching
|
||||
)
|
||||
)
|
||||
.orElse(trainProgress(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
.orElse(developInfrastructure(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
.orElse(armProgress(actingFactionId, availableCommands, province, quest, best, threshold))
|
||||
}
|
||||
.flatten
|
||||
.map(_.withOuterReason("safe province and high-value Mage quest giver"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def isHighValueQuestGiver(gameState: GameState, questHeroId: HeroId): Boolean =
|
||||
gameState.heroes.get(questHeroId).exists(_.profession == Mage)
|
||||
|
||||
private def isSafeForLongPreparation(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
province: ProvinceT
|
||||
): Boolean = {
|
||||
val factions = gameState.factions.values.toVector
|
||||
FactionUtils
|
||||
.hostileNeighbors(province, actingFactionId, gameState.provinces, factions)
|
||||
.isEmpty &&
|
||||
!province.incomingArmies.exists(incomingArmy =>
|
||||
FactionUtils.factionsAreHostile(actingFactionId, incomingArmy.army.factionId, factions)
|
||||
)
|
||||
}
|
||||
|
||||
private def armCostFor(
|
||||
costPerTroop: Double,
|
||||
oldArmament: Double,
|
||||
|
||||
+122
-4
@@ -2,7 +2,7 @@ package net.eagle0.eagle.library.util.command_choice_helpers.quest_command_selec
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.library.settings.{FoodIncreasePerAgriculture, GoldPerHeroHeldBack, MinSupportForTaxes}
|
||||
import net.eagle0.eagle.model.state.{BattalionType, BattalionTypeId, GameType, RoundPhase}
|
||||
import net.eagle0.eagle.model.state.{Army, BattalionType, BattalionTypeId, GameType, MovingArmy, RoundPhase, Supplies}
|
||||
import net.eagle0.eagle.model.state.battalion.concrete.BattalionC
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand.{
|
||||
ArmTroopsAvailable,
|
||||
@@ -36,6 +36,8 @@ import net.eagle0.eagle.model.state.date.Date.Month.June
|
||||
import net.eagle0.eagle.model.state.faction.concrete.FactionC
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.hero.concrete.HeroC
|
||||
import net.eagle0.eagle.model.state.hero.Profession
|
||||
import net.eagle0.eagle.model.state.hero.Profession.{Mage, NoProfession}
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.state.province.Neighbor
|
||||
import net.eagle0.eagle.model.state.quest.{ImproveAgricultureQuest, UpgradeBattalionQuest}
|
||||
@@ -116,10 +118,12 @@ class UpgradeBattalionQuestCommandChooserTest extends AnyFlatSpec with Matchers
|
||||
province: ProvinceC,
|
||||
battalions: Map[BattalionId, BattalionC] = Map.empty,
|
||||
otherProvinces: Map[ProvinceId, ProvinceC] = Map.empty,
|
||||
extraHeroes: Map[HeroId, HeroC] = Map.empty
|
||||
extraHeroes: Map[HeroId, HeroC] = Map.empty,
|
||||
extraFactions: Map[FactionId, FactionC] = Map.empty,
|
||||
questHeroProfession: Profession = Mage
|
||||
): GameState = {
|
||||
val factionLeader = HeroC(id = factionLeaderId, factionId = Some(actingFactionId))
|
||||
val questHero = HeroC(id = questHeroId, factionId = None)
|
||||
val questHero = HeroC(id = questHeroId, factionId = None, profession = questHeroProfession)
|
||||
val faction = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = factionLeaderId,
|
||||
@@ -136,7 +140,7 @@ class UpgradeBattalionQuestCommandChooserTest extends AnyFlatSpec with Matchers
|
||||
heroes = Map(factionLeaderId -> factionLeader, questHeroId -> questHero) ++ extraHeroes,
|
||||
battalions = battalions,
|
||||
destroyedBattalions = Map.empty,
|
||||
factions = Map(actingFactionId -> faction),
|
||||
factions = Map(actingFactionId -> faction) ++ extraFactions,
|
||||
factionCommandCounts = Map.empty,
|
||||
killedHeroes = Map.empty,
|
||||
destroyedFactions = Map.empty,
|
||||
@@ -633,6 +637,120 @@ class UpgradeBattalionQuestCommandChooserTest extends AnyFlatSpec with Matchers
|
||||
}
|
||||
}
|
||||
|
||||
it should "not begin long preparation for an ordinary quest giver" in {
|
||||
val gs = makeGameState(
|
||||
province = baseProvince,
|
||||
questHeroProfession = NoProfession
|
||||
)
|
||||
|
||||
val result = UpgradeBattalionQuestCommandChooser.chosenDeterministicCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommands = Vector(organizeAvailable),
|
||||
uhsWithQuests = questUhs
|
||||
)
|
||||
|
||||
result shouldBe None
|
||||
}
|
||||
|
||||
it should "not begin long preparation for a Mage quest giver on a hostile border" in {
|
||||
val enemyFactionId = 2
|
||||
val enemyProvince = ProvinceC(
|
||||
id = neighborProvinceId,
|
||||
rulingFactionId = Some(enemyFactionId),
|
||||
neighbors = Vector(Neighbor(provinceId = provinceId, startingPositionIndex = 0))
|
||||
)
|
||||
val questProvince = baseProvince.copy(
|
||||
neighbors = Vector(Neighbor(provinceId = neighborProvinceId, startingPositionIndex = 0))
|
||||
)
|
||||
val enemyFaction = FactionC(
|
||||
id = enemyFactionId,
|
||||
factionHeadId = 0,
|
||||
name = "Enemy Faction",
|
||||
leaderIds = Vector.empty
|
||||
)
|
||||
val gs = makeGameState(
|
||||
province = questProvince,
|
||||
otherProvinces = Map(neighborProvinceId -> enemyProvince),
|
||||
extraFactions = Map(enemyFactionId -> enemyFaction)
|
||||
)
|
||||
|
||||
val result = UpgradeBattalionQuestCommandChooser.chosenDeterministicCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommands = Vector(organizeAvailable),
|
||||
uhsWithQuests = questUhs
|
||||
)
|
||||
|
||||
result shouldBe None
|
||||
}
|
||||
|
||||
it should "not begin long preparation for a Mage quest giver facing a hostile incoming army" in {
|
||||
val enemyFactionId = 2
|
||||
val enemyFaction = FactionC(
|
||||
id = enemyFactionId,
|
||||
factionHeadId = 0,
|
||||
name = "Enemy Faction",
|
||||
leaderIds = Vector.empty
|
||||
)
|
||||
val questProvince = baseProvince.copy(
|
||||
incomingArmies = Vector(
|
||||
MovingArmy(
|
||||
id = 1,
|
||||
army = Army(factionId = enemyFactionId, units = Vector.empty),
|
||||
arrivalRound = 1,
|
||||
destinationProvinceId = provinceId,
|
||||
originProvinceId = neighborProvinceId,
|
||||
supplies = Supplies(gold = 0, food = 0),
|
||||
suppliesLoss = 0.0,
|
||||
startingPositionIndex = None
|
||||
)
|
||||
)
|
||||
)
|
||||
val gs = makeGameState(
|
||||
province = questProvince,
|
||||
extraFactions = Map(enemyFactionId -> enemyFaction)
|
||||
)
|
||||
|
||||
val result = UpgradeBattalionQuestCommandChooser.chosenDeterministicCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommands = Vector(organizeAvailable),
|
||||
uhsWithQuests = questUhs
|
||||
)
|
||||
|
||||
result shouldBe None
|
||||
}
|
||||
|
||||
it should "allow an ordinary quest giver's immediate completion step" in {
|
||||
val province = baseProvince.copy(battalionIds = Vector(battalionId1))
|
||||
val battalions = Map(
|
||||
battalionId1 -> BattalionC(
|
||||
id = battalionId1,
|
||||
typeId = BattalionTypeId.LightInfantry,
|
||||
size = 800,
|
||||
armament = 0.0,
|
||||
training = 0.5
|
||||
)
|
||||
)
|
||||
val gs = makeGameState(
|
||||
province = province,
|
||||
battalions = battalions,
|
||||
questHeroProfession = NoProfession
|
||||
)
|
||||
|
||||
val result = UpgradeBattalionQuestCommandChooser.chosenDeterministicCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommands = Vector(armTroopsAvailable),
|
||||
uhsWithQuests = questUhs
|
||||
)
|
||||
|
||||
inside(result) {
|
||||
case Some(command) => command.selected shouldBe a[ArmTroopsSelected]
|
||||
}
|
||||
}
|
||||
|
||||
it should "develop Infrastructure when the armament target exceeds infrastructure (Step G)" in {
|
||||
val province = baseProvince.copy(
|
||||
infrastructure = 1.0,
|
||||
|
||||
Reference in New Issue
Block a user