Adds a deterministic chooser that walks a priority tree per turn toward
fulfilling an UpgradeBattalionQuest: arm-completes (optionally preceded by
travel and/or a safe food sale to cover the gold cost) -> train-completes
-> march in a pre-qualified neighbor battalion -> organize/top-off of the
quest battalion type -> march in an unqualified neighbor battalion ->
develop Economy/Agriculture -> train progress -> develop Infrastructure
-> arm progress. Travel is only toggled when it directly enables an
arm-completes finisher, to avoid fragile multi-turn plans.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* Add FightBeastsAloneQuest AI quest handler
When an unaffiliated hero offers a FightBeastsAloneQuest, the AI now
sends the weakest expendable non-leader hero to fight beasts without a
battalion. Only heroes weaker than the quest-giving hero are considered,
since the hero will almost certainly die.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add MaxExpendableHeroPowerRatio setting for FightBeastsAloneQuest
Hero must have power at most 75% of the quest-giving hero's power to
be considered expendable, ensuring the trade is clearly worthwhile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add MaxExpendableHeroPowerRatio to settings.tsv and regenerate loader BUILD
The new setting was added to the settings BUILD.bazel but was missing from the
TSV source file, causing the auto-generated settings_loader to lack the dep.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add BattalionDiversityQuest AI quest handler
When an unaffiliated hero offers a BattalionDiversityQuest, the AI now
hires one battalion of a type it doesn't already have. Only types where
the province meets development requirements are considered, and the
province must have sufficient gold and food surplus.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Only hire battalion when it would reach 3+ distinct types
The quest requires 3+ different types at near-full capacity. Skip
hiring if the province has fewer than 2 existing types, since adding
one more wouldn't reach the required 3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Reorganize the "Does Not Attempt" section into a prioritized plan for
future implementation and a list of quests not planned for active
pursuit.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When an unaffiliated hero has a SuppressRiotByForceQuest and the faction
has battalions available, the AI now prefers CrackDown over Give when
handling riots. This modifies the existing riot handler priority rather
than adding a quest command chooser, since riot handling runs before
FulfillQuestsCommandSelector.
The AI estimates survival odds against a 90th-percentile riot before
committing to CrackDown, and prefers non-leader heroes to avoid risking
the faction head.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Matches the quest's target outlawHeroId against available outlaws in the
province and issues an ApprehendOutlaw command when found.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Higher priority than the count-based ReconProvincesQuest since reconning
a specific province also counts toward generic recon counts. Prefers
targets not yet reconned by the faction.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add ReconProvincesQuest AI quest handler
When an unaffiliated hero has a ReconProvincesQuest, the AI now issues
a Recon command to reconnoiter a province, helping fulfill the quest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Prioritize recon target provinces in ReconProvincesQuestCommandChooser
Sort candidates by (isNeighbor, isHostile, notRecentlyReconned) to
prefer hostile neighboring provinces that haven't been scouted recently,
matching the prioritization pattern from MidGameAIClient.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Deprioritize unowned provinces in recon target selection
Unowned provinces (no ruling faction) are now sorted last, even if
they're neighbors, since reconning owned hostile provinces is more
strategically valuable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add GrandArmyQuest AI quest handler
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address review: extract helper, use flatMap/inside, verify quest fulfillable
- Extract grandArmyTarget into a private method with pattern matching
- Replace organize match with flatMap chain
- Only return command if total troops after organizing meet the quest
target (prevents partial fulfillment)
- Replace asInstanceOf with inside() in tests
- Add test for insufficient resources to meet target
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add AI quest handlers for blizzard, drought, and epidemic own-province filtering
Create ControlWeatherQuestCommandChooser to handle StartBlizzardQuest and
StartDroughtQuest via the ControlWeather command. Update StartEpidemicQuest
CommandChooser to skip quests targeting the acting faction's own provinces.
Both handlers verify the appropriate command is available before selecting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address review: use inside() pattern and extract questTargets method
- Replace asInstanceOf with inside() pattern in ControlWeather and
StartEpidemic test assertions
- Extract questTargets into a private method in
ControlWeatherQuestCommandChooser and match directly on its result
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add DevelopProvinces and MobilizeProvinces AI quest handlers
Implement IssueOrders-based quest command choosers so the AI can
fulfill DevelopProvincesQuest and MobilizeProvincesQuest by switching
province orders. Develop prefers non-hostile-neighbor provinces;
Mobilize prefers hostile-neighbor provinces. Mobilize is skipped when
a DevelopProvincesQuest also exists to avoid conflicting orders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Extract ProvinceOrderQuestHelper to deduplicate order-switching logic
The Develop and Mobilize choosers shared nearly identical logic for
finding the IssueOrders command, counting current orders, partitioning
by hostile neighbors, and building the selection. Extract this into
ProvinceOrderQuestHelper.chooseOrders parameterized by target order
type, hostile-neighbor preference, and reason string.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove early returns from province order quest choosers
Use pattern matching, flatMap, and Option.when instead of early
returns for idiomatic Scala style.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The doc was missing 11 quest handlers that were added since it was
written: all prisoner quests, TotalDevelopment, SpendOnFeasts,
SendSupplies, RestProvince, StartEpidemic, and SwearBrotherhood.
Also fixes the priority order (Alliance is last, not first).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Documents which quests the AI proactively attempts to complete via
FulfillQuestsCommandSelector and which quests are not handled.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>