mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 03:25:41 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
473ccc341b | ||
|
|
f50db80180 | ||
|
|
e13a5e209f | ||
|
|
5d8aefb6c8 | ||
|
|
54bfe56cc4 | ||
|
|
24252d1243 | ||
|
|
d6b9edde4c | ||
|
|
3ec3d59740 | ||
|
|
c2d38fcaf4 | ||
|
|
19f54545c1 | ||
|
|
5b29ff40bc | ||
|
|
dc09ae768a | ||
|
|
ecd652d8ef | ||
|
|
27f2f07e8f | ||
|
|
21117aff42 | ||
|
|
8034474edc | ||
|
|
4b1cf06b5a | ||
|
|
fc56b5dde9 | ||
|
|
86e2212511 | ||
|
|
446d483d24 | ||
|
|
055449043f | ||
|
|
1d60e186f4 | ||
|
|
51479e9c75 | ||
|
|
ade98d20cd | ||
|
|
7820e63fe9 | ||
|
|
06f24631ff | ||
|
|
996a53b9d0 |
@@ -178,4 +178,5 @@ done
|
||||
|
||||
- Bazel handles multi-language builds and dependencies
|
||||
- CI/CD via GitHub Actions with platform-specific build scripts in `/ci/github_actions/`
|
||||
- Docker containerization available via `ci/eagle_run.Dockerfile`
|
||||
- Docker containerization available via `ci/eagle_run.Dockerfile`
|
||||
- Always run "bazel run //:gazelle" after editing any BUILD.bazel files
|
||||
+1
-9
@@ -20,13 +20,7 @@ bazel_dep(name = "rules_pkg", version = "1.1.0")
|
||||
# Language Support - Scala
|
||||
#
|
||||
|
||||
bazel_dep(name = "rules_scala")
|
||||
|
||||
git_override(
|
||||
commit = "f4523243ab5f946600c2b0d7a4b5791bb8758799",
|
||||
module_name = "rules_scala",
|
||||
remote = "https://github.com/bazel-contrib/rules_scala.git",
|
||||
)
|
||||
bazel_dep(name = "rules_scala", version = "7.1.1")
|
||||
|
||||
scala_config = use_extension(
|
||||
"@rules_scala//scala/extensions:config.bzl",
|
||||
@@ -83,8 +77,6 @@ use_repo(
|
||||
"com_github_aws_aws_sdk_go_v2_credentials",
|
||||
"com_github_aws_aws_sdk_go_v2_service_s3",
|
||||
"org_golang_google_protobuf",
|
||||
"org_golang_x_text",
|
||||
"com_github_google_go_cmp",
|
||||
)
|
||||
|
||||
#
|
||||
|
||||
Generated
+5
-3
@@ -317,6 +317,8 @@
|
||||
"https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917",
|
||||
"https://bcr.bazel.build/modules/rules_rust/0.45.1/MODULE.bazel": "a69d0db3a958fab2c6520961e1b2287afcc8b36690fd31bbc4f6f7391397150d",
|
||||
"https://bcr.bazel.build/modules/rules_scala/7.1.1/MODULE.bazel": "b1f80c52ae49b27d41b9291d8b328b69247de2b7596d35d09afe6147b82cf562",
|
||||
"https://bcr.bazel.build/modules/rules_scala/7.1.1/source.json": "5038cb231d4020c5965c920681cf961a7bf137b40315025e40f3a7b6a0ac1f0f",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3",
|
||||
@@ -1266,7 +1268,7 @@
|
||||
"@@rules_scala~//scala/extensions:config.bzl%scala_config": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "TdBxhkZTM7VU6teIFS+KoonKU7wmb5BL7leCWWx7yX8=",
|
||||
"usagesDigest": "6V8NLCEm/+v54a4/jhHtdftOmlUdkW4PPxw+IISD0Eo=",
|
||||
"usagesDigest": "z8BblsnuAs+q3LEu90nfjZZasRDCB2K31wb7NXFSZVM=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {
|
||||
@@ -1291,8 +1293,8 @@
|
||||
},
|
||||
"@@rules_scala~//scala/extensions:deps.bzl%scala_deps": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "auQqXmoQ01Gebqkny5AjUoLJjButvOXfi1JYq7gucsI=",
|
||||
"usagesDigest": "086XZ0aCCfOZmHhDfMCTOlr5OcQC3zEr2jiL87XtSm8=",
|
||||
"bzlTransitiveDigest": "F2PMm61fmZ/IE+VSw1rigJ71hBDD7k3vqyYR1/GgXeA=",
|
||||
"usagesDigest": "kwo8oolISmSSITnit4b4S0vBiUtHlHK0WLDUwScxmOg=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
# Actions and Commands Model Usage Analysis
|
||||
|
||||
This document analyzes all actions and commands in `src/main/scala/net/eagle0/eagle/library/actions/impl` to determine which use Scala models vs protobuf models, based on BUILD.bazel dependencies.
|
||||
|
||||
**Legend:**
|
||||
- ✅ **Scala Models Only** - Uses only `//src/main/scala/net/eagle0/eagle/model` dependencies
|
||||
- ❌ **Uses Protobuf** - Has dependencies on `//src/main/protobuf` targets
|
||||
- 🔄 **Partial Conversion** - Conversion attempted but blocked by dependencies
|
||||
|
||||
## Summary
|
||||
|
||||
Based on BUILD.bazel dependency analysis (2025-09-04):
|
||||
- **Total Commands Analyzed:** 40
|
||||
- **Commands Fully Migrated (No Protobuf):** 36 (90%)
|
||||
- **Commands Still Using Protobuf:** 4 (10%)
|
||||
- **Actions:** Most still have protobuf dependencies
|
||||
- **Base Classes:** 8 protoless variants available, 6 still use protobuf
|
||||
|
||||
## Conversion Insights
|
||||
|
||||
Based on conversion attempt of `ResolveTruceOfferCommand` (see [PR #4379](https://github.com/nolen777/eagle0/pull/4379)):
|
||||
|
||||
### Key Challenges Discovered
|
||||
|
||||
1. **LLM Integration Dependencies**: Commands that use `DiplomacyResolutionLlmRequestGenerator` face challenges because the LLM system still expects protobuf enum types, not Scala model enums.
|
||||
|
||||
2. **Inconsistent Package Naming**: Some files have inconsistent package declarations vs BUILD file locations (e.g., `generated_text_request_generators` in package vs `llm_request_generators` in BUILD).
|
||||
|
||||
3. **Model Constructor Differences**: Scala model constructors (e.g., `TruceOffer`) have different required parameters than their protobuf counterparts, requiring more complex data mapping.
|
||||
|
||||
4. **Type System Complexity**: Union types and type constraints become more complex when mixing protobuf and Scala model types during transition.
|
||||
|
||||
5. **Cascading Dependency Issues**: Converting to `ActionResultC` requires extensive trait dependencies (`ChangedBattalionT`, `ChangedHeroT`, `GeneratedTextRequestT`, etc.) that create complex BUILD dependency graphs, unlike simple protobuf `ActionResult`.
|
||||
|
||||
6. **BUILD Complexity**: Each Scala model conversion requires significantly more BUILD dependencies than protobuf equivalents, making incremental conversion difficult.
|
||||
|
||||
7. **Build Verification Critical**: Any conversion must maintain working build state - even simple commands like `DefendCommand` can break main server build due to dependency cascades.
|
||||
### Successful Conversion Elements
|
||||
|
||||
- ✅ Base class conversion (`SimpleAction` → `ProtolessSimpleAction`)
|
||||
- ✅ Import updates for most Scala model types
|
||||
- ✅ BUILD.bazel dependency updates for core action result types
|
||||
- ✅ Basic type conversions for simple cases
|
||||
|
||||
### Recommended Conversion Strategy
|
||||
|
||||
1. **Architecture-First Approach**: Convert base infrastructure (LLM generators, action result builders) before individual commands
|
||||
2. **Wrapper Pattern**: Use existing `Protoless*ActionWrapper` classes as templates for gradual transition
|
||||
3. **Dependency Analysis**: Map full dependency trees before attempting conversions to avoid cascading build failures
|
||||
4. **Batch Conversions**: Convert related commands together to minimize dependency conflicts
|
||||
5. **Build Verification**: **ALWAYS** verify `//src/main/scala/net/eagle0/eagle:eagle_server` and test suite build before creating PRs
|
||||
|
||||
### Conversion Requirements
|
||||
|
||||
**Before creating any PR:**
|
||||
- ✅ `bazel build //src/main/scala/net/eagle0/eagle:eagle_server` succeeds
|
||||
- ✅ `bazel test //src/test/scala/... --keep_going` passes (or doesn't introduce new failures)
|
||||
- ✅ All BUILD dependencies are correctly specified
|
||||
- ✅ Scalafmt and other linters pass
|
||||
|
||||
---
|
||||
|
||||
## Common Base Classes
|
||||
|
||||
| File | Type | Model Usage | Notes |
|
||||
|------|------|-------------|-------|
|
||||
| Action.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` |
|
||||
| ActionWithResultingState.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` |
|
||||
| DeterministicSingleResultAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` |
|
||||
| DeterministicSequentialResultsAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` |
|
||||
| ProtolessRandomSequentialResultsAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` |
|
||||
| ProtolessRandomSimpleAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` |
|
||||
| ProtolessSequentialResultsAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` |
|
||||
| ProtolessSimpleAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` |
|
||||
| RandomSequentialResultsAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` |
|
||||
| RandomSimpleAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto` |
|
||||
| RandomStateProtoSequencer.scala | Sequencer | ❌ Uses Protobuf | Bridge class, depends on both protobuf and Scala models |
|
||||
| RandomStateTSequencer.scala | Sequencer | ❌ Uses Protobuf | Bridge class, depends on both protobuf and Scala models |
|
||||
| SimpleAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto` |
|
||||
| VigorXPApplier.scala | Utility | ❌ Uses Protobuf | Depends on `action_result_scala_proto` |
|
||||
|
||||
---
|
||||
|
||||
## Actions
|
||||
|
||||
| File | Model Usage | Notes |
|
||||
|------|-------------|-------|
|
||||
| CheckForFactionChangesAction.scala | ❌ Uses Protobuf | |
|
||||
| CheckForFailedQuestsAction.scala | ❌ Uses Protobuf | Depends on `unaffiliated_hero_quest_scala_proto` |
|
||||
| CheckForFulfilledQuestsAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| ChronicleEventGenerator.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndAttackDecisionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndBattleAftermathPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndBattleRequestPhaseAction.scala | ❌ Uses Protobuf | Depends on `diplomacy_offer_status_scala_proto` |
|
||||
| EndBattleResolutionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndDefenseDecisionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndDiplomacyResolutionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllBattleRequestPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllBattleResolutionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllDecisionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndHandleRiotsPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndPlayerCommandsPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndPleaseRecruitMePhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndProvinceMoveResolutionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndUnaffiliatedHeroActionsPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| EndVassalCommandsPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| FreeForAllDrawAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| FriendlyMoveAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| HeroBackstoryUpdateAction.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| HeroBackstoryUpdateActionGenerator.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| NewRoundAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| NewYearAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformFoodConsumptionPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformForcedTurnBackAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformHeroDeparturesAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformHostileArmySetupAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformProvinceEventsAction.scala | ❌ Uses Protobuf | Depends on `province_event_scala_proto` |
|
||||
| PerformProvinceMoveResolutionAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformReconResolutionAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformUnaffiliatedHeroesAction.scala | ❌ Uses Protobuf | Depends on `unaffiliated_hero_quest_scala_proto` |
|
||||
| PerformUncontestedConquestAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformVassalCommandsPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PerformVassalDefenseDecisionsAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| PrisonerEscapeAction.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| PrisonerExchangeAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| ProvinceConqueredAction.scala | ❌ Uses Protobuf | Depends on `common_unit_scala_proto` |
|
||||
| ProvinceHeldAction.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| RequestBattlesAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| RequestFreeForAllBattlesAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| ResolveBattleAction.scala | ❌ Uses Protobuf | Depends on `shardok_internal_interface_scala_grpc` |
|
||||
| SafePassageArmiesProceedAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| ShipmentArrivedAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| TruceTurnBackPhaseAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| UnaffiliatedHeroAppearedAction.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| UnaffiliatedHeroMovedAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| UnaffiliatedHeroRejoinedAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| UnaffiliatedHeroesChangedAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
| WithdrawnArmiesReturnHomeAction.scala | ❌ Uses Protobuf | Depends on `game_state_scala_proto` |
|
||||
| WonFreeForAllAction.scala | ❌ Uses Protobuf | Depends on multiple protobuf targets |
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
### ✅ Fully Migrated Commands (No Protobuf Dependencies)
|
||||
|
||||
These commands have **NO protobuf dependencies** in their BUILD.bazel targets:
|
||||
|
||||
| File | Build Target | Notes |
|
||||
|------|--------------|-------|
|
||||
| AlmsCommand.scala | `alms_command` | Uses `ProtolessSimpleAction` |
|
||||
| ApprehendOutlawCommand.scala | `apprehend_outlaw_command` | Fully migrated |
|
||||
| AttackDecisionCommand.scala | `attack_decision_command` | Fully migrated |
|
||||
| ControlWeatherCommand.scala | `control_weather_command` | Fully migrated |
|
||||
| DeclineQuestCommand.scala | `decline_quest_command` | Uses quest fulfillment models |
|
||||
| DivineCommand.scala | `divine_command` | Uses LLM request generation |
|
||||
| ExileVassalCommand.scala | `exile_vassal_command` | Uses `ProtolessSimpleAction` |
|
||||
| FeastCommand.scala | `feast_command` | Fully migrated |
|
||||
| HandleCapturedHeroesCommand.scala | `handle_captured_heroes_command` | Uses LLM generation |
|
||||
| HandleRiotCrackDownCommand.scala | `handle_riot_crack_down_command` | Fully migrated |
|
||||
| HandleRiotDoNothingCommand.scala | `handle_riot_do_nothing_command` | Fully migrated |
|
||||
| HandleRiotGiveCommand.scala | `handle_riot_give_command` | Fully migrated |
|
||||
| HeroGiftCommand.scala | `hero_gift_command` | Fully migrated |
|
||||
| ImproveCommand.scala | `improve_command` | Uses quest fulfillment models |
|
||||
| IssueOrdersCommand.scala | `issue_orders_command` | Fully migrated |
|
||||
| ManagePrisonersCommand.scala | `manage_prisoners_command` | Fully migrated |
|
||||
| PleaseRecruitMeCommand.scala | `please_recruit_me_command` | Uses LLM generation |
|
||||
| RecruitHeroesCommand.scala | `recruit_heroes_command` | Fully migrated |
|
||||
| RestCommand.scala | `rest_command` | Fully migrated |
|
||||
| ReturnCommand.scala | `return_command` | Fully migrated |
|
||||
| SuppressBeastsCommand.scala | `suppress_beasts_command` | Uses LLM generation |
|
||||
| TradeCommand.scala | `trade_command` | Fully migrated |
|
||||
| TravelCommand.scala | `travel_command` | Uses quest fulfillment |
|
||||
| ArmTroopsCommand.scala | `arm_troops_command` | **NEWLY MIGRATED** - Uses Scala BattalionType model |
|
||||
| TrainCommand.scala | `train_command` | **NEWLY MIGRATED** - Uses Scala BattalionType model, ProtolessSimpleAction |
|
||||
| DefendCommand.scala | `defend_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction |
|
||||
| ReconCommand.scala | `recon_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction |
|
||||
| OrganizeTroopsCommand.scala | `organize_troops_command` | **NEWLY MIGRATED** - Uses ProtolessRandomSimpleAction |
|
||||
| SendSuppliesCommand.scala | `send_supplies_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, MovingSupplies domain model |
|
||||
| StartEpidemicCommand.scala | `start_epidemic_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, DeferredChange domain model |
|
||||
| SwearBrotherhoodCommand.scala | `swear_brotherhood_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, LLM integration |
|
||||
| MarchCommand.scala | `march_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, Army domain model |
|
||||
| ResolveTruceOfferCommand.scala | `resolve_truce_offer_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, TruceOffer domain model, LLM integration |
|
||||
| ResolveInvitationCommand.scala | `resolve_invitation_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, Invitation domain model, LLM integration |
|
||||
| ResolveRansomOfferCommand.scala | `resolve_ransom_offer_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, RansomOffer domain model, LLM integration |
|
||||
| ResolveTributeCommand.scala | `resolve_tribute_command` | **NEWLY MIGRATED** - Uses ProtolessSimpleAction, TributeAmount domain model |
|
||||
|
||||
**Total: 36 commands (90% of all commands)**
|
||||
|
||||
### ⚠️ Commands Still Using Protobuf Dependencies
|
||||
|
||||
These commands have protobuf dependencies in their BUILD.bazel files:
|
||||
|
||||
| File | Build Target | Key Protobuf Dependencies | Migration Complexity |
|
||||
|------|--------------|---------------------------|---------------------|
|
||||
| DiplomacyCommand.scala | `diplomacy_command` | `diplomacy_option`, `diplomacy_offer`, `available_command` | High - Complex diplomacy |
|
||||
| ResolveAllianceOfferCommand.scala | `resolve_alliance_offer_command` | `diplomacy_offer`, `available_command`, `action_result` | High - Diplomacy |
|
||||
| ResolveBreakAllianceCommand.scala | `resolve_break_alliance_command` | `diplomacy_offer`, `available_command`, `action_result` | High - Diplomacy |
|
||||
| ~~ResolveRansomOfferCommand.scala~~ | ~~`resolve_ransom_offer_command`~~ | ~~**MIGRATED**~~ | ~~High - Diplomacy~~ |
|
||||
| ~~ResolveTributeCommand.scala~~ | ~~`resolve_tribute_command`~~ | ~~**MIGRATED**~~ | ~~High - Diplomacy~~ |
|
||||
|
||||
**Total: 4 commands (10% of all commands)**
|
||||
|
||||
### Migration Complexity Analysis
|
||||
|
||||
**Low Complexity (0 commands)**: Single protobuf dependency
|
||||
- ~~All low complexity commands have been migrated~~
|
||||
|
||||
**Medium Complexity (0 commands)**: API layer or simple state dependencies
|
||||
- ~~All medium complexity commands have been migrated~~
|
||||
|
||||
**High Complexity (6 commands)**: Complex state or diplomacy
|
||||
- All diplomacy resolution commands (5) - need complete diplomacy model migration
|
||||
- Commands with complex `game_state` dependencies (1)
|
||||
|
||||
---
|
||||
|
||||
## Diplomacy Helpers
|
||||
|
||||
All diplomacy helpers use **Scala models only**:
|
||||
|
||||
| File | Model Usage | Notes |
|
||||
|------|-------------|-------|
|
||||
| AllianceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only |
|
||||
| BreakAllianceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only |
|
||||
| InvitationResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only |
|
||||
| RansomResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only |
|
||||
| TruceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only |
|
||||
|
||||
---
|
||||
|
||||
## Migration Priority Analysis
|
||||
|
||||
Based on the BUILD.bazel dependency analysis, here are the key findings and recommendations:
|
||||
|
||||
### 🎯 High Impact Migration Targets
|
||||
|
||||
**Core Dependencies Blocking Multiple Commands:**
|
||||
|
||||
1. **`action_result_scala_proto`** - Used by 12+ commands
|
||||
- Blocks: `DefendCommand`, `FreeForAllDecisionCommand`, diplomacy resolvers
|
||||
- Impact: Would unlock many command migrations
|
||||
|
||||
2. **`available_command_scala_proto` / `selected_command_scala_proto`** - Used by 10+ commands
|
||||
- Blocks: All UI-interactive commands
|
||||
- Impact: Would enable client-server interaction model migration
|
||||
|
||||
3. **`game_state_scala_proto`** - Used by 8+ commands
|
||||
- Blocks: Complex state-dependent commands
|
||||
- Impact: Core state representation migration
|
||||
|
||||
### 📊 Migration Tiers by Complexity
|
||||
|
||||
**Tier 1 - Quick Wins (2 commands):**
|
||||
- `ArmTroopsCommand` - Only `battalion_type` dependency
|
||||
- `TrainCommand` - Only `battalion_type` dependency
|
||||
- **Effort:** Low, **Impact:** Demonstrates battalion model usage
|
||||
|
||||
**Tier 2 - API Layer (5 commands):**
|
||||
- Commands blocked by `available_command`/`selected_command`
|
||||
- **Effort:** Medium, **Impact:** High (enables UI interaction models)
|
||||
|
||||
**Tier 3 - Diplomacy Suite (6 commands):**
|
||||
- All `Resolve*Command` diplomacy commands
|
||||
- **Effort:** High, **Impact:** High (complete diplomacy model migration)
|
||||
- **Strategy:** Migrate as a group after diplomacy models are ready
|
||||
|
||||
### 🏆 Success Metrics
|
||||
|
||||
**Current Status:**
|
||||
- ✅ **82.5% of commands fully migrated** (33/40)
|
||||
- ✅ **All diplomacy helpers use Scala models**
|
||||
- ✅ **All protoless base classes available**
|
||||
- ✅ **One diplomacy command completed** (ResolveTruceOfferCommand)
|
||||
|
||||
**Next Milestones:**
|
||||
- ✅ **70% target:** Migrate Tier 1 + some Tier 2 commands **COMPLETED**
|
||||
- ✅ **80% target:** Continue with remaining non-diplomacy commands **COMPLETED**
|
||||
- **85% target:** Complete API layer migration
|
||||
- **95% target:** Complete diplomacy migration
|
||||
|
||||
### 🔄 Conversion Strategy Updates
|
||||
|
||||
**Revised Approach Based on Analysis:**
|
||||
|
||||
1. **Focus on Core Dependencies First**
|
||||
- Migrate `battalion_type` model (unlocks 2 commands immediately)
|
||||
- Migrate `action_result` model (unlocks 12+ commands)
|
||||
- Migrate `available_command`/`selected_command` (unlocks UI layer)
|
||||
|
||||
2. **Leverage Existing Success**
|
||||
- 77.5% of commands already fully migrated
|
||||
- Use migrated commands as reference implementations
|
||||
- Diplomacy helpers prove complex business logic can work with Scala models
|
||||
|
||||
3. **Group Related Migrations**
|
||||
- Military commands: `ArmTroopsCommand`, `TrainCommand`, `OrganizeTroopsCommand`
|
||||
- UI commands: All using `available_command`/`selected_command`
|
||||
- Diplomacy commands: All `Resolve*Command` variants
|
||||
|
||||
---
|
||||
|
||||
*Updated on 2025-09-04 - Analysis based on BUILD.bazel dependencies*
|
||||
+5
-6
@@ -5,10 +5,8 @@ import net.eagle0.eagle.library.util.unaffiliated_hero.UnaffiliatedHeroUtils
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
LlmRequestT,
|
||||
PleaseRecruitMeMessage
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.PleaseRecruitMeMessage
|
||||
import net.eagle0.eagle.model.action_result.types.EndUnaffiliatedHeroActionsPhaseResultType
|
||||
import net.eagle0.eagle.model.state.RoundPhase
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Outlaw
|
||||
@@ -67,10 +65,11 @@ case class EndUnaffiliatedHeroActionsPhaseAction(
|
||||
PleaseRecruitMeMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(fid),
|
||||
alwaysGenerate = false,
|
||||
heroId = uh.heroId,
|
||||
targetFactionId = fid,
|
||||
provinceId = province.id,
|
||||
recipientFactionIds = Vector(fid)
|
||||
provinceId = province.id
|
||||
),
|
||||
uh.withPleaseRecruitMeTextId(textId)
|
||||
)
|
||||
|
||||
+6
-8
@@ -6,10 +6,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
HeroBackstoryUpdateRequest,
|
||||
LlmRequestT
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.HeroBackstoryUpdateRequest
|
||||
import net.eagle0.eagle.model.action_result.types.HeroBackstoriesUpdatedResultType
|
||||
import net.eagle0.eagle.model.state.hero.backstory_version.BackstoryVersion
|
||||
import net.eagle0.eagle.model.state.hero.{EventForHeroBackstoryT, HeroT}
|
||||
@@ -86,14 +84,14 @@ case class HeroBackstoryUpdateAction(
|
||||
HeroBackstoryUpdateRequest(
|
||||
requestId = backstoryUpdateTextId,
|
||||
eagleGameId = gameId,
|
||||
heroId = heroId,
|
||||
previousBackstoryVersions = previousBackstoryVersions,
|
||||
events = events,
|
||||
recipientFactionIds = visibleToFactionIds(
|
||||
heroFactionId,
|
||||
visibleToFactionIds
|
||||
) ++ heroInProvinceOwnedBy(heroId).toVector,
|
||||
alwaysGenerate = true
|
||||
alwaysGenerate = true,
|
||||
heroId = heroId,
|
||||
previousBackstoryVersions = previousBackstoryVersions,
|
||||
events = events
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -4,10 +4,8 @@ import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
GeneratedTextRequestT,
|
||||
HeroInitialBackstoryRequest
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.GeneratedTextRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.HeroInitialBackstoryRequest
|
||||
import net.eagle0.eagle.model.action_result.types.HeroAppearsResultType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.hero.backstory_version.BackstoryVersion
|
||||
@@ -64,11 +62,10 @@ case class UnaffiliatedHeroAppearedAction(
|
||||
HeroInitialBackstoryRequest(
|
||||
requestId = newBackstoryTextId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = allFactionIds,
|
||||
heroId = hero.id,
|
||||
factionId = None,
|
||||
personalityWords =
|
||||
hero.personalityWords,
|
||||
recipientFactionIds = allFactionIds
|
||||
personalityWords = hero.personalityWords
|
||||
)
|
||||
)
|
||||
else Vector()) ++ nameGenerationRequest
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.util.PriceIndexUtils
|
||||
|
||||
@@ -142,18 +142,25 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_id_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:combat_unit_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:improvement_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:proto_conversion_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:tribute_amount_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:unaffiliated_hero_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province:order_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:improvement_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
@@ -204,7 +211,6 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
@@ -221,6 +227,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:arm_troops_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
@@ -343,14 +350,21 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:max_combat_unit_count_per_side",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:defend_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:combat_unit",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
@@ -494,12 +508,21 @@ scala_library(
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:army_advanced_to_free_for_all_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:army_withdrew_from_free_for_all_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -845,28 +868,25 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:battalion_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:action_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:march_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:max_combat_unit_count_per_side",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:turns_to_resolve_conquest",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:legacy_battalion_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:march_action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:combat_unit",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:supplies",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -878,16 +898,25 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:battalion_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:battalion_name_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:battalion_type_finder",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:price_index_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:organize_troops_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
@@ -1111,24 +1140,22 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_agility_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:recon_started_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:incoming_end_turn_action",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1174,17 +1201,24 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/llm_request_generators/diplomacy_llm_helpers:diplomacy_resolution_llm_request_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1196,17 +1230,23 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/llm_request_generators/diplomacy_llm_helpers:diplomacy_resolution_llm_request_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1217,26 +1257,25 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/llm_request_generators/diplomacy_llm_helpers:diplomacy_resolution_llm_request_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:invitation_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1247,25 +1286,25 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/llm_request_generators/diplomacy_llm_helpers:diplomacy_resolution_llm_request_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1277,17 +1316,26 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/llm_request_generators/diplomacy_llm_helpers:diplomacy_resolution_llm_request_generator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types/base:action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1298,26 +1346,25 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:date_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils:legacy_faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:tribute_paid_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:tribute_refused_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:tribute_amount",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1388,21 +1435,22 @@ scala_library(
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:action_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:send_supplies_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:ship_supplies_loss",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:turns_to_resolve_shipment",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:sent_supplies_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:supplies",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1436,26 +1484,21 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_base",
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:start_epidemic_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:start_epidemic_vigor_delta",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:epidemic_started_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:deferred_change_trait",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1513,25 +1556,26 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":command_builder",
|
||||
":deterministic_single_result_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:event_for_hero_backstory_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:accept_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:swear_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils:legacy_faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:failed_swear_brotherhood_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:swear_brotherhood_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1575,7 +1619,6 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:action_vigor_cost",
|
||||
@@ -1595,6 +1638,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:train_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
|
||||
+152
-17
@@ -25,6 +25,7 @@ import net.eagle0.eagle.api.command.util.prisoner_management_type.{
|
||||
}
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.model.proto_converters.CombatUnitConverter
|
||||
import net.eagle0.eagle.library.actions.impl.command.AttackDecisionCommand.{
|
||||
AttackDecision,
|
||||
SafePassage
|
||||
@@ -41,6 +42,8 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
import net.eagle0.eagle.library.util.faction_utils.LegacyFactionUtils
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.model.proto_converters.date.DateConverter
|
||||
import net.eagle0.eagle.model.proto_converters.diplomacy_offer.DiplomacyOfferConverter
|
||||
import net.eagle0.eagle.model.proto_converters.diplomacy_offer.status.StatusConverter
|
||||
import net.eagle0.eagle.model.proto_converters.faction.FactionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.hero.HeroConverter
|
||||
import net.eagle0.eagle.model.proto_converters.province.{
|
||||
@@ -49,11 +52,14 @@ import net.eagle0.eagle.model.proto_converters.province.{
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.{
|
||||
BattalionConverter,
|
||||
BattalionTypeConverter,
|
||||
ImprovementTypeConverter,
|
||||
ProtoConversionException,
|
||||
TributeAmountConverter,
|
||||
UnaffiliatedHeroConverter
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.BattalionTypeIdConverter
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{Invitation, TruceOffer}
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
@@ -131,7 +137,8 @@ class CommandFactory {
|
||||
),
|
||||
existingBattalions = gameState.battalions.values.toVector
|
||||
.map(BattalionConverter.fromProto),
|
||||
battalionTypes = gameState.battalionTypes.toVector,
|
||||
battalionTypes = gameState.battalionTypes.toVector
|
||||
.map(BattalionTypeConverter.fromProto),
|
||||
armamentCosts = atac.armamentCosts.map { ac =>
|
||||
ArmTroopsCommand.ArmamentCost(
|
||||
battalionTypeId = BattalionTypeId.fromInt(ac.`type`.value),
|
||||
@@ -197,8 +204,10 @@ class CommandFactory {
|
||||
case (dfac: DefendAvailableCommand, dfsc: DefendSelectedCommand) =>
|
||||
DefendCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = dfac,
|
||||
selectedCommand = dfsc,
|
||||
defendingUnits =
|
||||
dfsc.defendingUnits.map(CombatUnitConverter.fromProto).toVector,
|
||||
fleeProvinceId = dfsc.fleeProvinceId,
|
||||
availableFleeProvinceIds = dfac.availableFleeProvinceIds.toVector,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(dfac.actingProvinceId)
|
||||
)
|
||||
@@ -431,7 +440,28 @@ class CommandFactory {
|
||||
questFulfillmentChecker = questFulfillmentChecker(gameState)
|
||||
)
|
||||
case (ac: MarchAvailableCommand, sc: MarchSelectedCommand) =>
|
||||
MarchCommand.make(actingFactionId, gameState, ac, sc)
|
||||
val commandForOrigin = ac.oneProvinceCommands
|
||||
.find(_.originProvinceId == sc.originProvince)
|
||||
.get
|
||||
|
||||
MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = sc.originProvince,
|
||||
destinationProvinceId = sc.destinationProvinceId,
|
||||
marchingUnits =
|
||||
sc.marchingUnits.map(CombatUnitConverter.fromProto).toVector,
|
||||
gold = sc.gold,
|
||||
food = sc.food,
|
||||
availableDestinationProvinceIds =
|
||||
commandForOrigin.availableDestinationProvinces.toVector,
|
||||
availableHeroIds = commandForOrigin.availableHeroIds.toVector,
|
||||
availableBattalionIds =
|
||||
commandForOrigin.availableBattalions.map(_.battalionId).toVector,
|
||||
goldAvailable = commandForOrigin.goldAvailable,
|
||||
foodAvailable = commandForOrigin.foodAvailable,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
gameId = gameState.gameId
|
||||
)
|
||||
case (
|
||||
ac: OrganizeTroopsAvailableCommand,
|
||||
sc: OrganizeTroopsSelectedCommand
|
||||
@@ -448,14 +478,17 @@ class CommandFactory {
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
existingBattalions = gameState.battalions.values.toVector,
|
||||
existingBattalions = gameState.battalions.values.toVector
|
||||
.map(BattalionConverter.fromProto),
|
||||
constructibleBattalionTypeIds = ac.availableBattalionTypes
|
||||
.filter(
|
||||
_.meetsRequirements
|
||||
)
|
||||
.map(_.typeId)
|
||||
.map(BattalionTypeIdConverter.fromProto)
|
||||
.toVector,
|
||||
allBattalionTypes = gameState.battalionTypes.toVector,
|
||||
allBattalionTypes = gameState.battalionTypes.toVector
|
||||
.map(BattalionTypeConverter.fromProto),
|
||||
changedBattalions = sc.changedBattalions
|
||||
.map(cb =>
|
||||
OrganizeTroopsCommand.ChangedBattalion(
|
||||
@@ -470,7 +503,7 @@ class CommandFactory {
|
||||
newBattalions = sc.newBattalions
|
||||
.map(nb =>
|
||||
OrganizeTroopsCommand.NewBattalion(
|
||||
`type` = nb.`type`,
|
||||
`type` = BattalionTypeIdConverter.fromProto(nb.`type`),
|
||||
newTroops = nb.newTroops,
|
||||
troopsFromOtherBattalion =
|
||||
nb.troopsFromOtherBattalion.map(tfobConverter).toVector
|
||||
@@ -479,7 +512,7 @@ class CommandFactory {
|
||||
.toVector,
|
||||
troopCosts = ac.troopCosts.map { tc =>
|
||||
OrganizeTroopsCommand.TroopCost(
|
||||
battalionTypeId = tc.`type`,
|
||||
battalionTypeId = BattalionTypeIdConverter.fromProto(tc.`type`),
|
||||
cost = tc.costPerTroop
|
||||
)
|
||||
}.toVector
|
||||
@@ -530,7 +563,14 @@ class CommandFactory {
|
||||
)
|
||||
|
||||
case (ac: ReconAvailableCommand, sc: ReconSelectedCommand) =>
|
||||
ReconCommand.make(actingFactionId, gameState, ac, sc)
|
||||
ReconCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
actingHeroId = sc.actingHeroId,
|
||||
destinationProvinceId = sc.targetProvinceId,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
availableTargetProvinces = ac.availableTargetProvinces.toVector
|
||||
)
|
||||
case (
|
||||
ac: RecruitHeroesAvailableCommand,
|
||||
sc: RecruitHeroesSelectedCommand
|
||||
@@ -551,21 +591,60 @@ class CommandFactory {
|
||||
ac: ResolveInvitationAvailableCommand,
|
||||
sc: ResolveInvitationSelectedCommand
|
||||
) =>
|
||||
ResolveInvitationCommand.make(actingFactionId, gameState, ac, sc)
|
||||
ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = sc.originatingFactionId,
|
||||
resolution = StatusConverter.fromProto(sc.resolution),
|
||||
allFactions = allFactions(gameState).map(f => f.id -> f).toMap,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
case (
|
||||
ac: ResolveRansomOfferAvailableCommand,
|
||||
sc: ResolveRansomOfferSelectedCommand
|
||||
) =>
|
||||
ResolveRansomOfferCommand.make(actingFactionId, gameState, ac, sc)
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = sc.offeringFactionId,
|
||||
resolution = StatusConverter.fromProto(sc.resolution),
|
||||
allFactions = allFactions(gameState).map(f => f.id -> f).toMap,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
case (
|
||||
ac: ResolveTruceOfferAvailableCommand,
|
||||
sc: ResolveTruceOfferSelectedCommand
|
||||
) =>
|
||||
// Find the selected offer
|
||||
val selectedOffer = ac.offers
|
||||
.find(_.originatingFactionId == sc.originatingFactionId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"Could not find offer from faction ${sc.originatingFactionId}"
|
||||
)
|
||||
)
|
||||
|
||||
// Convert the offer to domain model
|
||||
val domainOffer =
|
||||
DiplomacyOfferConverter.fromProto(selectedOffer) match {
|
||||
case truceOffer: TruceOffer => truceOffer
|
||||
case _ => throw new EagleInternalException("Expected TruceOffer")
|
||||
}
|
||||
|
||||
ResolveTruceOfferCommand.make(
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = sc.originatingFactionId,
|
||||
messengerHeroId = selectedOffer.messengerHeroId,
|
||||
messengerOriginProvinceId = selectedOffer.messengerOriginProvinceId,
|
||||
truceOffer = domainOffer,
|
||||
resolution = StatusConverter.fromProto(sc.resolution),
|
||||
availableOriginatingFactionIds =
|
||||
ac.offers.map(_.originatingFactionId).toVector,
|
||||
availableResolutions = selectedOffer.eligibleStatuses
|
||||
.map(StatusConverter.fromProto)
|
||||
.toVector,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
@@ -598,7 +677,32 @@ class CommandFactory {
|
||||
ac: ResolveTributeAvailableCommand,
|
||||
sc: ResolveTributeSelectedCommand
|
||||
) =>
|
||||
ResolveTributeCommand.make(actingFactionId, gameState, ac, sc)
|
||||
import net.eagle0.eagle.model.proto_converters.TributeAmountConverter
|
||||
|
||||
val demandingFid = sc.demandingFactionId
|
||||
val selectedDemand = ac.demands
|
||||
.find(_.demandingFactionId == demandingFid)
|
||||
.getOrElse(
|
||||
throw new IllegalArgumentException(
|
||||
s"Selected faction ID $demandingFid was not among options ${ac.demands.map(_.demandingFactionId)}"
|
||||
)
|
||||
)
|
||||
val tributeAmount =
|
||||
TributeAmountConverter.fromProto(selectedDemand.tributeDemanded.get)
|
||||
|
||||
ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFid,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = sc.paid,
|
||||
availableDemandingFactionIds =
|
||||
ac.demands.map(_.demandingFactionId).toVector,
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
availableGold = ac.availableGold,
|
||||
availableFood = ac.availableFood,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
case (ac: RestAvailableCommand, sc: RestSelectedCommand) =>
|
||||
RestCommand.make(
|
||||
@@ -618,12 +722,33 @@ class CommandFactory {
|
||||
ac: SendSuppliesAvailableCommand,
|
||||
sc: SendSuppliesSelectedCommand
|
||||
) =>
|
||||
SendSuppliesCommand.make(actingFactionId, gameState, ac, sc)
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingHeroId = sc.actingHeroId,
|
||||
originProvinceId = ac.actingProvinceId,
|
||||
destinationProvinceId = sc.destinationProvinceId,
|
||||
availableDestinationProvinceIds =
|
||||
ac.availableDestinationProvinceIds.toVector,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
goldAvailable = ac.goldAvailable,
|
||||
foodAvailable = ac.foodAvailable,
|
||||
goldSent = sc.gold,
|
||||
foodSent = sc.food,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
case (
|
||||
ac: StartEpidemicAvailableCommand,
|
||||
sc: StartEpidemicSelectedCommand
|
||||
) =>
|
||||
StartEpidemicCommand.make(actingFactionId, gameState, ac, sc)
|
||||
StartEpidemicCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingHeroId = sc.actingHeroId,
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
targetProvinceId = sc.selectedProvinceId,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
availableTargetProvinceIds =
|
||||
ac.options.map(_.targetProvinceId).toVector
|
||||
)
|
||||
|
||||
case (
|
||||
ac: SuppressBeastsAvailableCommand,
|
||||
@@ -649,7 +774,16 @@ class CommandFactory {
|
||||
ac: SwearBrotherhoodAvailableCommand,
|
||||
sc: SwearBrotherhoodSelectedCommand
|
||||
) =>
|
||||
SwearBrotherhoodCommand.make(actingFactionId, gameState, ac, sc)
|
||||
SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
newBrotherHeroId = sc.newBrotherHeroId,
|
||||
availableHeroIds = ac.availableHeroes.map(_.heroId).toVector,
|
||||
factionHeadHeroId = gameState.factions(actingFactionId).factionHeadId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
gameId = gameState.gameId
|
||||
)
|
||||
|
||||
case (ac: TradeAvailableCommand, sc: TradeSelectedCommand) =>
|
||||
TradeCommand.make(
|
||||
@@ -679,6 +813,7 @@ class CommandFactory {
|
||||
.map(gameState.battalions)
|
||||
.map(BattalionConverter.fromProto),
|
||||
battalionTypes = gameState.battalionTypes.toVector
|
||||
.map(BattalionTypeConverter.fromProto)
|
||||
)
|
||||
case (ac: TravelAvailableCommand, _: TravelSelectedCommand) =>
|
||||
val province =
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.DefendAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.DefendSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.DEFEND
|
||||
import net.eagle0.eagle.common.combat_unit.CombatUnit
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.army.Army
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.DefendResultType
|
||||
import net.eagle0.eagle.model.state.{Army, CombatUnit}
|
||||
import net.eagle0.eagle.library.settings.MaxCombatUnitCountPerSide
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.Attacking
|
||||
@@ -17,56 +15,50 @@ import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
object DefendCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: DefendAvailableCommand,
|
||||
selectedCommand: DefendSelectedCommand,
|
||||
defendingUnits: Vector[CombatUnit],
|
||||
fleeProvinceId: Option[ProvinceId],
|
||||
availableFleeProvinceIds: Vector[ProvinceId],
|
||||
actingProvince: ProvinceT
|
||||
): SimpleAction = {
|
||||
val defendingUnits = selectedCommand.defendingUnits
|
||||
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
defendingUnits.length <= MaxCombatUnitCountPerSide.intValue,
|
||||
s"Tried to defend with ${defendingUnits.length} units (max is $MaxCombatUnitCountPerSide.intValue)"
|
||||
s"Tried to defend with ${defendingUnits.length} units (max is ${MaxCombatUnitCountPerSide.intValue})"
|
||||
)
|
||||
|
||||
// If there are any eligible flee provinces, one must be chosen; if there are none, the flee province must be empty
|
||||
if availableCommand.availableFleeProvinceIds.isEmpty then
|
||||
if availableFleeProvinceIds.isEmpty then
|
||||
commandRequire(
|
||||
selectedCommand.fleeProvinceId.isEmpty,
|
||||
s"Flee province ${selectedCommand.fleeProvinceId.get} was selected, but none were available"
|
||||
fleeProvinceId.isEmpty,
|
||||
s"Flee province ${fleeProvinceId.get} was selected, but none were available"
|
||||
)
|
||||
else {
|
||||
commandRequire(
|
||||
selectedCommand.fleeProvinceId.nonEmpty,
|
||||
s"Flee provinces ${availableCommand.availableFleeProvinceIds} are available, but none was selected"
|
||||
fleeProvinceId.nonEmpty,
|
||||
s"Flee provinces $availableFleeProvinceIds are available, but none was selected"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableCommand.availableFleeProvinceIds
|
||||
.contains(
|
||||
selectedCommand.fleeProvinceId.get
|
||||
),
|
||||
s"Selected flee province ${selectedCommand.fleeProvinceId.get} is not in available ${availableCommand.availableFleeProvinceIds}"
|
||||
availableFleeProvinceIds.contains(fleeProvinceId.get),
|
||||
s"Selected flee province ${fleeProvinceId.get} is not in available $availableFleeProvinceIds"
|
||||
)
|
||||
}
|
||||
end if
|
||||
|
||||
DefendCommand(
|
||||
sc = selectedCommand,
|
||||
defendingPlayer = actingFactionId,
|
||||
province = actingProvince,
|
||||
defendingUnits = defendingUnits,
|
||||
fleeProvinceId = selectedCommand.fleeProvinceId
|
||||
fleeProvinceId = fleeProvinceId
|
||||
)
|
||||
}
|
||||
|
||||
private case class DefendCommand(
|
||||
sc: DefendSelectedCommand,
|
||||
defendingPlayer: FactionId,
|
||||
province: ProvinceT,
|
||||
defendingUnits: Seq[CombatUnit],
|
||||
defendingUnits: Vector[CombatUnit],
|
||||
fleeProvinceId: Option[ProvinceId]
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult = {
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
commandRequire(
|
||||
province.hostileArmies.exists(_.status == Attacking),
|
||||
s"There are no attacking armies to defend against in province ${province.id}"
|
||||
@@ -77,18 +69,18 @@ object DefendCommand {
|
||||
"must specify at least one defending unit"
|
||||
)
|
||||
|
||||
ActionResult(
|
||||
`type` = DEFEND,
|
||||
player = Some(defendingPlayer),
|
||||
province = Some(province.id),
|
||||
provinceActed = Some(province.id),
|
||||
ActionResultC(
|
||||
actionResultType = DefendResultType,
|
||||
actingFactionId = Some(defendingPlayer),
|
||||
provinceId = Some(province.id),
|
||||
provinceIdActed = Some(province.id),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = province.id,
|
||||
ChangedProvinceC(
|
||||
provinceId = province.id,
|
||||
newDefendingArmy = Some(
|
||||
Army(
|
||||
factionId = defendingPlayer,
|
||||
units = defendingUnits.toVector,
|
||||
units = defendingUnits,
|
||||
fleeProvinceId = fleeProvinceId
|
||||
)
|
||||
)
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.ExileVassalMessage
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.ExileVassalMessage
|
||||
import net.eagle0.eagle.model.action_result.types.VassalExiledResultType
|
||||
import net.eagle0.eagle.model.action_result.{
|
||||
ActionResultT,
|
||||
|
||||
+34
-30
@@ -9,16 +9,20 @@ import net.eagle0.eagle.api.command.util.attack_decision_type.{
|
||||
WithdrawDecision
|
||||
}
|
||||
import net.eagle0.eagle.api.selected_command.FreeForAllDecisionSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.{
|
||||
ARMY_ADVANCED_TO_FREE_FOR_ALL,
|
||||
ARMY_WITHDREW_FROM_FREE_FOR_ALL
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.army.{AwaitingFreeForAll, Withdrawing}
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince.HostileArmyGroupStatusChange
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.HostileArmyStatusChange
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
ArmyAdvancedToFreeForAllResultType,
|
||||
ArmyWithdrewFromFreeForAllResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.{
|
||||
AwaitingFreeForAll,
|
||||
Withdrawing
|
||||
}
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
|
||||
@@ -27,20 +31,20 @@ object FreeForAllDecisionCommand {
|
||||
sc: FreeForAllDecisionSelectedCommand,
|
||||
attackingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = ARMY_ADVANCED_TO_FREE_FOR_ALL,
|
||||
player = Some(attackingFactionId),
|
||||
province = Some(provinceId),
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = ArmyAdvancedToFreeForAllResultType,
|
||||
actingFactionId = Some(attackingFactionId),
|
||||
provinceId = Some(provinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = provinceId,
|
||||
ChangedProvinceC(
|
||||
provinceId = provinceId,
|
||||
// set the new status on the hostile army
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
HostileArmyStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = AwaitingFreeForAll()
|
||||
newStatus = AwaitingFreeForAll
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -52,20 +56,20 @@ object FreeForAllDecisionCommand {
|
||||
sc: FreeForAllDecisionSelectedCommand,
|
||||
attackingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = ARMY_WITHDREW_FROM_FREE_FOR_ALL,
|
||||
player = Some(attackingFactionId),
|
||||
province = Some(provinceId),
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = ArmyWithdrewFromFreeForAllResultType,
|
||||
actingFactionId = Some(attackingFactionId),
|
||||
provinceId = Some(provinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = provinceId,
|
||||
ChangedProvinceC(
|
||||
provinceId = provinceId,
|
||||
// set the new status on the hostile army
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
HostileArmyStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = Withdrawing()
|
||||
newStatus = Withdrawing
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -77,7 +81,7 @@ object FreeForAllDecisionCommand {
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: FreeForAllDecisionAvailableCommand,
|
||||
selectedCommand: FreeForAllDecisionSelectedCommand
|
||||
): SimpleAction = {
|
||||
): ProtolessSimpleAction = {
|
||||
val selectedType = selectedCommand.decision
|
||||
|
||||
commandRequire(
|
||||
|
||||
+4
-6
@@ -23,10 +23,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
StatAbsolute
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
LlmRequestT,
|
||||
RecruitmentRefusedMessage
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.RecruitmentRefusedMessage
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
CapturedHeroExecutedResultType,
|
||||
CapturedHeroExiledResultType,
|
||||
@@ -325,6 +323,7 @@ object HandleCapturedHeroesCommand {
|
||||
): LlmRequestT = RecruitmentRefusedMessage(
|
||||
requestId = s"$currentRoundId ${capturedHero.heroId} 0 2",
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(capturingFactionId),
|
||||
capturedHeroId = capturedHero.heroId,
|
||||
capturedHeroFactionId = capturedHero.previousFactionId,
|
||||
actingHeroId = capturingHeroId,
|
||||
@@ -332,8 +331,7 @@ object HandleCapturedHeroesCommand {
|
||||
provinceId = provinceId,
|
||||
alreadyExecutedHeroIds = Vector(),
|
||||
alreadyImprisonedHeroIds = Vector(),
|
||||
alreadyExiledHeroIds = Vector(),
|
||||
recipientFactionIds = Vector(capturingFactionId)
|
||||
alreadyExiledHeroIds = Vector()
|
||||
)
|
||||
|
||||
def make(
|
||||
|
||||
@@ -1,75 +1,72 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.MarchAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.MarchSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.MARCH_ACTION
|
||||
import net.eagle0.eagle.common.combat_unit.CombatUnit
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.army.{Army, MovingArmy}
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.supplies.Supplies
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.state.CombatUnit
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.MarchActionResultType
|
||||
import net.eagle0.eagle.model.state.{Army, MovingArmy, Supplies}
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
MarchWisdomXp,
|
||||
MaxCombatUnitCountPerSide,
|
||||
TurnsToResolveConquest
|
||||
}
|
||||
import net.eagle0.eagle.library.util.LegacyBattalionUtils
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.{
|
||||
BattalionId,
|
||||
FactionId,
|
||||
GameId,
|
||||
HeroId,
|
||||
ProvinceId,
|
||||
RoundId
|
||||
}
|
||||
|
||||
object MarchCommand
|
||||
extends CommandBuilder[MarchAvailableCommand, MarchSelectedCommand] {
|
||||
override def make(
|
||||
object MarchCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: MarchAvailableCommand,
|
||||
selectedCommand: MarchSelectedCommand
|
||||
): DeterministicSingleResultCommand = {
|
||||
val originProvince = gameState.provinces(selectedCommand.originProvince)
|
||||
originProvinceId: ProvinceId,
|
||||
destinationProvinceId: ProvinceId,
|
||||
marchingUnits: Vector[CombatUnit],
|
||||
gold: Int,
|
||||
food: Int,
|
||||
availableDestinationProvinceIds: Vector[ProvinceId],
|
||||
availableHeroIds: Vector[HeroId],
|
||||
availableBattalionIds: Vector[BattalionId],
|
||||
goldAvailable: Int,
|
||||
foodAvailable: Int,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
): ProtolessSimpleAction = {
|
||||
|
||||
// Validate that the origin province has available heroes/battalions
|
||||
commandRequire(
|
||||
availableCommand.oneProvinceCommands
|
||||
.map(_.originProvinceId)
|
||||
.contains(originProvince.id),
|
||||
s"Tried to march from ${originProvince.id} but that was not in ${availableCommand.oneProvinceCommands
|
||||
.map(_.originProvinceId)}"
|
||||
)
|
||||
|
||||
val commandForOriginProvince = availableCommand.oneProvinceCommands
|
||||
.find(_.originProvinceId == originProvince.id)
|
||||
.get
|
||||
|
||||
val actingUnits = selectedCommand.marchingUnits
|
||||
commandRequire(
|
||||
actingUnits.length <= MaxCombatUnitCountPerSide.intValue,
|
||||
s"Tried to march with ${actingUnits.length} units (max is ${MaxCombatUnitCountPerSide.intValue})"
|
||||
)
|
||||
|
||||
val destinationProvinceId = selectedCommand.destinationProvinceId
|
||||
|
||||
// Validate that the destination province is within available set
|
||||
commandRequire(
|
||||
commandForOriginProvince.availableDestinationProvinces
|
||||
.contains(destinationProvinceId),
|
||||
s"Destination province $destinationProvinceId is not in ${commandForOriginProvince.availableDestinationProvinces}"
|
||||
availableHeroIds.nonEmpty,
|
||||
s"No available heroes to march from province $originProvinceId"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedCommand.gold <= commandForOriginProvince.goldAvailable,
|
||||
s"Specified ${selectedCommand.gold} gold but only ${commandForOriginProvince.goldAvailable} available"
|
||||
availableDestinationProvinceIds.contains(destinationProvinceId),
|
||||
s"Destination province $destinationProvinceId is not in $availableDestinationProvinceIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedCommand.food <= commandForOriginProvince.foodAvailable,
|
||||
s"Specified ${selectedCommand.food} gold but only ${commandForOriginProvince.foodAvailable} available"
|
||||
gold <= goldAvailable,
|
||||
s"Specified $gold gold but only $goldAvailable available"
|
||||
)
|
||||
|
||||
val actingHeroes = actingUnits.map(_.heroId)
|
||||
val actingBattalionIds = actingUnits.flatMap(_.battalionId)
|
||||
commandRequire(
|
||||
food <= foodAvailable,
|
||||
s"Specified $food food but only $foodAvailable available"
|
||||
)
|
||||
|
||||
val actingHeroes = marchingUnits.map(_.heroId)
|
||||
val actingBattalionIds = marchingUnits.flatMap(_.battalionId)
|
||||
|
||||
commandRequire(
|
||||
actingHeroes.toSet.size == actingHeroes.size,
|
||||
@@ -82,104 +79,94 @@ object MarchCommand
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
actingHeroes.forall(hid =>
|
||||
commandForOriginProvince.availableHeroIds.contains(hid)
|
||||
),
|
||||
s"Selected heroes $actingHeroes are not all in province ${originProvince.id}'s heroes ${commandForOriginProvince.availableHeroIds}"
|
||||
actingHeroes.forall(availableHeroIds.contains),
|
||||
s"Selected heroes $actingHeroes are not all in available heroes $availableHeroIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
actingBattalionIds.forall(bid =>
|
||||
commandForOriginProvince.availableBattalions
|
||||
.map(_.battalionId)
|
||||
.contains(bid)
|
||||
),
|
||||
s"Selected heroes $actingBattalionIds are not all in province ${originProvince.id}'s battalions ${originProvince.battalionIds}"
|
||||
actingBattalionIds.forall(availableBattalionIds.contains),
|
||||
s"Selected battalions $actingBattalionIds are not all in available battalions $availableBattalionIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
actingUnits.nonEmpty,
|
||||
marchingUnits.nonEmpty,
|
||||
"Must supply at least one acting unit for MarchCommand"
|
||||
)
|
||||
|
||||
val selectedFood = selectedCommand.food
|
||||
val requiredFood = LegacyBattalionUtils.monthlyConsumedFood(
|
||||
battalions = actingBattalionIds.map(gameState.battalions),
|
||||
bts = gameState.battalionTypes.toVector
|
||||
)
|
||||
val availableFood = originProvince.food
|
||||
commandRequire(
|
||||
selectedFood >= Math.min(requiredFood, availableFood),
|
||||
s"Food requirement is $requiredFood and available is $availableFood; must supply one of those"
|
||||
marchingUnits.length <= MaxCombatUnitCountPerSide.intValue,
|
||||
s"Tried to march with ${marchingUnits.length} units (max is ${MaxCombatUnitCountPerSide.intValue})"
|
||||
)
|
||||
|
||||
MarchCommand(
|
||||
sc = selectedCommand,
|
||||
startingState = gameState,
|
||||
actingProvinceId = availableCommand.actingProvinceId,
|
||||
attackingPlayer = actingFactionId,
|
||||
currentRound = gameState.currentRoundId,
|
||||
originProvinceId = selectedCommand.originProvince,
|
||||
new MarchCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
attackingUnits = actingUnits.toVector,
|
||||
gold = selectedCommand.gold,
|
||||
food = selectedFood
|
||||
marchingUnits = marchingUnits.toVector,
|
||||
gold = gold,
|
||||
food = food,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
private case class MarchCommand(
|
||||
sc: MarchSelectedCommand,
|
||||
startingState: GameState,
|
||||
actingProvinceId: ProvinceId,
|
||||
attackingPlayer: FactionId,
|
||||
currentRound: RoundId,
|
||||
private class MarchCommand(
|
||||
actingFactionId: FactionId,
|
||||
originProvinceId: ProvinceId,
|
||||
destinationProvinceId: ProvinceId,
|
||||
attackingUnits: Vector[CombatUnit],
|
||||
marchingUnits: Vector[CombatUnit],
|
||||
gold: Int,
|
||||
food: Int
|
||||
) extends DeterministicSingleResultCommand(startingState, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = MARCH_ACTION,
|
||||
player = Some(attackingPlayer),
|
||||
province = Some(originProvinceId),
|
||||
changedHeroes = attackingUnits
|
||||
.map(cu =>
|
||||
ChangedHero(
|
||||
id = cu.heroId,
|
||||
vigor = Vigor.VigorDelta(-ActionVigorCost.intValue),
|
||||
wisdomXpDelta = Some(MarchWisdomXp.intValue)
|
||||
)
|
||||
),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = originProvinceId,
|
||||
removedRulingPlayerHeroIds = attackingUnits.map(_.heroId),
|
||||
removedBattalionIds = attackingUnits.flatMap(_.battalionId),
|
||||
goldDelta = Some(-gold),
|
||||
foodDelta = Some(-food)
|
||||
),
|
||||
ChangedProvince(
|
||||
id = destinationProvinceId,
|
||||
addedIncomingArmies = Vector(
|
||||
MovingArmy(
|
||||
army = Some(
|
||||
Army(
|
||||
factionId = attackingPlayer,
|
||||
units = attackingUnits,
|
||||
fleeProvinceId = Some(originProvinceId)
|
||||
)
|
||||
),
|
||||
originProvince = originProvinceId,
|
||||
destinationProvince = destinationProvinceId,
|
||||
arrivalRound = currentRound + TurnsToResolveConquest.intValue,
|
||||
supplies = Some(Supplies(gold = gold, food = food))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
provinceActed = Some(actingProvinceId)
|
||||
food: Int,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val heroChanges = marchingUnits.map { cu =>
|
||||
ChangedHeroC(
|
||||
heroId = cu.heroId,
|
||||
vigorChange = StatDelta(-ActionVigorCost.intValue),
|
||||
wisdomXpDelta = Some(MarchWisdomXp.intValue)
|
||||
)
|
||||
}
|
||||
|
||||
val originProvinceChange = ChangedProvinceC(
|
||||
provinceId = originProvinceId,
|
||||
removedRulingFactionHeroIds = marchingUnits.map(_.heroId).toVector,
|
||||
removedBattalionIds = marchingUnits.flatMap(_.battalionId).toVector,
|
||||
goldDelta = Some(-gold),
|
||||
foodDelta = Some(-food)
|
||||
)
|
||||
|
||||
val movingArmy = MovingArmy(
|
||||
id =
|
||||
0, // ID will be generated by ActionResultProtoApplierImpl.modifyArmySet
|
||||
army = Army(
|
||||
factionId = actingFactionId,
|
||||
units = marchingUnits.toVector,
|
||||
fleeProvinceId = Some(originProvinceId)
|
||||
),
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
arrivalRound = currentRoundId + TurnsToResolveConquest.intValue,
|
||||
supplies = Supplies(gold = gold, food = food),
|
||||
suppliesLoss = 0.0,
|
||||
startingPositionIndex = None
|
||||
)
|
||||
|
||||
val destinationProvinceChange = ChangedProvinceC(
|
||||
provinceId = destinationProvinceId,
|
||||
newIncomingArmies = Vector(movingArmy)
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
actionResultType = MarchActionResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
provinceId = Some(originProvinceId),
|
||||
provinceIdActed = Some(originProvinceId),
|
||||
changedHeroes = heroChanges.toVector,
|
||||
changedProvinces =
|
||||
Vector(originProvinceChange, destinationProvinceChange)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
-61
@@ -1,18 +1,20 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.ORGANIZE_TROOPS
|
||||
import net.eagle0.eagle.common.battalion_type.{BattalionType, BattalionTypeId}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.battalion.Battalion
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.library.actions.impl.common.RandomSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.util.{
|
||||
BattalionNameGenerator,
|
||||
BattalionTypeFinder,
|
||||
PriceIndexUtils
|
||||
import net.eagle0.eagle.model.state.{BattalionType, BattalionTypeId}
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.battalion.concrete.BattalionC
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedBattalionC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.OrganizeTroopsResultType
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessRandomSimpleAction
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.util.{BattalionNameGenerator, PriceIndexUtils}
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.{BattalionId, FactionId}
|
||||
|
||||
@@ -38,13 +40,13 @@ object OrganizeTroopsCommand {
|
||||
private case class OrganizeTroopsCommand(
|
||||
factionId: FactionId,
|
||||
province: ProvinceT,
|
||||
existingBattalions: Vector[Battalion],
|
||||
existingBattalions: Vector[BattalionT],
|
||||
constructibleBattalionTypeIds: Vector[BattalionTypeId],
|
||||
allBattalionTypes: Vector[BattalionType],
|
||||
changedBattalions: Vector[ChangedBattalion],
|
||||
newBattalions: Vector[NewBattalion],
|
||||
troopCosts: Vector[TroopCost]
|
||||
) extends RandomSimpleAction {
|
||||
) extends ProtolessRandomSimpleAction {
|
||||
private def cost(battalionTypeId: BattalionTypeId): Double =
|
||||
troopCosts.find(_.battalionTypeId == battalionTypeId).get.cost
|
||||
|
||||
@@ -55,10 +57,10 @@ object OrganizeTroopsCommand {
|
||||
)
|
||||
|
||||
private def afterOneRemoval(
|
||||
battalionMap: Map[BattalionId, Battalion],
|
||||
battalionMap: Map[BattalionId, BattalionT],
|
||||
troopsMoved: TroopsFromOtherBattalion,
|
||||
expectedType: BattalionTypeId
|
||||
): Map[BattalionId, Battalion] = {
|
||||
): Map[BattalionId, BattalionT] = {
|
||||
commandRequire(
|
||||
battalionMap.contains(troopsMoved.fromBattalionId),
|
||||
s"Moving troops from battalion ${troopsMoved.fromBattalionId}, which does not exist"
|
||||
@@ -72,37 +74,43 @@ object OrganizeTroopsCommand {
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
battBefore.`type` == expectedType,
|
||||
s"Can't change ${battBefore.`type`} troops into $expectedType"
|
||||
battBefore.typeId == expectedType,
|
||||
s"Can't change ${battBefore.typeId} troops into $expectedType"
|
||||
)
|
||||
|
||||
battalionMap + (troopsMoved.fromBattalionId -> battBefore.update(
|
||||
_.size.modify(_ - troopsMoved.countMoved)
|
||||
battalionMap + (troopsMoved.fromBattalionId -> battBefore.updateWith(
|
||||
size = battBefore.size - troopsMoved.countMoved
|
||||
))
|
||||
}
|
||||
|
||||
private def afterRemovals(
|
||||
battalionMap: Map[BattalionId, Battalion],
|
||||
battalionMap: Map[BattalionId, BattalionT],
|
||||
allRemovals: Seq[TroopsFromOtherBattalion],
|
||||
expectedType: BattalionTypeId
|
||||
): Map[BattalionId, Battalion] = {
|
||||
): Map[BattalionId, BattalionT] = {
|
||||
def afterOne(
|
||||
bm: Map[BattalionId, Battalion],
|
||||
bm: Map[BattalionId, BattalionT],
|
||||
t: TroopsFromOtherBattalion
|
||||
): Map[BattalionId, Battalion] = afterOneRemoval(bm, t, expectedType)
|
||||
): Map[BattalionId, BattalionT] = afterOneRemoval(bm, t, expectedType)
|
||||
allRemovals.foldLeft(battalionMap)(afterOne)
|
||||
}
|
||||
|
||||
private def mergeIn(
|
||||
battalion: Battalion,
|
||||
battalion: BattalionT,
|
||||
mergedIn: TroopsFromOtherBattalion
|
||||
): Battalion = {
|
||||
): BattalionT = {
|
||||
val mergedInBatt =
|
||||
existingBattalions.find(_.id == mergedIn.fromBattalionId).get
|
||||
val newSize = battalion.size + mergedIn.countMoved
|
||||
|
||||
val battalionType =
|
||||
BattalionTypeFinder.battalionType(battalion.`type`, allBattalionTypes)
|
||||
allBattalionTypes
|
||||
.find(_.typeId == battalion.typeId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"No battalion type found for ${battalion.typeId}"
|
||||
)
|
||||
)
|
||||
commandRequire(
|
||||
newSize <= battalionType.capacity,
|
||||
s"New size $newSize is higher than battalion capacity after merging in troops"
|
||||
@@ -111,9 +119,9 @@ object OrganizeTroopsCommand {
|
||||
def weighted(origValue: Double, mergedValue: Double): Double =
|
||||
((origValue * battalion.size) + (mergedValue * mergedIn.countMoved)) / newSize
|
||||
|
||||
Battalion(
|
||||
BattalionC(
|
||||
id = battalion.id,
|
||||
`type` = battalion.`type`,
|
||||
typeId = battalion.typeId,
|
||||
size = newSize,
|
||||
training = weighted(battalion.training, mergedInBatt.training),
|
||||
armament = weighted(battalion.armament, mergedInBatt.armament),
|
||||
@@ -122,18 +130,24 @@ object OrganizeTroopsCommand {
|
||||
}
|
||||
|
||||
private def mergeInMultiple(
|
||||
battalion: Battalion,
|
||||
battalion: BattalionT,
|
||||
mergedIn: Seq[TroopsFromOtherBattalion]
|
||||
): Battalion =
|
||||
): BattalionT =
|
||||
mergedIn.foldLeft(battalion)(mergeIn)
|
||||
|
||||
case class BattalionAndCost(battalion: Battalion, cost: Int)
|
||||
case class BattalionAndCost(battalion: BattalionT, cost: Int)
|
||||
private def addTroops(
|
||||
battalion: Battalion,
|
||||
battalion: BattalionT,
|
||||
count: Int
|
||||
): BattalionAndCost = {
|
||||
val battalionType =
|
||||
BattalionTypeFinder.battalionType(battalion.`type`, allBattalionTypes)
|
||||
allBattalionTypes
|
||||
.find(_.typeId == battalion.typeId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"No battalion type found for ${battalion.typeId}"
|
||||
)
|
||||
)
|
||||
val newSize = battalion.size + count
|
||||
commandRequire(
|
||||
newSize <= battalionType.capacity,
|
||||
@@ -144,20 +158,20 @@ object OrganizeTroopsCommand {
|
||||
((origValue * battalion.size) + (inValue * count)) / newSize
|
||||
|
||||
BattalionAndCost(
|
||||
Battalion(
|
||||
BattalionC(
|
||||
id = battalion.id,
|
||||
`type` = battalion.`type`,
|
||||
typeId = battalion.typeId,
|
||||
size = newSize,
|
||||
training = weighted(battalion.training, 0.0),
|
||||
armament = weighted(battalion.armament, 0.0),
|
||||
name = battalion.name
|
||||
),
|
||||
(cost(battalion.`type`) * count).ceil.toInt
|
||||
(cost(battalion.typeId) * count).ceil.toInt
|
||||
)
|
||||
}
|
||||
|
||||
case class BattalionsAndCost(
|
||||
battalions: Map[BattalionId, Battalion],
|
||||
battalions: Map[BattalionId, BattalionT],
|
||||
cost: Int
|
||||
)
|
||||
private def addTroops(
|
||||
@@ -175,7 +189,7 @@ object OrganizeTroopsCommand {
|
||||
|
||||
override def immediateExecute(
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[ActionResult] = {
|
||||
): RandomState[ActionResultT] = {
|
||||
commandRequire(
|
||||
changedBattalions.map(_.id).toSet.subsetOf(province.battalionIds.toSet),
|
||||
s"Attempting to change battalions that are not in province ${province.id}"
|
||||
@@ -183,10 +197,13 @@ object OrganizeTroopsCommand {
|
||||
|
||||
newBattalions.foreach { nb =>
|
||||
checkConstructible(nb.`type`)
|
||||
val battalionType = BattalionTypeFinder.battalionType(
|
||||
nb.`type`,
|
||||
allBattalionTypes
|
||||
)
|
||||
val battalionType = allBattalionTypes
|
||||
.find(_.typeId == nb.`type`)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"No battalion type found for ${nb.`type`}"
|
||||
)
|
||||
)
|
||||
val newSize = nb.newTroops + nb.troopsFromOtherBattalion
|
||||
.map(_.countMoved)
|
||||
.sum
|
||||
@@ -207,12 +224,15 @@ object OrganizeTroopsCommand {
|
||||
changedBattalions.foreach { cb =>
|
||||
val batt = existingBattalions.find(_.id == cb.id).get
|
||||
if cb.newTroops > 0 then {
|
||||
checkConstructible(batt.`type`)
|
||||
checkConstructible(batt.typeId)
|
||||
}
|
||||
val battalionType = BattalionTypeFinder.battalionType(
|
||||
batt.`type`,
|
||||
allBattalionTypes
|
||||
)
|
||||
val battalionType = allBattalionTypes
|
||||
.find(_.typeId == batt.typeId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"No battalion type found for ${batt.typeId}"
|
||||
)
|
||||
)
|
||||
|
||||
cb.troopsFromOtherBattalion.foreach { tfob =>
|
||||
commandRequire(
|
||||
@@ -280,7 +300,7 @@ object OrganizeTroopsCommand {
|
||||
afterRemovals(
|
||||
battMap,
|
||||
cb.troopsFromOtherBattalion,
|
||||
afterRemovingForNew(cb.id).`type`
|
||||
afterRemovingForNew(cb.id).typeId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -296,7 +316,7 @@ object OrganizeTroopsCommand {
|
||||
newBattalionsWithIds
|
||||
.foldLeft(
|
||||
RandomState(
|
||||
newValue = Vector[Battalion](),
|
||||
newValue = Vector[BattalionT](),
|
||||
nextRandom = functionalRandom
|
||||
)
|
||||
) { case (RandomState(acc, fr), (id, nb)) =>
|
||||
@@ -308,9 +328,9 @@ object OrganizeTroopsCommand {
|
||||
)
|
||||
.map { name =>
|
||||
acc :+ mergeInMultiple(
|
||||
Battalion(
|
||||
BattalionC(
|
||||
id = id,
|
||||
`type` = nb.`type`,
|
||||
typeId = nb.`type`,
|
||||
size = 0,
|
||||
name = name
|
||||
),
|
||||
@@ -354,16 +374,19 @@ object OrganizeTroopsCommand {
|
||||
val (changedBatt, newBatt) = afterAddingForChanged.battalions.values
|
||||
.partition(b => startingBattalions.contains(b.id))
|
||||
|
||||
ActionResult(
|
||||
`type` = ORGANIZE_TROOPS,
|
||||
player = Some(factionId),
|
||||
changedBattalions = changedBatt.filterNot(_.size == 0).toVector,
|
||||
ActionResultC(
|
||||
actionResultType = OrganizeTroopsResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
changedBattalions = changedBatt
|
||||
.filterNot(_.size == 0)
|
||||
.map(b => ChangedBattalionC(to = b))
|
||||
.toVector,
|
||||
newBattalions = newBatt.toVector,
|
||||
destroyedBattalionIds =
|
||||
changedBatt.filter(_.size == 0).map(_.id).toVector,
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = province.id,
|
||||
ChangedProvinceC(
|
||||
provinceId = province.id,
|
||||
goldDelta = Some(-afterAddingForChanged.cost),
|
||||
newPriceIndex = PriceIndexUtils.maybeNewPriceIndexFromGoldSpend(
|
||||
province.priceIndex,
|
||||
@@ -371,8 +394,8 @@ object OrganizeTroopsCommand {
|
||||
)
|
||||
)
|
||||
),
|
||||
provinceActed = Some(province.id),
|
||||
province = Some(province.id)
|
||||
provinceIdActed = Some(province.id),
|
||||
provinceId = Some(province.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -382,13 +405,13 @@ object OrganizeTroopsCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
province: ProvinceT,
|
||||
existingBattalions: Vector[Battalion],
|
||||
existingBattalions: Vector[BattalionT],
|
||||
constructibleBattalionTypeIds: Vector[BattalionTypeId],
|
||||
allBattalionTypes: Vector[BattalionType],
|
||||
changedBattalions: Vector[ChangedBattalion],
|
||||
newBattalions: Vector[NewBattalion],
|
||||
troopCosts: Vector[TroopCost]
|
||||
): RandomSimpleAction = {
|
||||
): ProtolessRandomSimpleAction = {
|
||||
commandRequire(
|
||||
changedBattalions.nonEmpty ||
|
||||
newBattalions.nonEmpty,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.ReconAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ReconSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.RECON_STARTED
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.province.IncomingEndTurnAction
|
||||
import net.eagle0.eagle.internal.province.IncomingEndTurnAction.IncomingRecon
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ChangedHeroC, StatDelta}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.ReconStartedResultType
|
||||
import net.eagle0.eagle.model.state.province.{
|
||||
IncomingEndTurnAction,
|
||||
IncomingRecon
|
||||
}
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ReconAgilityXp,
|
||||
ReconVigorCost,
|
||||
@@ -17,73 +18,66 @@ import net.eagle0.eagle.library.settings.{
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
|
||||
object ReconCommand
|
||||
extends CommandBuilder[ReconAvailableCommand, ReconSelectedCommand] {
|
||||
object ReconCommand {
|
||||
|
||||
override def make(
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: ReconAvailableCommand,
|
||||
selectedCommand: ReconSelectedCommand
|
||||
): DeterministicSingleResultCommand = {
|
||||
val actingHeroId = selectedCommand.actingHeroId
|
||||
actingProvinceId: ProvinceId,
|
||||
actingHeroId: HeroId,
|
||||
destinationProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId],
|
||||
availableTargetProvinces: Vector[ProvinceId]
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds.contains(actingHeroId),
|
||||
s"Acting hero $actingHeroId is not among available ${availableCommand.availableHeroIds}"
|
||||
availableHeroIds.contains(actingHeroId),
|
||||
s"Acting hero $actingHeroId is not among available $availableHeroIds"
|
||||
)
|
||||
|
||||
val destinationProvinceId = selectedCommand.targetProvinceId
|
||||
commandRequire(
|
||||
availableCommand.availableTargetProvinces.contains(destinationProvinceId),
|
||||
s"Destination province $destinationProvinceId is not among available ${availableCommand.availableTargetProvinces}"
|
||||
availableTargetProvinces.contains(destinationProvinceId),
|
||||
s"Destination province $destinationProvinceId is not among available $availableTargetProvinces"
|
||||
)
|
||||
|
||||
ReconCommand(
|
||||
sc = selectedCommand,
|
||||
gameState = gameState,
|
||||
factionId = actingFactionId,
|
||||
actingProvinceId = availableCommand.actingProvinceId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
actingHeroId = actingHeroId,
|
||||
destinationProvinceId = destinationProvinceId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ReconCommand(
|
||||
sc: ReconSelectedCommand,
|
||||
gameState: GameState,
|
||||
factionId: FactionId,
|
||||
actingProvinceId: ProvinceId,
|
||||
actingHeroId: HeroId,
|
||||
destinationProvinceId: ProvinceId
|
||||
) extends DeterministicSingleResultCommand(gameState, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = RECON_STARTED,
|
||||
province = Some(actingProvinceId),
|
||||
player = Some(factionId),
|
||||
provinceActed = Some(actingProvinceId),
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = ReconStartedResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
provinceId = Some(actingProvinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = actingProvinceId,
|
||||
removedRulingPlayerHeroIds = Vector(actingHeroId)
|
||||
ChangedProvinceC(
|
||||
provinceId = actingProvinceId,
|
||||
removedRulingFactionHeroIds = Vector(actingHeroId)
|
||||
),
|
||||
ChangedProvince(
|
||||
id = destinationProvinceId,
|
||||
addedIncomingEndTurnActions = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = destinationProvinceId,
|
||||
newIncomingEndTurnActions = Vector(
|
||||
IncomingEndTurnAction(
|
||||
fromFactionId = factionId,
|
||||
fromProvinceId = actingProvinceId,
|
||||
action = IncomingEndTurnAction.Action.Recon(
|
||||
IncomingRecon(heroId = actingHeroId)
|
||||
)
|
||||
details = IncomingRecon(heroId = actingHeroId)
|
||||
)
|
||||
)
|
||||
),
|
||||
removedIncomingEndTurnActions = Vector()
|
||||
)
|
||||
),
|
||||
changedHeroes = Vector(
|
||||
ChangedHero(
|
||||
id = actingHeroId,
|
||||
vigor = VigorDelta(-ReconVigorCost.doubleValue),
|
||||
ChangedHeroC(
|
||||
heroId = actingHeroId,
|
||||
vigorChange = StatDelta(-ReconVigorCost.doubleValue),
|
||||
agilityXpDelta = Some(ReconAgilityXp.intValue),
|
||||
wisdomXpDelta = Some(ReconWisdomXp.intValue)
|
||||
)
|
||||
|
||||
+175
-114
@@ -1,135 +1,196 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.ResolveAllianceOfferAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveAllianceOfferSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
AllianceAcceptedDetails,
|
||||
AllianceAmbassadorImprisonedDetails,
|
||||
AllianceRejectedDetails,
|
||||
Notification
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.diplomacy_offer.DiplomacyOffer
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNKNOWN,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
Unrecognized
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.diplomacy_llm_helpers.DiplomacyResolutionLlmRequestGenerator
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.{EagleCommandException, EagleInternalException}
|
||||
import net.eagle0.eagle.{FactionId, GameId, RoundId}
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.AllianceOfferResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Accepted,
|
||||
Imprisoned,
|
||||
Rejected,
|
||||
Status
|
||||
}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.AllianceOffer
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object ResolveAllianceOfferCommand {
|
||||
private case class ResolveAllianceOfferCommand(
|
||||
sc: ResolveAllianceOfferSelectedCommand,
|
||||
allianceOffer: DiplomacyOffer,
|
||||
resolution: DiplomacyOfferStatus,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator.allianceResolutionRequest(
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
originatingFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = allianceOffer.targetFactionId,
|
||||
messengerHeroId = allianceOffer.messengerHeroId,
|
||||
resolution = resolution
|
||||
)
|
||||
|
||||
ActionResult(
|
||||
`type` = ActionResultType.OFFER_RESOLVED,
|
||||
player = Some(allianceOffer.targetFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = allianceOffer.targetFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(allianceOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(allianceOffer.withStatus(resolution))
|
||||
)
|
||||
),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
AllianceAcceptedDetails(
|
||||
offeringFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = allianceOffer.targetFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
AllianceRejectedDetails(
|
||||
offeringFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = allianceOffer.targetFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
AllianceAmbassadorImprisonedDetails(
|
||||
offeringFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = allianceOffer.targetFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_INVALIDATED =>
|
||||
throw new EagleCommandException(
|
||||
"Invalid diplomacy offers status for command"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_UNKNOWN |
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED | Unrecognized(_) =>
|
||||
throw new EagleInternalException(
|
||||
s"Unknown diplomacy offer status"
|
||||
)
|
||||
},
|
||||
llm = Llm.LlmId(llmRequest.id)
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: ResolveAllianceOfferAvailableCommand,
|
||||
selectedCommand: ResolveAllianceOfferSelectedCommand,
|
||||
originatingFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
messengerOriginProvinceId: ProvinceId,
|
||||
allianceOffer: AllianceOffer,
|
||||
resolution: Status,
|
||||
availableOriginatingFactionIds: Vector[FactionId],
|
||||
availableResolutions: Vector[Status],
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
): SimpleAction = {
|
||||
// check requirements
|
||||
val offeringFid = selectedCommand.originatingFactionId
|
||||
val offers = availableCommand.offers
|
||||
val selectedOffer = offers.find(_.originatingFactionId == offeringFid)
|
||||
|
||||
): ProtolessSimpleAction = {
|
||||
// Validation
|
||||
commandRequire(
|
||||
selectedOffer.nonEmpty,
|
||||
s"Selected faction ID $offeringFid was not among options ${offers.map(_.originatingFactionId)}"
|
||||
availableOriginatingFactionIds.contains(originatingFactionId),
|
||||
s"Selected faction ID $originatingFactionId was not among options $availableOriginatingFactionIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedOffer.get.eligibleStatuses.contains(selectedCommand.resolution),
|
||||
s"Selected alliance resolution ${selectedCommand.resolution} was not among options ${selectedOffer.get.eligibleStatuses}"
|
||||
availableResolutions.contains(resolution),
|
||||
s"Selected alliance resolution $resolution was not among options $availableResolutions"
|
||||
)
|
||||
|
||||
ResolveAllianceOfferCommand(
|
||||
sc = selectedCommand,
|
||||
allianceOffer = selectedOffer.get,
|
||||
resolution = selectedCommand.resolution,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
allianceOffer = allianceOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ResolveAllianceOfferCommand(
|
||||
actingFactionId: FactionId,
|
||||
originatingFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
messengerOriginProvinceId: ProvinceId,
|
||||
allianceOffer: AllianceOffer,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"${currentRoundId} resolve alliance offer ${messengerHeroId}"
|
||||
|
||||
resolution match {
|
||||
case Accepted => acceptAllianceOffer(llmRequestId)
|
||||
case Rejected => rejectAllianceOffer(llmRequestId)
|
||||
case Imprisoned => imprisonAmbassador(llmRequestId)
|
||||
case _ =>
|
||||
throw new EagleCommandException(
|
||||
s"Invalid diplomacy offer status for command: $resolution"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def acceptAllianceOffer(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(allianceOffer.copy(status = Accepted))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(createNotification(llmRequestId, Accepted)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Accepted))
|
||||
)
|
||||
}
|
||||
|
||||
private def rejectAllianceOffer(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(allianceOffer.copy(status = Rejected))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(createNotification(llmRequestId, Rejected)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Rejected))
|
||||
)
|
||||
}
|
||||
|
||||
private def imprisonAmbassador(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(allianceOffer.copy(status = Imprisoned))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(createNotification(llmRequestId, Imprisoned)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Imprisoned))
|
||||
)
|
||||
}
|
||||
|
||||
private def createNotification(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): NotificationC = {
|
||||
NotificationC(
|
||||
details = status match {
|
||||
case Accepted =>
|
||||
NotificationDetails.AllianceAccepted(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
|
||||
case Rejected =>
|
||||
NotificationDetails.AllianceRejected(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
|
||||
case Imprisoned =>
|
||||
NotificationDetails.AllianceAmbassadorImprisoned(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
|
||||
case _ =>
|
||||
throw new EagleCommandException(s"Unexpected status: $status")
|
||||
},
|
||||
affectedProvinceIds = Vector(),
|
||||
affectedHeroIds = Vector(messengerHeroId),
|
||||
llm = NotificationT.Llm.Id(llmRequestId),
|
||||
deferred = false
|
||||
)
|
||||
}
|
||||
|
||||
private def createLlmRequest(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): AllianceOfferResolutionMessage = {
|
||||
AllianceOfferResolutionMessage(
|
||||
requestId = llmRequestId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector.empty,
|
||||
alwaysGenerate = false,
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolution = status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+132
-98
@@ -1,130 +1,164 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.ResolveBreakAllianceAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveBreakAllianceSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
BreakAllianceAcceptedDetails,
|
||||
BreakAllianceAmbassadorImprisonedDetails,
|
||||
Notification
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.diplomacy_offer.DiplomacyOffer
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNKNOWN,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
Unrecognized
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.diplomacy_llm_helpers.DiplomacyResolutionLlmRequestGenerator
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.{EagleCommandException, EagleInternalException}
|
||||
import net.eagle0.eagle.{FactionId, GameId, RoundId}
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.BreakAllianceResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Accepted,
|
||||
Imprisoned,
|
||||
Rejected,
|
||||
Status
|
||||
}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{
|
||||
BreakAlliance,
|
||||
DiplomacyOffer
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object ResolveBreakAllianceCommand {
|
||||
private case class ResolveBreakAllianceCommand(
|
||||
sc: ResolveBreakAllianceSelectedCommand,
|
||||
breakAllianceOffer: DiplomacyOffer,
|
||||
resolution: DiplomacyOfferStatus,
|
||||
actingFactionId: FactionId,
|
||||
originatingFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
messengerOriginProvinceId: ProvinceId,
|
||||
breakAllianceOffer: BreakAlliance,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator.breakAllianceResolutionRequest(
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
originatingFactionId = breakAllianceOffer.originatingFactionId,
|
||||
targetFactionId = breakAllianceOffer.targetFactionId,
|
||||
messengerHeroId = breakAllianceOffer.messengerHeroId,
|
||||
resolution = resolution
|
||||
)
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"$currentRoundId resolve break alliance $messengerHeroId"
|
||||
|
||||
ActionResult(
|
||||
`type` = ActionResultType.OFFER_RESOLVED,
|
||||
player = Some(breakAllianceOffer.targetFactionId),
|
||||
resolution match {
|
||||
case Accepted =>
|
||||
acceptBreakAlliance(llmRequestId)
|
||||
case Imprisoned =>
|
||||
imprisonAmbassador(llmRequestId)
|
||||
case Rejected =>
|
||||
throw new EagleCommandException(
|
||||
"REJECTED not valid for break alliance"
|
||||
)
|
||||
case _ =>
|
||||
throw new EagleCommandException(
|
||||
s"Invalid diplomacy offer status for command: $resolution"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def acceptBreakAlliance(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = breakAllianceOffer.targetFactionId,
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(breakAllianceOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(breakAllianceOffer.withStatus(resolution))
|
||||
Vector(originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(breakAllianceOffer.copy(status = Accepted))
|
||||
)
|
||||
),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
BreakAllianceAcceptedDetails(
|
||||
offeringFactionId = breakAllianceOffer.originatingFactionId,
|
||||
targetFactionId = breakAllianceOffer.targetFactionId,
|
||||
ambassadorHeroId = breakAllianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
throw new EagleCommandException(
|
||||
"REJECTED not valid for break alliance"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
BreakAllianceAmbassadorImprisonedDetails(
|
||||
offeringFactionId = breakAllianceOffer.originatingFactionId,
|
||||
targetFactionId = breakAllianceOffer.targetFactionId,
|
||||
ambassadorHeroId = breakAllianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_INVALIDATED =>
|
||||
throw new EagleCommandException(
|
||||
"Invalid diplomacy offers status for command"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_UNKNOWN |
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED | Unrecognized(_) =>
|
||||
throw new EagleInternalException(
|
||||
s"Unknown diplomacy offer status"
|
||||
)
|
||||
},
|
||||
llm = Llm.LlmId(llmRequest.id)
|
||||
newNotifications = Vector(
|
||||
NotificationC(
|
||||
details = NotificationDetails.BreakAllianceAccepted(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
),
|
||||
affectedHeroIds = Vector(messengerHeroId),
|
||||
deferred = true
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest)
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Accepted))
|
||||
)
|
||||
}
|
||||
|
||||
private def imprisonAmbassador(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(breakAllianceOffer.copy(status = Imprisoned))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(
|
||||
NotificationC(
|
||||
details = NotificationDetails.BreakAllianceAmbassadorImprisoned(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
),
|
||||
affectedHeroIds = Vector(messengerHeroId),
|
||||
deferred = true
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Imprisoned))
|
||||
)
|
||||
}
|
||||
|
||||
private def createLlmRequest(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): BreakAllianceResolutionMessage = {
|
||||
BreakAllianceResolutionMessage(
|
||||
requestId = llmRequestId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector.empty,
|
||||
alwaysGenerate = false,
|
||||
breakingFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolution = status
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: ResolveBreakAllianceAvailableCommand,
|
||||
selectedCommand: ResolveBreakAllianceSelectedCommand,
|
||||
originatingFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
messengerOriginProvinceId: ProvinceId,
|
||||
breakAllianceOffer: BreakAlliance,
|
||||
resolution: Status,
|
||||
availableOriginatingFactionIds: Vector[FactionId],
|
||||
availableResolutions: Vector[Status],
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
): SimpleAction = {
|
||||
// check requirements
|
||||
val breakingFid = selectedCommand.originatingFactionId
|
||||
val offers = availableCommand.offers
|
||||
val selectedOffer = offers.find(_.originatingFactionId == breakingFid)
|
||||
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
selectedOffer.nonEmpty,
|
||||
s"Selected faction ID $breakingFid was not among options ${offers.map(_.originatingFactionId)}"
|
||||
availableOriginatingFactionIds.contains(originatingFactionId),
|
||||
s"Selected faction ID $originatingFactionId was not among options $availableOriginatingFactionIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedOffer.get.eligibleStatuses.contains(selectedCommand.resolution),
|
||||
s"Selected break alliance resolution ${selectedCommand.resolution} was not among options ${selectedOffer.get.eligibleStatuses}"
|
||||
availableResolutions.contains(resolution),
|
||||
s"Selected break alliance resolution $resolution was not among options $availableResolutions"
|
||||
)
|
||||
|
||||
ResolveBreakAllianceCommand(
|
||||
sc = selectedCommand,
|
||||
breakAllianceOffer = selectedOffer.get,
|
||||
resolution = selectedCommand.resolution,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
breakAllianceOffer = breakAllianceOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
|
||||
+220
-204
@@ -1,238 +1,254 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.ResolveInvitationAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveInvitationSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm.LlmId
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
InvitationAcceptedDetails,
|
||||
InvitationAmbassadorImprisonedDetails,
|
||||
InvitationRejectedDetails,
|
||||
Notification
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.diplomacy_offer.DiplomacyOffer
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.generated_text_request.GeneratedTextRequest
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.diplomacy_llm_helpers.DiplomacyResolutionLlmRequestGenerator
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
|
||||
object ResolveInvitationCommand
|
||||
extends CommandBuilder[
|
||||
ResolveInvitationAvailableCommand,
|
||||
ResolveInvitationSelectedCommand
|
||||
] {
|
||||
private def llmRequestForResolution(
|
||||
gameState: GameState,
|
||||
invitation: DiplomacyOffer,
|
||||
resolution: DiplomacyOfferStatus
|
||||
): GeneratedTextRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator
|
||||
.invitationResolutionRequest(
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
originatingFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = invitation.targetFactionId,
|
||||
messengerHeroId = invitation.messengerHeroId,
|
||||
resolution = resolution
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.InvitationResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.types.InvitationResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{DiplomacyOffer, Invitation}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Status,
|
||||
Accepted,
|
||||
Rejected,
|
||||
Imprisoned,
|
||||
Invalidated
|
||||
}
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object ResolveInvitationCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
originatingFactionId: FactionId,
|
||||
resolution: Status,
|
||||
allFactions: Map[
|
||||
FactionId,
|
||||
FactionT
|
||||
], // All factions with their diplomacy offers
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
): ProtolessSimpleAction = {
|
||||
// Find the acting faction and invitation
|
||||
val actingFaction = allFactions.getOrElse(
|
||||
actingFactionId,
|
||||
throw new EagleCommandException(
|
||||
s"Acting faction $actingFactionId not found in faction data"
|
||||
)
|
||||
)
|
||||
|
||||
val invitation = actingFaction.incomingDiplomacyOffers
|
||||
.collectFirst {
|
||||
case inv: Invitation
|
||||
if inv.originatingFactionId == originatingFactionId =>
|
||||
inv
|
||||
}
|
||||
.getOrElse(
|
||||
throw new EagleCommandException(
|
||||
s"Invitation from faction $originatingFactionId not found"
|
||||
)
|
||||
)
|
||||
|
||||
private case class AcceptInvitationCommand(
|
||||
sc: ResolveInvitationSelectedCommand,
|
||||
gs: GameState,
|
||||
invitation: DiplomacyOffer
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
private val acceptingFid = invitation.targetFactionId
|
||||
private val acceptedInvitation =
|
||||
invitation.withStatus(DIPLOMACY_OFFER_STATUS_ACCEPTED)
|
||||
// Derive available originating faction IDs from all invitations
|
||||
val availableOriginatingFactionIds = actingFaction.incomingDiplomacyOffers
|
||||
.collect { case inv: Invitation => inv.originatingFactionId }
|
||||
|
||||
private def invalidatedOutgoings: Vector[ChangedFaction] =
|
||||
gs.factions.values.filterNot(_.id == acceptingFid).toVector.map {
|
||||
faction =>
|
||||
ChangedFaction(
|
||||
id = faction.id,
|
||||
removedIncomingDiplomacyOfferFactionIds = Vector(acceptingFid),
|
||||
addedIncomingDiplomacyOffers = faction.incomingDiplomacyOffers
|
||||
.filter(_.originatingFactionId == acceptingFid)
|
||||
.map(_.withStatus(DIPLOMACY_OFFER_STATUS_INVALIDATED))
|
||||
// Validate the originating faction ID
|
||||
commandRequire(
|
||||
availableOriginatingFactionIds.contains(originatingFactionId),
|
||||
s"Selected faction ID $originatingFactionId was not among options $availableOriginatingFactionIds"
|
||||
)
|
||||
|
||||
// Validate the resolution against the invitation's eligible statuses
|
||||
commandRequire(
|
||||
invitation.eligibleStatuses.contains(resolution),
|
||||
s"Selected invitation resolution $resolution was not among options ${invitation.eligibleStatuses}"
|
||||
)
|
||||
|
||||
ResolveInvitationCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
invitation = invitation,
|
||||
resolution = resolution,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ResolveInvitationCommand(
|
||||
actingFactionId: FactionId,
|
||||
invitation: Invitation,
|
||||
resolution: Status,
|
||||
allFactions: Map[FactionId, FactionT],
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"${currentRoundId} resolve invitation ${invitation.messengerHeroId}"
|
||||
|
||||
resolution match {
|
||||
case Accepted => acceptInvitation(llmRequestId)
|
||||
case Rejected => rejectInvitation(llmRequestId)
|
||||
case Imprisoned => imprisonAmbassador(llmRequestId)
|
||||
case _ =>
|
||||
throw new EagleCommandException(
|
||||
s"Invalid diplomacy offer status for command: $resolution"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest = llmRequestForResolution(
|
||||
gameState = gs,
|
||||
invitation = invitation,
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED
|
||||
private def acceptInvitation(llmRequestId: String): ActionResultT = {
|
||||
// When accepting invitation, we need to:
|
||||
// 1. Invalidate ALL outgoing offers FROM the accepting faction TO other factions
|
||||
// 2. Remove ALL incoming offers TO the accepting faction and add them back invalidated
|
||||
// 3. Add the accepted invitation back with ACCEPTED status
|
||||
|
||||
val acceptingFaction = allFactions(actingFactionId)
|
||||
val acceptedInvitation = invitation.copy(status = Accepted)
|
||||
|
||||
// Invalidate outgoing offers: Check all factions for incoming offers FROM accepting faction
|
||||
val invalidatedOutgoingsChanges = allFactions.values.toVector
|
||||
.filterNot(_.id == actingFactionId)
|
||||
.map { otherFaction =>
|
||||
val outgoingOffersToInvalidate = otherFaction.incomingDiplomacyOffers
|
||||
.filter(_.originatingFactionId == actingFactionId)
|
||||
|
||||
ChangedFactionC(
|
||||
factionId = otherFaction.id,
|
||||
newIncomingDiplomacyOffers =
|
||||
outgoingOffersToInvalidate.map(_.withStatus(Invalidated)),
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
if outgoingOffersToInvalidate.nonEmpty then
|
||||
Vector(actingFactionId)
|
||||
else Vector.empty
|
||||
)
|
||||
}
|
||||
.filter(
|
||||
_.removedIncomingDiplomacyOfferFactionIds.nonEmpty
|
||||
) // Only include factions with changes
|
||||
|
||||
// Handle accepting faction: invalidate all OTHER incoming offers, accept the selected one
|
||||
val allIncomingOffers = acceptingFaction.incomingDiplomacyOffers
|
||||
val otherIncomingOffers = allIncomingOffers.filterNot(offer =>
|
||||
offer.originatingFactionId == invitation.originatingFactionId &&
|
||||
offer.messengerHeroId == invitation.messengerHeroId
|
||||
)
|
||||
val invalidatedIncomingOffers =
|
||||
otherIncomingOffers.map(_.withStatus(Invalidated))
|
||||
|
||||
val acceptingFactionChange = ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
newIncomingDiplomacyOffers =
|
||||
acceptedInvitation +: invalidatedIncomingOffers,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
allIncomingOffers.map(_.originatingFactionId)
|
||||
)
|
||||
|
||||
ActionResult(
|
||||
`type` = ActionResultType.INVITATION_RESOLVED,
|
||||
player = Some(acceptingFid),
|
||||
changedFactions = invalidatedOutgoings ++ Vector(
|
||||
ChangedFaction(
|
||||
id = acceptingFid,
|
||||
removedIncomingDiplomacyOfferFactionIds = gs
|
||||
.factions(acceptingFid)
|
||||
.incomingDiplomacyOffers
|
||||
.map(_.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers = gs
|
||||
.factions(acceptingFid)
|
||||
.incomingDiplomacyOffers
|
||||
.filterNot(
|
||||
_.originatingFactionId == invitation.originatingFactionId
|
||||
)
|
||||
.map(
|
||||
_.withStatus(DIPLOMACY_OFFER_STATUS_INVALIDATED)
|
||||
) :+ acceptedInvitation
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest),
|
||||
notificationsToDeliver = Vector(
|
||||
Notification(
|
||||
details = InvitationAcceptedDetails(
|
||||
offeringFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = invitation.targetFactionId
|
||||
),
|
||||
llm = LlmId(llmRequest.id)
|
||||
)
|
||||
)
|
||||
ActionResultC(
|
||||
actionResultType = InvitationResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = invalidatedOutgoingsChanges :+ acceptingFactionChange,
|
||||
newNotifications = Vector(createNotification(llmRequestId, Accepted)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Accepted))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class RejectInvitationCommand(
|
||||
sc: ResolveInvitationSelectedCommand,
|
||||
gs: GameState,
|
||||
invitation: DiplomacyOffer
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
private val rejectingFid = invitation.targetFactionId
|
||||
private val rejectedInvitation =
|
||||
invitation.withStatus(DIPLOMACY_OFFER_STATUS_REJECTED)
|
||||
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest = llmRequestForResolution(
|
||||
gameState = gs,
|
||||
invitation = invitation,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
ActionResult(
|
||||
`type` = ActionResultType.INVITATION_RESOLVED,
|
||||
player = Some(rejectingFid),
|
||||
private def rejectInvitation(llmRequestId: String): ActionResultT = {
|
||||
// When rejecting, only update the single invitation being rejected
|
||||
ActionResultC(
|
||||
actionResultType = InvitationResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = rejectingFid,
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(invitation.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers = Vector(rejectedInvitation)
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(invitation.copy(status = Rejected))
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest),
|
||||
notificationsToDeliver = Vector(
|
||||
Notification(
|
||||
details = InvitationRejectedDetails(
|
||||
offeringFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = invitation.targetFactionId
|
||||
),
|
||||
llm = LlmId(llmRequest.id)
|
||||
)
|
||||
)
|
||||
newNotifications = Vector(createNotification(llmRequestId, Rejected)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Rejected))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class ImprisonAmbassadorCommand(
|
||||
sc: ResolveInvitationSelectedCommand,
|
||||
gs: GameState,
|
||||
invitation: DiplomacyOffer
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
private val rejectingFid = invitation.targetFactionId
|
||||
private val rejectedInvitation =
|
||||
invitation.withStatus(DIPLOMACY_OFFER_STATUS_IMPRISONED)
|
||||
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest = llmRequestForResolution(
|
||||
gameState = gs,
|
||||
invitation = invitation,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
ActionResult(
|
||||
`type` = ActionResultType.INVITATION_RESOLVED,
|
||||
player = Some(rejectingFid),
|
||||
private def imprisonAmbassador(llmRequestId: String): ActionResultT = {
|
||||
// When imprisoning, only update the single invitation being rejected
|
||||
ActionResultC(
|
||||
actionResultType = InvitationResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = rejectingFid,
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(invitation.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers = Vector(rejectedInvitation)
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(invitation.copy(status = Imprisoned))
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = InvitationAmbassadorImprisonedDetails(
|
||||
newNotifications = Vector(createNotification(llmRequestId, Imprisoned)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Imprisoned))
|
||||
)
|
||||
}
|
||||
|
||||
private def createNotification(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): NotificationC = {
|
||||
NotificationC(
|
||||
details = status match {
|
||||
case Accepted =>
|
||||
NotificationDetails.InvitationAccepted(
|
||||
offeringFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = invitation.targetFactionId,
|
||||
invitedFactionId = actingFactionId
|
||||
)
|
||||
|
||||
case Rejected =>
|
||||
NotificationDetails.InvitationRejected(
|
||||
offeringFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = actingFactionId
|
||||
)
|
||||
|
||||
case Imprisoned =>
|
||||
NotificationDetails.InvitationAmbassadorImprisoned(
|
||||
offeringFactionId = invitation.originatingFactionId,
|
||||
invitedFactionId = actingFactionId,
|
||||
ambassadorHeroId = invitation.messengerHeroId
|
||||
),
|
||||
llm = LlmId(llmRequest.id)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case _ =>
|
||||
throw new EagleCommandException(s"Unexpected status: $status")
|
||||
},
|
||||
affectedProvinceIds = Vector(),
|
||||
affectedHeroIds = Vector(invitation.messengerHeroId),
|
||||
llm = NotificationT.Llm.Id(llmRequestId),
|
||||
deferred =
|
||||
status == Imprisoned // Only imprison notifications are deferred
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: ResolveInvitationAvailableCommand,
|
||||
selectedCommand: ResolveInvitationSelectedCommand
|
||||
): Command = {
|
||||
// check requirements
|
||||
|
||||
val invitingFid = selectedCommand.originatingFactionId
|
||||
val invitations = availableCommand.invitations
|
||||
val selectedInvitation =
|
||||
invitations.find(_.originatingFactionId == invitingFid)
|
||||
|
||||
commandRequire(
|
||||
selectedInvitation.nonEmpty,
|
||||
s"Selected faction ID $invitingFid was not among options ${invitations.map(_.originatingFactionId).toList}"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedInvitation.get.eligibleStatuses
|
||||
.contains(selectedCommand.resolution),
|
||||
s"Selected invitation resolution ${selectedCommand.resolution} was not among options ${selectedInvitation.get.eligibleStatuses}"
|
||||
)
|
||||
|
||||
selectedCommand.resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
AcceptInvitationCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
invitation = selectedInvitation.get
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
RejectInvitationCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
invitation = selectedInvitation.get
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
ImprisonAmbassadorCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
invitation = selectedInvitation.get
|
||||
)
|
||||
case _ => ???
|
||||
private def createLlmRequest(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): InvitationResolutionMessage = {
|
||||
InvitationResolutionMessage(
|
||||
requestId = llmRequestId,
|
||||
eagleGameId = gameId,
|
||||
invitingFactionId = invitation.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = invitation.messengerHeroId,
|
||||
resolution = status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+159
-165
@@ -1,184 +1,178 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.ResolveRansomOfferAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveRansomOfferSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
Notification,
|
||||
RansomPaidDetails,
|
||||
RansomRejectedDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
DiplomacyOffer,
|
||||
RansomOfferDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNKNOWN,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
Unrecognized
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.diplomacy_llm_helpers.DiplomacyResolutionLlmRequestGenerator
|
||||
import net.eagle0.eagle.library.{EagleCommandException, EagleInternalException}
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.RansomResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{
|
||||
DiplomacyOffer,
|
||||
RansomOffer
|
||||
}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Status,
|
||||
Accepted,
|
||||
Rejected
|
||||
}
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.{FactionId, GameId, RoundId}
|
||||
|
||||
object ResolveRansomOfferCommand
|
||||
extends CommandBuilder[
|
||||
ResolveRansomOfferAvailableCommand,
|
||||
ResolveRansomOfferSelectedCommand
|
||||
] {
|
||||
object ResolveRansomOfferCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
originatingFactionId: FactionId,
|
||||
resolution: Status,
|
||||
allFactions: Map[
|
||||
FactionId,
|
||||
FactionT
|
||||
], // All factions with their diplomacy offers
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
): ProtolessSimpleAction = {
|
||||
// Find the acting faction and ransom offer
|
||||
val actingFaction = allFactions.getOrElse(
|
||||
actingFactionId,
|
||||
throw new EagleCommandException(
|
||||
s"Acting faction $actingFactionId not found in faction data"
|
||||
)
|
||||
)
|
||||
|
||||
private def withResolution(
|
||||
gameState: GameState,
|
||||
ransomOffer: DiplomacyOffer,
|
||||
resolution: DiplomacyOfferStatus
|
||||
): ActionResult = ransomOffer.offerDetails match {
|
||||
case RansomOfferDetails(
|
||||
Some(prisonerToBeRansomed),
|
||||
_ /* prisonersOffered */,
|
||||
_ /* hostagesOffered */,
|
||||
_ /* goldOffered */,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
val llmRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator.ransomResolutionRequest(
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
originatingFactionId = ransomOffer.originatingFactionId,
|
||||
targetFactionId = ransomOffer.targetFactionId,
|
||||
ransomedHeroId = prisonerToBeRansomed.prisonerHeroId,
|
||||
resolution = resolution
|
||||
val ransomOffer = actingFaction.incomingDiplomacyOffers
|
||||
.collectFirst {
|
||||
case offer: RansomOffer
|
||||
if offer.originatingFactionId == originatingFactionId =>
|
||||
offer
|
||||
}
|
||||
.getOrElse(
|
||||
throw new EagleCommandException(
|
||||
s"Ransom offer from faction $originatingFactionId not found"
|
||||
)
|
||||
ActionResult(
|
||||
`type` = ActionResultType.OFFER_RESOLVED,
|
||||
player = Some(ransomOffer.targetFactionId),
|
||||
)
|
||||
|
||||
// Validate the resolution against the ransom offer's eligible statuses
|
||||
commandRequire(
|
||||
ransomOffer.eligibleStatuses.contains(resolution),
|
||||
s"Selected ransom offer resolution $resolution was not among options ${ransomOffer.eligibleStatuses}"
|
||||
)
|
||||
|
||||
ResolveRansomOfferCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
ransomOffer = ransomOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ResolveRansomOfferCommand(
|
||||
actingFactionId: FactionId,
|
||||
ransomOffer: RansomOffer,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"${currentRoundId} resolve ransom offer ${ransomOffer.messengerHeroId}"
|
||||
|
||||
resolution match {
|
||||
case Accepted => acceptRansomOffer(llmRequestId)
|
||||
case Rejected => rejectRansomOffer(llmRequestId)
|
||||
case _ =>
|
||||
throw new EagleCommandException(
|
||||
s"Invalid diplomacy offer status for command: $resolution"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def acceptRansomOffer(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = ransomOffer.targetFactionId,
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(ransomOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(ransomOffer.withStatus(resolution))
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(ransomOffer.copy(status = Accepted))
|
||||
)
|
||||
),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
RansomPaidDetails(
|
||||
ransomedHeroId = prisonerToBeRansomed.prisonerHeroId,
|
||||
ransomPaidByFactionId = ransomOffer.originatingFactionId,
|
||||
ransomPaidToFactionId = ransomOffer.targetFactionId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
RansomRejectedDetails(
|
||||
ransomedHeroId = prisonerToBeRansomed.prisonerHeroId,
|
||||
ransomOfferingFactionId = ransomOffer.originatingFactionId,
|
||||
ransomRefusedByFactionId = ransomOffer.targetFactionId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
throw new EagleInternalException(
|
||||
s"IMPRISONED not valid for ransom offer"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_INVALIDATED =>
|
||||
throw new EagleInternalException(
|
||||
s"INVALIDATED not valid for ransom offer"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_UNKNOWN |
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED | Unrecognized(_) =>
|
||||
throw new EagleInternalException(
|
||||
s"Unknown diplomacy offer status"
|
||||
)
|
||||
},
|
||||
llm = Llm.LlmId(llmRequest.id)
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(llmRequest)
|
||||
newNotifications = Vector(createNotification(llmRequestId, Accepted)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Accepted))
|
||||
)
|
||||
case _ => throw new EagleInternalException("Not a ransom offer")
|
||||
}
|
||||
}
|
||||
|
||||
private case class AcceptRansomOfferCommand(
|
||||
sc: ResolveRansomOfferSelectedCommand,
|
||||
gs: GameState,
|
||||
ransomOffer: DiplomacyOffer
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
withResolution(gs, ransomOffer, DIPLOMACY_OFFER_STATUS_ACCEPTED)
|
||||
}
|
||||
private def rejectRansomOffer(llmRequestId: String): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(ransomOffer.originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(ransomOffer.copy(status = Rejected))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(createNotification(llmRequestId, Rejected)),
|
||||
newGeneratedTextRequests =
|
||||
Vector(createLlmRequest(llmRequestId, Rejected))
|
||||
)
|
||||
}
|
||||
|
||||
private case class RejectRansomOfferCommand(
|
||||
sc: ResolveRansomOfferSelectedCommand,
|
||||
gs: GameState,
|
||||
ransomOffer: DiplomacyOffer
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
private def createNotification(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): NotificationC = {
|
||||
NotificationC(
|
||||
details = status match {
|
||||
case Accepted =>
|
||||
NotificationDetails.RansomPaid(
|
||||
ransomedHeroId = ransomOffer.prisonerToBeRansomed.prisonerHeroId,
|
||||
ransomPaidByFactionId = actingFactionId,
|
||||
ransomPaidToFactionId = ransomOffer.originatingFactionId
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
withResolution(gs, ransomOffer, DIPLOMACY_OFFER_STATUS_REJECTED)
|
||||
}
|
||||
case Rejected =>
|
||||
NotificationDetails.RansomRejected(
|
||||
ransomedHeroId = ransomOffer.prisonerToBeRansomed.prisonerHeroId,
|
||||
ransomRefusedByFactionId = actingFactionId,
|
||||
ransomOfferingFactionId = ransomOffer.originatingFactionId
|
||||
)
|
||||
|
||||
override def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: ResolveRansomOfferAvailableCommand,
|
||||
selectedCommand: ResolveRansomOfferSelectedCommand
|
||||
): Command = {
|
||||
// check requirements
|
||||
case _ =>
|
||||
throw new EagleCommandException(s"Unexpected status: $status")
|
||||
},
|
||||
affectedProvinceIds = Vector(),
|
||||
affectedHeroIds = Vector(ransomOffer.messengerHeroId),
|
||||
llm = NotificationT.Llm.Id(llmRequestId),
|
||||
deferred = false
|
||||
)
|
||||
}
|
||||
|
||||
val offeringFid = selectedCommand.offeringFactionId
|
||||
val offers = availableCommand.offers
|
||||
val selectedOffer = offers.find(_.originatingFactionId == offeringFid)
|
||||
|
||||
commandRequire(
|
||||
selectedOffer.nonEmpty,
|
||||
s"Selected faction ID $offeringFid was not among options ${offers.map(_.originatingFactionId)}"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedOffer.get.eligibleStatuses.contains(selectedCommand.resolution),
|
||||
s"Selected ransom resolution ${selectedCommand.resolution} was not among options ${selectedOffer.get.eligibleStatuses}"
|
||||
)
|
||||
|
||||
selectedCommand.resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
AcceptRansomOfferCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
ransomOffer = selectedOffer.get
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
RejectRansomOfferCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
ransomOffer = selectedOffer.get
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
throw new EagleCommandException(
|
||||
"IMPRISONED not valid for ransom resolution"
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_INVALIDATED =>
|
||||
throw new EagleCommandException(
|
||||
"INVALIDATED not valid for ransom resolution"
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_UNRESOLVED =>
|
||||
throw new EagleCommandException(
|
||||
"UNRESOLVED not valid for ransom resolution"
|
||||
)
|
||||
case DIPLOMACY_OFFER_STATUS_UNKNOWN |
|
||||
DiplomacyOfferStatus.Unrecognized(_) =>
|
||||
throw new EagleCommandException("Unknown diplomacy offer status")
|
||||
private def createLlmRequest(
|
||||
llmRequestId: String,
|
||||
status: Status
|
||||
): RansomResolutionMessage = {
|
||||
RansomResolutionMessage(
|
||||
requestId = llmRequestId,
|
||||
eagleGameId = gameId,
|
||||
offeringFactionId = ransomOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
offeringHeroId = ransomOffer.messengerHeroId,
|
||||
ransomedHeroId = ransomOffer.prisonerToBeRansomed.prisonerHeroId,
|
||||
resolution = status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+138
-177
@@ -1,195 +1,156 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
ResolveTributeAvailableCommand,
|
||||
TributeAndFaction
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC
|
||||
}
|
||||
import net.eagle0.eagle.api.selected_command.ResolveTributeSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.tribute_amount.TributeAmount
|
||||
import net.eagle0.eagle.internal.faction_relationship.FactionRelationship
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.army.{
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.{
|
||||
ChangedProvinceC,
|
||||
HostileArmyStatusChange
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
TributePaidResultType,
|
||||
TributeRefusedResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.{
|
||||
Attacking,
|
||||
HostileArmyGroup,
|
||||
TributeDemanded,
|
||||
TributePaid
|
||||
}
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince.HostileArmyGroupStatusChange
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.util.DateProtoUtils.*
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.util.faction_utils.LegacyFactionUtils
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.model.state.TributeAmount
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship.RelationshipLevel
|
||||
import net.eagle0.eagle.{FactionId, GameId, ProvinceId, RoundId}
|
||||
|
||||
object ResolveTributeCommand
|
||||
extends CommandBuilder[
|
||||
ResolveTributeAvailableCommand,
|
||||
ResolveTributeSelectedCommand
|
||||
] {
|
||||
|
||||
private case class PayTributeCommand(
|
||||
sc: ResolveTributeSelectedCommand,
|
||||
gs: GameState,
|
||||
pid: ProvinceId,
|
||||
demandingArmy: HostileArmyGroup,
|
||||
payingFid: FactionId
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
lazy val otherTributeDemandingCps: Vector[ChangedProvince] =
|
||||
gs.provinces.values
|
||||
.filter(_.rulingFactionId.contains(payingFid))
|
||||
.flatMap { province =>
|
||||
province.hostileArmies
|
||||
.find(_.factionId == demandingArmy.factionId)
|
||||
.filter(_.status.asMessage.sealedValue.isTributeDemanded)
|
||||
.map { ha =>
|
||||
ChangedProvince(
|
||||
id = province.id,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = ha.factionId,
|
||||
newStatus = TributePaid(Some(TributeAmount(0, 0)))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.toVector
|
||||
|
||||
override def immediateExecute: ActionResult = {
|
||||
val tributeAmount = demandingArmy.status match {
|
||||
case TributeDemanded(tributeAmount, _ /* unknownFieldSet */ ) =>
|
||||
tributeAmount
|
||||
case _ => throw new IllegalStateException("Tribute not paid")
|
||||
}
|
||||
ActionResult(
|
||||
`type` = ActionResultType.TRIBUTE_PAID,
|
||||
player = Some(payingFid),
|
||||
changedProvinces = ChangedProvince(
|
||||
id = pid,
|
||||
goldDelta = Some(-tributeAmount.get.gold),
|
||||
foodDelta = Some(-tributeAmount.get.food),
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = demandingArmy.factionId,
|
||||
newStatus = TributePaid(tributeAmount = tributeAmount)
|
||||
)
|
||||
)
|
||||
) +: otherTributeDemandingCps,
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = payingFid,
|
||||
changedFactionRelationships = Vector(
|
||||
LegacyFactionUtils
|
||||
.factionRelationship(payingFid, demandingArmy.factionId, gs)
|
||||
.update(
|
||||
_.relationshipLevel := FactionRelationship.RelationshipLevel.TRUCE,
|
||||
_.resetDate := gs.currentDate.get.addMonths(12)
|
||||
)
|
||||
)
|
||||
),
|
||||
ChangedFaction(
|
||||
id = demandingArmy.factionId,
|
||||
changedFactionRelationships = Vector(
|
||||
LegacyFactionUtils
|
||||
.factionRelationship(demandingArmy.factionId, payingFid, gs)
|
||||
.update(
|
||||
_.relationshipLevel := FactionRelationship.RelationshipLevel.TRUCE,
|
||||
_.resetDate := gs.currentDate.get.addMonths(12)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class RejectDemandCommand(
|
||||
sc: ResolveTributeSelectedCommand,
|
||||
gs: GameState,
|
||||
pid: ProvinceId,
|
||||
demandingArmy: HostileArmyGroup,
|
||||
rejectingFid: FactionId
|
||||
) extends DeterministicSingleResultCommand(gs, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = ActionResultType.TRIBUTE_REFUSED,
|
||||
player = Some(rejectingFid),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = pid,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = demandingArmy.factionId,
|
||||
newStatus = Attacking()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override def make(
|
||||
object ResolveTributeCommand {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: ResolveTributeAvailableCommand,
|
||||
selectedCommand: ResolveTributeSelectedCommand
|
||||
): Command = {
|
||||
val demandingFid = selectedCommand.demandingFactionId
|
||||
|
||||
val demands = availableCommand.demands
|
||||
val selectedDemand = demands.find(_.demandingFactionId == demandingFid)
|
||||
|
||||
demandingFactionId: FactionId,
|
||||
tributeAmount: TributeAmount,
|
||||
paid: Boolean,
|
||||
availableDemandingFactionIds: Vector[FactionId],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableGold: Int,
|
||||
availableFood: Int,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
): ProtolessSimpleAction = {
|
||||
// Validate the demanding faction ID
|
||||
commandRequire(
|
||||
selectedDemand.nonEmpty,
|
||||
s"Selected faction ID $demandingFid was not among options ${demands.map(_.demandingFactionId).toList}"
|
||||
availableDemandingFactionIds.contains(demandingFactionId),
|
||||
s"Selected demanding faction ID $demandingFactionId was not among options $availableDemandingFactionIds"
|
||||
)
|
||||
|
||||
val demandingArmy = gameState
|
||||
.provinces(availableCommand.actingProvinceId)
|
||||
.hostileArmies
|
||||
.filter(_.status.asMessage.sealedValue.isTributeDemanded)
|
||||
.find(_.factionId == demandingFid)
|
||||
.get
|
||||
|
||||
val tributeDemanded = selectedDemand.get match {
|
||||
case TributeAndFaction(
|
||||
_,
|
||||
tributeDemanded,
|
||||
_,
|
||||
_,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
tributeDemanded
|
||||
// Validate that we have enough resources if paying
|
||||
if paid then {
|
||||
commandRequire(
|
||||
availableGold >= tributeAmount.gold,
|
||||
s"Not enough gold to pay tribute: have $availableGold, need ${tributeAmount.gold}"
|
||||
)
|
||||
commandRequire(
|
||||
availableFood >= tributeAmount.food,
|
||||
s"Not enough food to pay tribute: have $availableFood, need ${tributeAmount.food}"
|
||||
)
|
||||
}
|
||||
|
||||
if selectedCommand.paid then {
|
||||
commandRequire(
|
||||
availableCommand.availableFood >= tributeDemanded.get.food,
|
||||
s"Trying to pay ${tributeDemanded.get.food} food, but only ${availableCommand.availableFood} available"
|
||||
)
|
||||
commandRequire(
|
||||
availableCommand.availableGold >= tributeDemanded.get.gold,
|
||||
s"Trying to pay ${tributeDemanded.get.gold} gold, but only ${availableCommand.availableGold} available"
|
||||
)
|
||||
ResolveTributeCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = paid,
|
||||
actingProvinceId = actingProvinceId,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
}
|
||||
|
||||
PayTributeCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
pid = availableCommand.actingProvinceId,
|
||||
demandingArmy = demandingArmy,
|
||||
payingFid = actingFactionId
|
||||
private case class ResolveTributeCommand(
|
||||
actingFactionId: FactionId,
|
||||
demandingFactionId: FactionId,
|
||||
tributeAmount: TributeAmount,
|
||||
paid: Boolean,
|
||||
actingProvinceId: ProvinceId,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
if paid then {
|
||||
payTribute()
|
||||
} else {
|
||||
rejectTribute()
|
||||
}
|
||||
}
|
||||
|
||||
private def payTribute(): ActionResultT = {
|
||||
// Create a truce that lasts for 12 months
|
||||
val truceEndDate = currentDate.addMonths(12)
|
||||
|
||||
ActionResultC(
|
||||
actionResultType = TributePaidResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = actingProvinceId,
|
||||
goldDelta = Some(-tributeAmount.gold),
|
||||
foodDelta = Some(-tributeAmount.food),
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyStatusChange(
|
||||
factionId = demandingFactionId,
|
||||
newStatus = TributePaid(tributeAmount)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
changedFactions = Vector(
|
||||
// Update the paying faction's relationship with the demanding faction
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
changedFactionRelationships = Vector(
|
||||
FactionRelationship(
|
||||
targetFactionId = demandingFactionId,
|
||||
relationshipLevel = RelationshipLevel.Truce,
|
||||
resetDate = Some(truceEndDate)
|
||||
)
|
||||
)
|
||||
),
|
||||
// Update the demanding faction's relationship with the paying faction
|
||||
ChangedFactionC(
|
||||
factionId = demandingFactionId,
|
||||
changedFactionRelationships = Vector(
|
||||
FactionRelationship(
|
||||
targetFactionId = actingFactionId,
|
||||
relationshipLevel = RelationshipLevel.Truce,
|
||||
resetDate = Some(truceEndDate)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
} else
|
||||
RejectDemandCommand(
|
||||
sc = selectedCommand,
|
||||
gs = gameState,
|
||||
pid = availableCommand.actingProvinceId,
|
||||
demandingArmy = demandingArmy,
|
||||
rejectingFid = actingFactionId
|
||||
}
|
||||
|
||||
private def rejectTribute(): ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = TributeRefusedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = actingProvinceId,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyStatusChange(
|
||||
factionId = demandingFactionId,
|
||||
newStatus = Attacking
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end if
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+108
-113
@@ -1,134 +1,129 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.ResolveTruceOfferAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveTruceOfferSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
Notification,
|
||||
TruceAcceptedDetails,
|
||||
TruceAmbassadorImprisonedDetails,
|
||||
TruceRejectedDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.common.diplomacy_offer.DiplomacyOffer
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNKNOWN,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
Unrecognized
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.diplomacy_llm_helpers.DiplomacyResolutionLlmRequestGenerator
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.TruceResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Accepted,
|
||||
Imprisoned,
|
||||
Rejected,
|
||||
Status
|
||||
}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.TruceOffer
|
||||
import net.eagle0.eagle.library.{EagleCommandException, EagleInternalException}
|
||||
import net.eagle0.eagle.{GameId, RoundId}
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object ResolveTruceOfferCommand {
|
||||
private case class ResolveTruceOfferCommand(
|
||||
sc: ResolveTruceOfferSelectedCommand,
|
||||
truceOffer: DiplomacyOffer,
|
||||
resolution: DiplomacyOfferStatus,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult = {
|
||||
val newLlmRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator.truceResolutionRequest(
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
originatingFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = truceOffer.targetFactionId,
|
||||
messengerHeroId = truceOffer.messengerHeroId,
|
||||
resolution = resolution
|
||||
)
|
||||
|
||||
ActionResult(
|
||||
`type` = ActionResultType.OFFER_RESOLVED,
|
||||
player = Some(truceOffer.targetFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = truceOffer.targetFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(truceOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(truceOffer.withStatus(resolution))
|
||||
)
|
||||
),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = resolution match {
|
||||
case DIPLOMACY_OFFER_STATUS_ACCEPTED =>
|
||||
TruceAcceptedDetails(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = truceOffer.targetFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_REJECTED =>
|
||||
TruceRejectedDetails(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = truceOffer.targetFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_IMPRISONED =>
|
||||
TruceAmbassadorImprisonedDetails(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = truceOffer.targetFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_INVALIDATED =>
|
||||
throw new EagleCommandException(
|
||||
"Invalid diplomacy offers status for command"
|
||||
)
|
||||
|
||||
case DIPLOMACY_OFFER_STATUS_UNKNOWN |
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED | Unrecognized(_) =>
|
||||
throw new EagleInternalException(
|
||||
s"Unknown diplomacy offer status"
|
||||
)
|
||||
},
|
||||
llm = Llm.LlmId(newLlmRequest.id)
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(newLlmRequest)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def make(
|
||||
availableCommand: ResolveTruceOfferAvailableCommand,
|
||||
selectedCommand: ResolveTruceOfferSelectedCommand,
|
||||
actingFactionId: FactionId,
|
||||
originatingFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
messengerOriginProvinceId: ProvinceId,
|
||||
truceOffer: TruceOffer,
|
||||
resolution: Status,
|
||||
availableOriginatingFactionIds: Vector[FactionId],
|
||||
availableResolutions: Vector[Status],
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
): SimpleAction = {
|
||||
// check requirements
|
||||
val offeringFid = selectedCommand.originatingFactionId
|
||||
val offers = availableCommand.offers
|
||||
val selectedOffer = offers.find(_.originatingFactionId == offeringFid)
|
||||
|
||||
): ProtolessSimpleAction = {
|
||||
// Validation
|
||||
commandRequire(
|
||||
selectedOffer.nonEmpty,
|
||||
s"Selected faction ID $offeringFid was not among options ${offers.map(_.originatingFactionId)}"
|
||||
availableOriginatingFactionIds.contains(originatingFactionId),
|
||||
s"Selected faction ID $originatingFactionId was not among options $availableOriginatingFactionIds"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
selectedOffer.get.eligibleStatuses.contains(selectedCommand.resolution),
|
||||
s"Selected truce resolution ${selectedCommand.resolution} was not among options ${selectedOffer.get.eligibleStatuses}"
|
||||
availableResolutions.contains(resolution),
|
||||
s"Selected truce resolution $resolution was not among options $availableResolutions"
|
||||
)
|
||||
|
||||
ResolveTruceOfferCommand(
|
||||
sc = selectedCommand,
|
||||
truceOffer = selectedOffer.get,
|
||||
resolution = selectedCommand.resolution,
|
||||
actingFactionId = actingFactionId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ResolveTruceOfferCommand(
|
||||
actingFactionId: FactionId,
|
||||
truceOffer: TruceOffer,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"${currentRoundId} resolve truce ${truceOffer.messengerHeroId}"
|
||||
|
||||
ActionResultC(
|
||||
actionResultType = OfferResolvedResultType,
|
||||
actingFactionId = Some(actingFactionId),
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(truceOffer.originatingFactionId),
|
||||
newIncomingDiplomacyOffers =
|
||||
Vector(truceOffer.copy(status = resolution))
|
||||
)
|
||||
),
|
||||
newNotifications = Vector(
|
||||
NotificationC(
|
||||
details = resolution match {
|
||||
case Accepted =>
|
||||
NotificationDetails.TruceAccepted(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case Rejected =>
|
||||
NotificationDetails.TruceRejected(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case Imprisoned =>
|
||||
NotificationDetails.TruceAmbassadorImprisoned(
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = truceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case _ =>
|
||||
throw new EagleCommandException(
|
||||
s"Invalid diplomacy offer status for command: $resolution"
|
||||
)
|
||||
},
|
||||
affectedProvinceIds = Vector(),
|
||||
affectedHeroIds = Vector(truceOffer.messengerHeroId),
|
||||
llm = NotificationT.Llm.Id(llmRequestId),
|
||||
deferred = true
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(
|
||||
TruceResolutionMessage(
|
||||
requestId = llmRequestId,
|
||||
eagleGameId = gameId,
|
||||
offeringFactionId = truceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = truceOffer.messengerHeroId,
|
||||
resolution = resolution
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
-84
@@ -1,119 +1,121 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.SendSuppliesAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SendSuppliesSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.SENT_SUPPLIES
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.supplies.{MovingSupplies, Supplies}
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.SentSuppliesResultType
|
||||
import net.eagle0.eagle.model.state.{MovingSupplies, Supplies}
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
SendSuppliesWisdomXp,
|
||||
ShipSuppliesLoss,
|
||||
TurnsToResolveShipment
|
||||
}
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object SendSuppliesCommand
|
||||
extends CommandBuilder[
|
||||
SendSuppliesAvailableCommand,
|
||||
SendSuppliesSelectedCommand
|
||||
] {
|
||||
object SendSuppliesCommand {
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
originProvinceId: ProvinceId,
|
||||
destinationProvinceId: ProvinceId,
|
||||
availableDestinationProvinceIds: Vector[ProvinceId],
|
||||
availableHeroIds: Vector[HeroId],
|
||||
goldAvailable: Int,
|
||||
foodAvailable: Int,
|
||||
goldSent: Int,
|
||||
foodSent: Int,
|
||||
currentRoundId: RoundId
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
foodSent >= 0,
|
||||
"Food amount cannot be negative"
|
||||
)
|
||||
commandRequire(
|
||||
foodSent <= foodAvailable,
|
||||
s"Food amount $foodSent greater than available $foodAvailable"
|
||||
)
|
||||
commandRequire(
|
||||
goldSent >= 0,
|
||||
"Gold amount cannot be negative"
|
||||
)
|
||||
commandRequire(
|
||||
goldSent <= goldAvailable,
|
||||
s"Gold amount $goldSent greater than available $goldAvailable"
|
||||
)
|
||||
commandRequire(
|
||||
availableHeroIds.contains(actingHeroId),
|
||||
s"Available heroes $availableHeroIds did not include $actingHeroId"
|
||||
)
|
||||
commandRequire(
|
||||
availableDestinationProvinceIds.contains(destinationProvinceId),
|
||||
s"Available destination provinces $availableDestinationProvinceIds did not include $destinationProvinceId"
|
||||
)
|
||||
|
||||
SendSuppliesCommand(
|
||||
factionId = actingFactionId,
|
||||
actor = actingHeroId,
|
||||
originProvince = originProvinceId,
|
||||
destinationProvince = destinationProvinceId,
|
||||
gold = goldSent,
|
||||
food = foodSent,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class SendSuppliesCommand(
|
||||
sc: SendSuppliesSelectedCommand,
|
||||
gameState: GameState,
|
||||
factionId: FactionId,
|
||||
actor: HeroId,
|
||||
originProvince: ProvinceId,
|
||||
destinationProvince: ProvinceId,
|
||||
gold: Int,
|
||||
food: Int
|
||||
) extends DeterministicSingleResultCommand(gameState, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = SENT_SUPPLIES,
|
||||
player = Some(factionId),
|
||||
leader = Some(actor),
|
||||
province = Some(originProvince),
|
||||
provinceActed = Some(originProvince),
|
||||
food: Int,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = SentSuppliesResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(actor),
|
||||
provinceId = Some(originProvince),
|
||||
provinceIdActed = Some(originProvince),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = originProvince,
|
||||
ChangedProvinceC(
|
||||
provinceId = originProvince,
|
||||
goldDelta = Some(-gold),
|
||||
foodDelta = Some(-food)
|
||||
),
|
||||
ChangedProvince(
|
||||
id = destinationProvince,
|
||||
addedIncomingShipments = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = destinationProvince,
|
||||
newIncomingShipments = Vector(
|
||||
MovingSupplies(
|
||||
factionId = factionId,
|
||||
originProvinceId = Some(originProvince),
|
||||
id = 0, // ID will be assigned by ActionResultProtoApplierImpl
|
||||
supplies = Supplies(gold = gold, food = food),
|
||||
arrivalRound = currentRoundId + TurnsToResolveShipment.intValue,
|
||||
destinationProvinceId = destinationProvince,
|
||||
arrivalRound =
|
||||
gameState.currentRoundId + TurnsToResolveShipment.intValue,
|
||||
supplies = Some(Supplies(gold = gold, food = food)),
|
||||
originProvinceId = Some(originProvince),
|
||||
factionId = factionId,
|
||||
suppliesLoss = ShipSuppliesLoss.doubleValue
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
changedHeroes = Vector(
|
||||
ChangedHero(
|
||||
id = actor,
|
||||
vigor = Vigor.VigorDelta(-ActionVigorCost.intValue),
|
||||
ChangedHeroC(
|
||||
heroId = actor,
|
||||
vigorChange = StatDelta(-ActionVigorCost.intValue.toDouble),
|
||||
wisdomXpDelta = Some(SendSuppliesWisdomXp.intValue)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: SendSuppliesAvailableCommand,
|
||||
selectedCommand: SendSuppliesSelectedCommand
|
||||
): DeterministicSingleResultCommand = {
|
||||
commandRequire(
|
||||
selectedCommand.food >= 0,
|
||||
"Food amount cannot be negative"
|
||||
)
|
||||
commandRequire(
|
||||
selectedCommand.food <= availableCommand.foodAvailable,
|
||||
s"Food amount ${selectedCommand.food} greater than available ${availableCommand.foodAvailable}"
|
||||
)
|
||||
commandRequire(
|
||||
selectedCommand.gold >= 0,
|
||||
"Gold amount cannot be negative"
|
||||
)
|
||||
commandRequire(
|
||||
selectedCommand.gold <= availableCommand.goldAvailable,
|
||||
s"Gold amount ${selectedCommand.gold} greater than available ${availableCommand.goldAvailable}"
|
||||
)
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds.contains(selectedCommand.actingHeroId),
|
||||
s"Available heroes ${availableCommand.availableHeroIds} did not include ${selectedCommand.actingHeroId}"
|
||||
)
|
||||
|
||||
val destinationProvinceId = selectedCommand.destinationProvinceId
|
||||
commandRequire(
|
||||
availableCommand.availableDestinationProvinceIds
|
||||
.contains(destinationProvinceId),
|
||||
s"Available destination provinces ${availableCommand.availableDestinationProvinceIds} did not include $destinationProvinceId"
|
||||
)
|
||||
SendSuppliesCommand(
|
||||
sc = selectedCommand,
|
||||
gameState = gameState,
|
||||
factionId = actingFactionId,
|
||||
actor = selectedCommand.actingHeroId,
|
||||
originProvince = availableCommand.actingProvinceId,
|
||||
destinationProvince = destinationProvinceId,
|
||||
gold = selectedCommand.gold,
|
||||
food = selectedCommand.food
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+57
-66
@@ -1,14 +1,15 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.StartEpidemicAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.StartEpidemicSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.EPIDEMIC_STARTED
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.deferred_change.EpidemicStarted
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.EpidemicStartedResultType
|
||||
import net.eagle0.eagle.model.state.province.DeferredChange
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
StartEpidemicCharismaXp,
|
||||
StartEpidemicVigorDelta
|
||||
@@ -16,73 +17,63 @@ import net.eagle0.eagle.library.settings.{
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
|
||||
object StartEpidemicCommand
|
||||
extends CommandBuilder[
|
||||
StartEpidemicAvailableCommand,
|
||||
StartEpidemicSelectedCommand
|
||||
] {
|
||||
object StartEpidemicCommand {
|
||||
|
||||
private case class StartEpidemicCommand(
|
||||
sc: StartEpidemicSelectedCommand,
|
||||
gameState: GameState,
|
||||
factionId: FactionId,
|
||||
actingProvinceId: ProvinceId,
|
||||
actingHeroId: HeroId,
|
||||
targetProvinceId: ProvinceId
|
||||
) extends DeterministicSingleResultCommand(gameState, sc) {
|
||||
private def changedTargetedProvince: ChangedProvince = {
|
||||
ChangedProvince(
|
||||
id = targetProvinceId,
|
||||
addedDeferredChange = EpidemicStarted(responsibleFaction = factionId)
|
||||
)
|
||||
}
|
||||
|
||||
private def changedHero: ChangedHero =
|
||||
ChangedHero(
|
||||
id = actingHeroId,
|
||||
vigor = VigorDelta(StartEpidemicVigorDelta.doubleValue),
|
||||
charismaXpDelta = Some(StartEpidemicCharismaXp.intValue)
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = EPIDEMIC_STARTED,
|
||||
player = Some(factionId),
|
||||
leader = Some(actingHeroId),
|
||||
province = Some(actingProvinceId),
|
||||
provinceActed = Some(actingProvinceId),
|
||||
changedProvinces = Vector(changedTargetedProvince),
|
||||
changedHeroes = Vector(changedHero)
|
||||
)
|
||||
}
|
||||
|
||||
override def make(
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: StartEpidemicAvailableCommand,
|
||||
selectedCommand: StartEpidemicSelectedCommand
|
||||
): DeterministicSingleResultCommand = {
|
||||
val leader = selectedCommand.actingHeroId
|
||||
actingHeroId: HeroId,
|
||||
actingProvinceId: ProvinceId,
|
||||
targetProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId],
|
||||
availableTargetProvinceIds: Vector[ProvinceId]
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds.contains(leader),
|
||||
s"Must select hero from ${availableCommand.availableHeroIds} but chose $leader"
|
||||
availableHeroIds.contains(actingHeroId),
|
||||
s"Must select hero from $availableHeroIds but chose $actingHeroId"
|
||||
)
|
||||
|
||||
val pid = selectedCommand.selectedProvinceId
|
||||
commandRequire(
|
||||
availableCommand.options
|
||||
.exists(_.targetProvinceId == pid),
|
||||
s"Selected pid $pid was not among ${availableCommand.options
|
||||
.map(_.targetProvinceId)}"
|
||||
availableTargetProvinceIds.contains(targetProvinceId),
|
||||
s"Selected pid $targetProvinceId was not among $availableTargetProvinceIds"
|
||||
)
|
||||
|
||||
StartEpidemicCommand(
|
||||
sc = selectedCommand,
|
||||
gameState = gameState,
|
||||
factionId = actingFactionId,
|
||||
actingProvinceId = availableCommand.actingProvinceId,
|
||||
actingHeroId = selectedCommand.actingHeroId,
|
||||
targetProvinceId = selectedCommand.selectedProvinceId
|
||||
actingHeroId = actingHeroId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
targetProvinceId = targetProvinceId
|
||||
)
|
||||
}
|
||||
|
||||
private case class StartEpidemicCommand(
|
||||
factionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingProvinceId: ProvinceId,
|
||||
targetProvinceId: ProvinceId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = EpidemicStartedResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(actingHeroId),
|
||||
provinceId = Some(actingProvinceId),
|
||||
provinceIdActed = Some(actingProvinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = targetProvinceId,
|
||||
newDeferredChange = Some(
|
||||
DeferredChange.EpidemicStarted(responsibleFaction = factionId)
|
||||
)
|
||||
)
|
||||
),
|
||||
changedHeroes = Vector(
|
||||
ChangedHeroC(
|
||||
heroId = actingHeroId,
|
||||
vigorChange = StatDelta(StartEpidemicVigorDelta.doubleValue),
|
||||
charismaXpDelta = Some(StartEpidemicCharismaXp.intValue)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -20,7 +20,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
NotificationC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
SuppressBeastsFailedMessage,
|
||||
SuppressBeastsSucceededMessage
|
||||
}
|
||||
@@ -192,9 +193,7 @@ object SuppressBeastsCommand {
|
||||
battalionTypeId = optionalBattalion.map(_.id),
|
||||
beastTypeId = 1, // TODO: beastInfo.id
|
||||
beastCount = beastCount,
|
||||
provinceId = province.id,
|
||||
recipientFactionIds =
|
||||
Vector() // all factions learn about failed suppressions
|
||||
provinceId = province.id
|
||||
)
|
||||
val notification = NotificationC(
|
||||
details = NotificationDetails.SuppressBeastsFailed(
|
||||
@@ -214,6 +213,7 @@ object SuppressBeastsCommand {
|
||||
requestId =
|
||||
s"suppressed beasts $currentRoundId $factionId ${hero.id}",
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(factionId),
|
||||
heroId = hero.id,
|
||||
factionId = factionId,
|
||||
battalionTypeId = optionalBattalion.map(_.id),
|
||||
@@ -222,8 +222,7 @@ object SuppressBeastsCommand {
|
||||
provinceId = province.id,
|
||||
casualtyCount = casualties,
|
||||
goldGained = goldDelta.getOrElse(0),
|
||||
foodGained = foodDelta.getOrElse(0),
|
||||
recipientFactionIds = Vector(factionId)
|
||||
foodGained = foodDelta.getOrElse(0)
|
||||
)
|
||||
val notification = NotificationC(
|
||||
details = NotificationDetails.SuppressedBeasts(
|
||||
|
||||
+88
-99
@@ -1,45 +1,32 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.SwearBrotherhoodAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SwearBrotherhoodSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
Notification,
|
||||
SwearBrotherhoodDetails
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.{
|
||||
FAILED_SWEAR_BROTHERHOOD,
|
||||
SWEAR_BROTHERHOOD
|
||||
}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.event_for_hero_backstory.{
|
||||
EventForHeroBackstory,
|
||||
SworeBrotherhoodBackstoryEvent
|
||||
}
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.generated_text_request.{
|
||||
GeneratedTextRequest,
|
||||
SwearBrotherhoodMessage
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.SwearBrotherhoodMessage
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
FailedSwearBrotherhoodResultType,
|
||||
SwearBrotherhoodResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
AcceptBrotherhoodCharismaXp,
|
||||
SwearBrotherhoodCharismaXp
|
||||
}
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.library.util.faction_utils.LegacyFactionUtils
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.model.state.hero.SworeBrotherhoodBackstoryEvent
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
|
||||
object SwearBrotherhoodCommand
|
||||
extends CommandBuilder[
|
||||
SwearBrotherhoodAvailableCommand,
|
||||
SwearBrotherhoodSelectedCommand
|
||||
] {
|
||||
object SwearBrotherhoodCommand {
|
||||
def accepts(
|
||||
heroId: HeroId,
|
||||
factionId: FactionId,
|
||||
gameState: GameState
|
||||
factionId: FactionId
|
||||
): Boolean = {
|
||||
true /*
|
||||
val vassal = gameState.heroes(heroId)
|
||||
@@ -51,101 +38,103 @@ object SwearBrotherhoodCommand
|
||||
) > ThresholdForSwearBrotherhood.doubleValue*/
|
||||
}
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
actingProvinceId: ProvinceId,
|
||||
newBrotherHeroId: HeroId,
|
||||
availableHeroIds: Vector[HeroId],
|
||||
factionHeadHeroId: HeroId,
|
||||
currentDate: Date,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
availableHeroIds.contains(newBrotherHeroId),
|
||||
s"Tried to swear brotherhood with $newBrotherHeroId, but options were $availableHeroIds"
|
||||
)
|
||||
|
||||
SwearBrotherhoodCommand(
|
||||
factionId = actingFactionId,
|
||||
provinceId = actingProvinceId,
|
||||
newBrotherId = newBrotherHeroId,
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
private case class SwearBrotherhoodCommand(
|
||||
sc: SwearBrotherhoodSelectedCommand,
|
||||
gameState: GameState,
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId,
|
||||
newBrotherId: HeroId
|
||||
) extends DeterministicSingleResultCommand(gameState, sc) {
|
||||
override def immediateExecute: ActionResult =
|
||||
if accepts(newBrotherId, factionId, gameState) then {
|
||||
newBrotherId: HeroId,
|
||||
factionHeadHeroId: HeroId,
|
||||
currentDate: Date,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
if accepts(newBrotherId, factionId) then {
|
||||
val notificationLlmId =
|
||||
s"${gameState.currentRoundId} $factionId swear brotherhood $newBrotherId"
|
||||
s"${currentRoundId} swear brotherhood ${newBrotherId}"
|
||||
|
||||
val swornBrotherBackstoryEvent = EventForHeroBackstory(
|
||||
date = gameState.currentDate,
|
||||
details = SworeBrotherhoodBackstoryEvent(
|
||||
sworeWithFactionId = factionId,
|
||||
sworeInProvinceId = provinceId
|
||||
)
|
||||
val swornBrotherBackstoryEvent = SworeBrotherhoodBackstoryEvent(
|
||||
date = currentDate,
|
||||
sworeWithFactionId = factionId,
|
||||
sworeInProvinceId = provinceId
|
||||
)
|
||||
|
||||
ActionResult(
|
||||
`type` = SWEAR_BROTHERHOOD,
|
||||
player = Some(factionId),
|
||||
province = Some(provinceId),
|
||||
provinceActed = Some(provinceId),
|
||||
leader = Some(newBrotherId),
|
||||
ActionResultC(
|
||||
actionResultType = SwearBrotherhoodResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(newBrotherId),
|
||||
provinceId = Some(provinceId),
|
||||
provinceIdActed = Some(provinceId),
|
||||
changedHeroes = Vector(
|
||||
ChangedHero(
|
||||
id = LegacyFactionUtils.factionHead(factionId, gameState).get.id,
|
||||
ChangedHeroC(
|
||||
heroId = factionHeadHeroId,
|
||||
charismaXpDelta = Some(SwearBrotherhoodCharismaXp.intValue)
|
||||
),
|
||||
ChangedHero(
|
||||
id = newBrotherId,
|
||||
ChangedHeroC(
|
||||
heroId = newBrotherId,
|
||||
charismaXpDelta = Some(AcceptBrotherhoodCharismaXp.intValue),
|
||||
newBackstoryEvents = Vector(swornBrotherBackstoryEvent)
|
||||
newEventsForHeroBackstory = Vector(swornBrotherBackstoryEvent)
|
||||
)
|
||||
),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = factionId,
|
||||
addedLeaders = Vector(newBrotherId)
|
||||
ChangedFactionC(
|
||||
factionId = factionId,
|
||||
newLeaderHeroIds = Vector(newBrotherId)
|
||||
)
|
||||
),
|
||||
newDeferredNotification = Some(
|
||||
Notification(
|
||||
details = SwearBrotherhoodDetails(
|
||||
newNotifications = Vector(
|
||||
NotificationC(
|
||||
details = NotificationDetails.SwearBrotherhood(
|
||||
factionId = factionId,
|
||||
newBrotherHeroId = newBrotherId
|
||||
),
|
||||
llm = Llm.LlmId(notificationLlmId)
|
||||
affectedProvinceIds = Vector(provinceId),
|
||||
affectedHeroIds = Vector(newBrotherId, factionHeadHeroId),
|
||||
llm = NotificationT.Llm.Id(notificationLlmId),
|
||||
deferred = true
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(
|
||||
GeneratedTextRequest(
|
||||
id = notificationLlmId,
|
||||
eagleGameId = gameState.gameId,
|
||||
details = SwearBrotherhoodMessage(
|
||||
factionId = factionId,
|
||||
swornBrotherHeroId = newBrotherId
|
||||
)
|
||||
SwearBrotherhoodMessage(
|
||||
requestId = notificationLlmId,
|
||||
eagleGameId = gameId,
|
||||
factionId = factionId,
|
||||
swornBrotherHeroId = newBrotherId
|
||||
)
|
||||
)
|
||||
)
|
||||
} else
|
||||
ActionResult(
|
||||
`type` = FAILED_SWEAR_BROTHERHOOD,
|
||||
player = Some(factionId),
|
||||
province = Some(provinceId),
|
||||
provinceActed = Some(provinceId),
|
||||
leader = Some(newBrotherId)
|
||||
ActionResultC(
|
||||
actionResultType = FailedSwearBrotherhoodResultType,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(newBrotherId),
|
||||
provinceId = Some(provinceId),
|
||||
provinceIdActed = Some(provinceId)
|
||||
)
|
||||
}
|
||||
|
||||
override def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: SwearBrotherhoodAvailableCommand,
|
||||
selectedCommand: SwearBrotherhoodSelectedCommand
|
||||
): DeterministicSingleResultCommand = {
|
||||
val selectedBrotherId = selectedCommand.newBrotherHeroId
|
||||
|
||||
commandRequire(
|
||||
availableCommand.availableHeroes
|
||||
.map(_.heroId)
|
||||
.contains(selectedBrotherId),
|
||||
s"Tried to swear brotherhood with $selectedBrotherId, but options were ${availableCommand.availableHeroes
|
||||
.map(_.heroId)}"
|
||||
)
|
||||
|
||||
SwearBrotherhoodCommand(
|
||||
sc = selectedCommand,
|
||||
gameState = gameState,
|
||||
factionId = actingFactionId,
|
||||
provinceId = availableCommand.actingProvinceId,
|
||||
newBrotherId = selectedBrotherId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
@@ -11,7 +11,6 @@ import net.eagle0.eagle.library.settings.{
|
||||
TrainStatDivisor,
|
||||
TrainStrengthXp
|
||||
}
|
||||
import net.eagle0.eagle.library.util.BattalionTypeFinder
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
@@ -59,7 +58,13 @@ object TrainCommand {
|
||||
battalionTypes: Vector[BattalionType]
|
||||
) extends ProtolessSimpleAction {
|
||||
private def battalionType(battalionTypeId: BattalionTypeId): BattalionType =
|
||||
BattalionTypeFinder.battalionType(battalionTypeId, battalionTypes)
|
||||
battalionTypes
|
||||
.find(_.typeId == battalionTypeId)
|
||||
.getOrElse(
|
||||
throw new IllegalArgumentException(
|
||||
s"No battalion type found for $battalionTypeId"
|
||||
)
|
||||
)
|
||||
|
||||
private val trainingMax = 100.0
|
||||
|
||||
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
# Protoless Command Conversion Analysis
|
||||
|
||||
This document identifies all commands in the `src/main/scala/net/eagle0/eagle/library/actions/impl/command/` directory that still use protobuf-based base classes and estimates the conversion effort from lowest to highest.
|
||||
|
||||
## Already Converted (Protoless ✅)
|
||||
|
||||
The following commands have already been converted to use `ProtolessRandomSimpleAction` or other protoless traits:
|
||||
|
||||
- **SuppressBeastsCommand.scala** - Recently converted
|
||||
- **RestCommand.scala** - **✅ CONVERTED** - Uses ProtolessSimpleAction (65 lines)
|
||||
- **ReturnCommand.scala** - **✅ NEWLY CONVERTED** - Uses ProtolessSimpleAction (40 lines)
|
||||
- **DivineCommand.scala** - Uses ProtolessRandomSimpleAction (220 lines)
|
||||
- **HandleRiotCrackDownCommand.scala** - Uses ProtolessRandomSimpleAction (192 lines)
|
||||
- **HandleRiotGiveCommand.scala** - Uses ProtolessRandomSimpleAction (156 lines)
|
||||
- **HandleCapturedHeroesCommand.scala** - Uses ProtolessRandomSimpleAction (411 lines)
|
||||
- **ManagePrisonersCommand.scala** - Already protoless (309 lines)
|
||||
|
||||
## Commands Requiring Conversion
|
||||
|
||||
Listed from **lowest to highest estimated effort**:
|
||||
|
||||
### 🟢 LOW EFFORT (1-2 hours each)
|
||||
|
||||
1. **ReconCommand.scala** (93 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: 7 `internal.*` imports including `IncomingRecon`
|
||||
- **Logic**: Creates incoming recon actions, hero XP updates
|
||||
- **Conversion**: Need to handle `IncomingEndTurnAction` conversion
|
||||
|
||||
2. **StartEpidemicCommand.scala** (88 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: Moderate protobuf usage
|
||||
- **Logic**: Disease/epidemic mechanics
|
||||
- **Conversion**: Disease model conversion required
|
||||
|
||||
3. **SendSuppliesCommand.scala** (119 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: 7+ `internal.*` imports including `MovingSupplies`
|
||||
- **Logic**: Supply transfer with `MovingSupplies` mechanics
|
||||
- **Conversion**: Need supply system model conversion
|
||||
|
||||
4. **SwearBrotherhoodCommand.scala** (151 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: Moderate protobuf usage
|
||||
- **Logic**: Hero relationship mechanics
|
||||
- **Conversion**: Relationship model updates needed
|
||||
|
||||
### 🟠 HIGH EFFORT (5-8 hours each)
|
||||
|
||||
5. **ResolveRansomOfferCommand.scala** (184 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: Heavy protobuf usage for diplomacy
|
||||
- **Logic**: Complex ransom resolution with multiple outcomes
|
||||
- **Conversion**: Diplomacy system models, prisoner mechanics
|
||||
|
||||
6. **MarchCommand.scala** (185 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: 7 `internal.*` imports including `MovingArmy`, `CombatUnit`
|
||||
- **Logic**: Complex army movement with combat unit validation
|
||||
- **Conversion**: Army and combat unit model conversion, movement mechanics
|
||||
|
||||
7. **ResolveTributeCommand.scala** (194 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand`
|
||||
- **Protobuf Dependencies**: Heavy diplomacy protobuf usage
|
||||
- **Logic**: Complex tribute resolution mechanics
|
||||
- **Conversion**: Diplomacy model conversion, resource transfers
|
||||
|
||||
### 🔴 VERY HIGH EFFORT (8+ hours each)
|
||||
|
||||
8. **ResolveInvitationCommand.scala** (238 lines)
|
||||
- **Base Class**: `DeterministicSingleResultCommand` (multiple subclasses)
|
||||
- **Protobuf Dependencies**: Extensive diplomacy protobuf usage
|
||||
- **Logic**: Complex invitation resolution with faction joining mechanics
|
||||
- **Conversion**: Major diplomacy model overhaul, faction management updates
|
||||
|
||||
## Summary
|
||||
|
||||
- **Total Commands to Convert**: 8 *(down from 9 - ReturnCommand now completed!)*
|
||||
- **Estimated Total Effort**: 32-53 hours *(reduced by ~2 hours)*
|
||||
- **Priority Order**: Start with ReconCommand for quick wins, then work up through complexity
|
||||
|
||||
### Recent Conversions
|
||||
|
||||
**RestCommand.scala** ✅ **COMPLETED**
|
||||
- **Effort**: ~2 hours actual time
|
||||
- **Changes Made**:
|
||||
- `DeterministicSingleResultCommand` → `ProtolessSimpleAction`
|
||||
- `ActionResult` → `ActionResultC`
|
||||
- `ChangedHero` → `ChangedHeroC`
|
||||
- `Vigor.VigorDelta()` → `StatDelta()`
|
||||
- Updated BUILD dependencies to use `rest_result_type`
|
||||
- Removed all protobuf dependencies
|
||||
- **Key Learnings**: Simple commands with basic business logic convert very quickly. The main effort is in understanding the correct target names for BUILD dependencies.
|
||||
|
||||
**ReturnCommand.scala** ✅ **COMPLETED**
|
||||
- **Effort**: ~2 hours actual time
|
||||
- **Changes Made**:
|
||||
- `DeterministicSingleResultCommand` → `ProtolessSimpleAction`
|
||||
- `ActionResult` → `ActionResultC`
|
||||
- `ChangedProvince` → `ChangedProvinceC`
|
||||
- Simplified interface: removed complex GameState/Command parameters, now takes `factionId`, `provinceId`, `rulerIsTraveling`
|
||||
- Updated CommandFactory caller to extract `rulerIsTraveling` from GameState
|
||||
- Updated BUILD dependencies and tests
|
||||
- **Key Learnings**: Province-based commands are straightforward. Parameter simplification makes the API much cleaner.
|
||||
|
||||
## Conversion Pattern
|
||||
|
||||
Based on the successful SuppressBeastsCommand conversion:
|
||||
|
||||
1. Change base class from `DeterministicSingleResultCommand` → `ProtolessSimpleAction`
|
||||
2. Replace protobuf imports with Scala model imports
|
||||
3. Update `ActionResult` → `ActionResultC`
|
||||
4. Replace protobuf changed objects with concrete Scala models (`ChangedHeroC`, `ChangedProvinceC`, etc.)
|
||||
5. Update BUILD dependencies
|
||||
6. Convert and restore comprehensive tests
|
||||
7. Run scalafmt for formatting
|
||||
|
||||
The main complexity factors are:
|
||||
- Number of protobuf dependencies
|
||||
- Complexity of business logic
|
||||
- Availability of equivalent Scala model classes
|
||||
- Test coverage requirements
|
||||
+5
-5
@@ -3,12 +3,12 @@ package net.eagle0.eagle.library.actions.generated_text_request_generators.captu
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
CapturedHeroExecutedMessage,
|
||||
CapturedHeroExiledMessage,
|
||||
CapturedHeroImprisonedMessage,
|
||||
HandleCapturedHeroPlea,
|
||||
LlmRequestT
|
||||
HandleCapturedHeroPlea
|
||||
}
|
||||
import net.eagle0.eagle.model.state.CapturedHero
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
@@ -37,13 +37,13 @@ object CapturedHeroPleaGenerator {
|
||||
requestId =
|
||||
s"$gameId $currentRoundId ${capturedHero.heroId} ${handled.countsString} 1",
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(capturingFactionId),
|
||||
actingFactionId = capturingFactionId,
|
||||
capturedHeroId = capturedHero.heroId,
|
||||
provinceId = provinceId,
|
||||
alreadyExecutedHeroIds = handled.executed,
|
||||
alreadyImprisonedHeroIds = handled.imprisoned,
|
||||
alreadyExiledHeroIds = handled.exiled,
|
||||
recipientFactionIds = Vector(capturingFactionId)
|
||||
alreadyExiledHeroIds = handled.exiled
|
||||
)
|
||||
|
||||
def withPleaForCapturedHero(
|
||||
|
||||
+2
-4
@@ -1,10 +1,8 @@
|
||||
package net.eagle0.eagle.library.actions.generated_text_request_generators.divine_llm_helpers
|
||||
|
||||
import net.eagle0.eagle.{GameId, HeroId, RoundId}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
DivineMessage,
|
||||
LlmRequestT
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.DivineMessage
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
|
||||
object DivineLlmRequestGenerator {
|
||||
|
||||
@@ -27,11 +27,11 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/util:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/common:json_utils",
|
||||
"//src/main/scala/net/eagle0/common/name_generation:string_construction_token_generator",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.eagle0.common.name_generation.{
|
||||
StringConstructionTokenGenerator
|
||||
}
|
||||
import net.eagle0.common.{FunctionalRandom, JsonUtils, RandomState}
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
@@ -56,6 +56,7 @@ class BattalionNameGenerator(
|
||||
private val lightCavalryToken = tokenFor("light_cavalry", "light_cavalry_adj")
|
||||
private val heavyCavalryToken = tokenFor("heavy_cavalry", "heavy_cavalry_adj")
|
||||
private val longbowmenToken = tokenFor("longbowmen", "longbowmen_adj")
|
||||
private val undeadToken = tokenFor("undead", "undead_adj")
|
||||
|
||||
def nextName(
|
||||
battalionTypeId: BattalionTypeId,
|
||||
@@ -63,11 +64,11 @@ class BattalionNameGenerator(
|
||||
random: FunctionalRandom
|
||||
): RandomState[String] =
|
||||
(battalionTypeId match {
|
||||
case BattalionTypeId.LIGHT_INFANTRY => lightInfantryToken
|
||||
case BattalionTypeId.HEAVY_INFANTRY => heavyInfantryToken
|
||||
case BattalionTypeId.LIGHT_CAVALRY => lightCavalryToken
|
||||
case BattalionTypeId.HEAVY_CAVALRY => heavyCavalryToken
|
||||
case BattalionTypeId.LONGBOWMEN => longbowmenToken
|
||||
case _ => ???
|
||||
case BattalionTypeId.LightInfantry => lightInfantryToken
|
||||
case BattalionTypeId.HeavyInfantry => heavyInfantryToken
|
||||
case BattalionTypeId.LightCavalry => lightCavalryToken
|
||||
case BattalionTypeId.HeavyCavalry => heavyCavalryToken
|
||||
case BattalionTypeId.Longbowmen => longbowmenToken
|
||||
case BattalionTypeId.Undead => undeadToken
|
||||
}).nextString(random, Map(placeNamePlaceholder -> provinceName))
|
||||
}
|
||||
|
||||
+7
-7
@@ -12,8 +12,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
LlmRequestT,
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
QuestFailedMessage,
|
||||
QuestFulfilledMessage
|
||||
}
|
||||
@@ -117,11 +117,11 @@ object QuestFulfillmentUtils {
|
||||
QuestFulfilledMessage(
|
||||
requestId = s"quest fulfilled ${uh.heroId} Quest($quest)",
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(province.getRulingFactionId),
|
||||
heroId = uh.heroId,
|
||||
provinceId = province.id,
|
||||
factionId = province.getRulingFactionId,
|
||||
quest = quest,
|
||||
recipientFactionIds = Vector(province.getRulingFactionId)
|
||||
quest = quest
|
||||
)
|
||||
}
|
||||
|
||||
@@ -250,15 +250,15 @@ object QuestFulfillmentUtils {
|
||||
QuestFailedMessage(
|
||||
requestId = s"quest failed ${uh.heroId} $quest",
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(province.getRulingFactionId),
|
||||
heroId = uh.heroId,
|
||||
provinceId = province.id,
|
||||
factionId = province.getRulingFactionId,
|
||||
quest = quest,
|
||||
recipientFactionIds = Vector(province.getRulingFactionId)
|
||||
quest = quest
|
||||
)
|
||||
}
|
||||
|
||||
def questFailedBackstoryEvent(
|
||||
private def questFailedBackstoryEvent(
|
||||
uh: UnaffiliatedHeroT,
|
||||
province: ProvinceT,
|
||||
currentDate: Date
|
||||
|
||||
+297
-292
@@ -8,6 +8,11 @@ import net.eagle0.eagle.model.state.hero.backstory_version.BackstoryVersion
|
||||
import net.eagle0.eagle.model.state.quest.QuestT
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, GameId, HeroId, ProvinceId}
|
||||
|
||||
case class ChronicleUpdatePreviousEntry(
|
||||
date: Date,
|
||||
generatedTextId: String
|
||||
)
|
||||
|
||||
sealed trait GeneratedTextRequestT {
|
||||
def requestId: String
|
||||
def eagleGameId: GameId
|
||||
@@ -34,316 +39,316 @@ case class GeneratedHeroName(
|
||||
override def alwaysGenerate: Boolean = true
|
||||
}
|
||||
|
||||
sealed trait LlmRequestT extends GeneratedTextRequestT
|
||||
case class AllianceOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
) extends LlmRequestT
|
||||
enum LlmRequestT extends GeneratedTextRequestT:
|
||||
def requestId: String
|
||||
def eagleGameId: GameId
|
||||
def recipientFactionIds: Vector[FactionId]
|
||||
def alwaysGenerate: Boolean
|
||||
|
||||
case class AllianceOfferResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
) extends LlmRequestT
|
||||
|
||||
case class BreakAllianceMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
breakingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
) extends LlmRequestT
|
||||
|
||||
case class BreakAllianceResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
breakingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
) extends LlmRequestT
|
||||
|
||||
case class CapturedHeroExecutedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
|
||||
case class CapturedHeroExiledMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
|
||||
case class CapturedHeroImprisonedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
|
||||
object ChronicleUpdateMessage {
|
||||
case class PreviousChronicleEntry(
|
||||
date: Date,
|
||||
generatedTextId: String
|
||||
case AllianceOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
)
|
||||
}
|
||||
case class ChronicleUpdateMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
current_date: Date,
|
||||
previous_entries: Vector[ChronicleUpdateMessage.PreviousChronicleEntry],
|
||||
new_entries: Vector[ChronicleEvent]
|
||||
) extends LlmRequestT
|
||||
|
||||
case class DivineMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
divinedHeroId: HeroId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
case AllianceOfferResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
|
||||
case class ExileVassalMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
exiledHeroId: HeroId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId,
|
||||
requestingHeroIds: Vector[HeroId]
|
||||
) extends LlmRequestT
|
||||
case BreakAllianceMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
breakingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
)
|
||||
|
||||
case class HandleCapturedHeroPlea(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
actingFactionId: FactionId,
|
||||
capturedHeroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
alreadyExecutedHeroIds: Vector[HeroId],
|
||||
alreadyImprisonedHeroIds: Vector[HeroId],
|
||||
alreadyExiledHeroIds: Vector[HeroId]
|
||||
) extends LlmRequestT
|
||||
case BreakAllianceResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
breakingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
|
||||
case class HeroBackstoryUpdateRequest(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
previousBackstoryVersions: Vector[BackstoryVersion],
|
||||
events: Vector[EventForHeroBackstoryT]
|
||||
) extends LlmRequestT
|
||||
case CapturedHeroExecutedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class HeroDepartureMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
departingHeroId: HeroId,
|
||||
fromFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
case CapturedHeroExiledMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class HeroInitialBackstoryRequest(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: Option[FactionId],
|
||||
personalityWords: Vector[String]
|
||||
) extends LlmRequestT
|
||||
case CapturedHeroImprisonedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class InvitationMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
invitingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
) extends LlmRequestT
|
||||
case ChronicleUpdateMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
current_date: Date,
|
||||
previous_entries: Vector[ChronicleUpdatePreviousEntry],
|
||||
new_entries: Vector[ChronicleEvent]
|
||||
)
|
||||
|
||||
case class InvitationResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
invitingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
) extends LlmRequestT
|
||||
case DivineMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
divinedHeroId: HeroId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class PleaseRecruitMeMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
targetFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
case ExileVassalMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
exiledHeroId: HeroId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId,
|
||||
requestingHeroIds: Vector[HeroId]
|
||||
)
|
||||
|
||||
case class QuestFailedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
factionId: FactionId,
|
||||
quest: QuestT
|
||||
) extends LlmRequestT
|
||||
case HandleCapturedHeroPlea(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId],
|
||||
alwaysGenerate: Boolean = false,
|
||||
actingFactionId: FactionId,
|
||||
capturedHeroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
alreadyExecutedHeroIds: Vector[HeroId],
|
||||
alreadyImprisonedHeroIds: Vector[HeroId],
|
||||
alreadyExiledHeroIds: Vector[HeroId]
|
||||
)
|
||||
|
||||
case class QuestFulfilledMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
factionId: FactionId,
|
||||
quest: QuestT
|
||||
) extends LlmRequestT
|
||||
case HeroBackstoryUpdateRequest(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
previousBackstoryVersions: Vector[BackstoryVersion],
|
||||
events: Vector[EventForHeroBackstoryT]
|
||||
)
|
||||
|
||||
case class RansomOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
offeringHeroId: HeroId,
|
||||
ransomedHeroId: HeroId,
|
||||
goldOffered: Int,
|
||||
hostageHeroIdsOffered: Vector[HeroId],
|
||||
prisonerHeroIdsOffered: Vector[HeroId]
|
||||
) extends LlmRequestT
|
||||
case HeroDepartureMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
departingHeroId: HeroId,
|
||||
fromFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class RansomResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
offeringHeroId: HeroId,
|
||||
ransomedHeroId: HeroId,
|
||||
resolution: Status
|
||||
) extends LlmRequestT
|
||||
case HeroInitialBackstoryRequest(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: Option[FactionId],
|
||||
personalityWords: Vector[String]
|
||||
)
|
||||
|
||||
case class RecruitmentRefusedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId,
|
||||
alreadyExecutedHeroIds: Vector[HeroId],
|
||||
alreadyImprisonedHeroIds: Vector[HeroId],
|
||||
alreadyExiledHeroIds: Vector[HeroId]
|
||||
) extends LlmRequestT
|
||||
case InvitationMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
invitingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
)
|
||||
|
||||
case class SuppressBeastsFailedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: FactionId,
|
||||
battalionTypeId: Option[BattalionId],
|
||||
beastTypeId: Int,
|
||||
beastCount: Int,
|
||||
provinceId: ProvinceId
|
||||
) extends LlmRequestT
|
||||
case InvitationResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
invitingFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
|
||||
case class SuppressBeastsSucceededMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: FactionId,
|
||||
battalionTypeId: Option[BattalionId],
|
||||
beastTypeId: Int,
|
||||
beastCount: Int,
|
||||
provinceId: ProvinceId,
|
||||
casualtyCount: Int,
|
||||
foodGained: Int,
|
||||
goldGained: Int
|
||||
) extends LlmRequestT
|
||||
case PleaseRecruitMeMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
targetFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case class SwearBrotherhoodMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
factionId: FactionId,
|
||||
swornBrotherHeroId: HeroId
|
||||
) extends LlmRequestT
|
||||
case QuestFailedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId],
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
factionId: FactionId,
|
||||
quest: QuestT
|
||||
)
|
||||
|
||||
case class TruceOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
) extends LlmRequestT
|
||||
case QuestFulfilledMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId],
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
provinceId: ProvinceId,
|
||||
factionId: FactionId,
|
||||
quest: QuestT
|
||||
)
|
||||
|
||||
case class TruceResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
) extends LlmRequestT
|
||||
case RansomOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
offeringHeroId: HeroId,
|
||||
ransomedHeroId: HeroId,
|
||||
goldOffered: Int,
|
||||
hostageHeroIdsOffered: Vector[HeroId],
|
||||
prisonerHeroIdsOffered: Vector[HeroId]
|
||||
)
|
||||
|
||||
case RansomResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
offeringHeroId: HeroId,
|
||||
ransomedHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
|
||||
case RecruitmentRefusedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
capturedHeroId: HeroId,
|
||||
capturedHeroFactionId: FactionId,
|
||||
actingHeroId: HeroId,
|
||||
actingFactionId: FactionId,
|
||||
provinceId: ProvinceId,
|
||||
alreadyExecutedHeroIds: Vector[HeroId],
|
||||
alreadyImprisonedHeroIds: Vector[HeroId],
|
||||
alreadyExiledHeroIds: Vector[HeroId]
|
||||
)
|
||||
|
||||
case SuppressBeastsFailedMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: FactionId,
|
||||
battalionTypeId: Option[BattalionId],
|
||||
beastTypeId: Int,
|
||||
beastCount: Int,
|
||||
provinceId: ProvinceId
|
||||
)
|
||||
|
||||
case SuppressBeastsSucceededMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId],
|
||||
alwaysGenerate: Boolean = false,
|
||||
heroId: HeroId,
|
||||
factionId: FactionId,
|
||||
battalionTypeId: Option[BattalionId],
|
||||
beastTypeId: Int,
|
||||
beastCount: Int,
|
||||
provinceId: ProvinceId,
|
||||
casualtyCount: Int,
|
||||
foodGained: Int,
|
||||
goldGained: Int
|
||||
)
|
||||
|
||||
case SwearBrotherhoodMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
factionId: FactionId,
|
||||
swornBrotherHeroId: HeroId
|
||||
)
|
||||
|
||||
case TruceOfferMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId
|
||||
)
|
||||
|
||||
case TruceResolutionMessage(
|
||||
requestId: String,
|
||||
eagleGameId: GameId,
|
||||
recipientFactionIds: Vector[FactionId] = Vector.empty,
|
||||
alwaysGenerate: Boolean = false,
|
||||
offeringFactionId: FactionId,
|
||||
targetFactionId: FactionId,
|
||||
messengerHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
end LlmRequestT
|
||||
|
||||
@@ -104,6 +104,21 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "battalion_type_converter",
|
||||
srcs = ["BattalionTypeConverter.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":battalion_type_id_converter",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "battle_revelation_converter",
|
||||
srcs = ["BattleRevelationConverter.scala"],
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.eagle0.eagle.model.proto_converters
|
||||
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType as BattalionTypeProto
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
|
||||
object BattalionTypeConverter {
|
||||
def fromProto(battalionTypeProto: BattalionTypeProto): BattalionType =
|
||||
BattalionType(
|
||||
typeId = BattalionTypeIdConverter.fromProto(battalionTypeProto.typeId),
|
||||
name = battalionTypeProto.name,
|
||||
capacity = battalionTypeProto.capacity,
|
||||
allowsCasting = battalionTypeProto.allowsCasting,
|
||||
allowsStealth = battalionTypeProto.allowsStealth,
|
||||
alwaysArcheryCapable = battalionTypeProto.alwaysArcheryCapable,
|
||||
baseCost = battalionTypeProto.baseCost,
|
||||
monthlyFoodCost = battalionTypeProto.monthlyFoodCost,
|
||||
baseArmamentCostPerTroop = battalionTypeProto.baseArmamentCostPerTroop,
|
||||
trainingDifficulty = battalionTypeProto.trainingDifficulty,
|
||||
minimumAgriculture = battalionTypeProto.minimumAgriculture,
|
||||
minimumEconomy = battalionTypeProto.minimumEconomy
|
||||
)
|
||||
|
||||
def toProto(battalionType: BattalionType): BattalionTypeProto =
|
||||
BattalionTypeProto(
|
||||
typeId = BattalionTypeIdConverter.toProto(battalionType.typeId),
|
||||
name = battalionType.name,
|
||||
capacity = battalionType.capacity,
|
||||
allowsCasting = battalionType.allowsCasting,
|
||||
allowsStealth = battalionType.allowsStealth,
|
||||
alwaysArcheryCapable = battalionType.alwaysArcheryCapable,
|
||||
baseCost = battalionType.baseCost,
|
||||
monthlyFoodCost = battalionType.monthlyFoodCost,
|
||||
baseArmamentCostPerTroop = battalionType.baseArmamentCostPerTroop,
|
||||
trainingDifficulty = battalionType.trainingDifficulty,
|
||||
minimumAgriculture = battalionType.minimumAgriculture,
|
||||
minimumEconomy = battalionType.minimumEconomy
|
||||
)
|
||||
}
|
||||
+5
-4
@@ -32,7 +32,9 @@ import net.eagle0.eagle.internal.generated_text_request.{
|
||||
TruceOfferMessage as TruceOfferMessageProto,
|
||||
TruceResolutionMessage as TruceResolutionMessageProto
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.ChronicleUpdatePreviousEntry
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
AllianceOfferMessage,
|
||||
AllianceOfferResolutionMessage,
|
||||
BreakAllianceMessage,
|
||||
@@ -49,7 +51,6 @@ import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
HeroInitialBackstoryRequest,
|
||||
InvitationMessage,
|
||||
InvitationResolutionMessage,
|
||||
LlmRequestT,
|
||||
PleaseRecruitMeMessage,
|
||||
QuestFailedMessage,
|
||||
QuestFulfilledMessage,
|
||||
@@ -212,14 +213,14 @@ object LlmRequestConverter {
|
||||
_: Boolean /* alwaysGenerate */,
|
||||
currentDate: Date,
|
||||
previousEntries: Vector[
|
||||
ChronicleUpdateMessage.PreviousChronicleEntry
|
||||
ChronicleUpdatePreviousEntry
|
||||
],
|
||||
newEntries: Vector[ChronicleEvent]
|
||||
) =>
|
||||
ChronicleUpdateMessageProto(
|
||||
currentDate = Some(DateConverter.toProto(currentDate)),
|
||||
previousEntries = previousEntries.map {
|
||||
case ChronicleUpdateMessage.PreviousChronicleEntry(
|
||||
case ChronicleUpdatePreviousEntry(
|
||||
date,
|
||||
generatedTextId
|
||||
) =>
|
||||
|
||||
@@ -44,6 +44,21 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "battalion_type",
|
||||
srcs = ["BattalionType.scala"],
|
||||
visibility = [
|
||||
":__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":battalion_type_id",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "battle_revelation",
|
||||
srcs = ["BattleRevelation.scala"],
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.eagle0.eagle.model.state
|
||||
|
||||
case class BattalionType(
|
||||
typeId: BattalionTypeId,
|
||||
name: String,
|
||||
capacity: Int,
|
||||
allowsCasting: Boolean,
|
||||
allowsStealth: Boolean,
|
||||
alwaysArcheryCapable: Boolean,
|
||||
baseCost: Double,
|
||||
monthlyFoodCost: Double,
|
||||
baseArmamentCostPerTroop: Double,
|
||||
trainingDifficulty: Double,
|
||||
minimumAgriculture: Int,
|
||||
minimumEconomy: Int
|
||||
)
|
||||
+11
-4
@@ -38,7 +38,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
CapturedHeroExecutedMessage,
|
||||
CapturedHeroExiledMessage,
|
||||
CapturedHeroImprisonedMessage
|
||||
@@ -317,8 +318,10 @@ class EndBattleAftermathPhaseActionTest
|
||||
)
|
||||
)
|
||||
result.newGeneratedTextRequests.loneElement shouldBe CapturedHeroExecutedMessage(
|
||||
eagleGameId = 0xcafe,
|
||||
requestId = "execution 717 18",
|
||||
eagleGameId = 0xcafe,
|
||||
recipientFactionIds = Vector.empty,
|
||||
alwaysGenerate = false,
|
||||
capturedHeroId = executedHero.id,
|
||||
capturedHeroFactionId = 6,
|
||||
actingHeroId = 71,
|
||||
@@ -445,8 +448,10 @@ class EndBattleAftermathPhaseActionTest
|
||||
}
|
||||
result.newGeneratedTextRequests should contain(
|
||||
CapturedHeroImprisonedMessage(
|
||||
eagleGameId = 0xcafe,
|
||||
requestId = "imprison 717 18",
|
||||
eagleGameId = 0xcafe,
|
||||
recipientFactionIds = Vector.empty,
|
||||
alwaysGenerate = false,
|
||||
capturedHeroId = 18,
|
||||
capturedHeroFactionId = 6,
|
||||
actingHeroId = 71,
|
||||
@@ -618,8 +623,10 @@ class EndBattleAftermathPhaseActionTest
|
||||
|
||||
result.newGeneratedTextRequests should contain(
|
||||
CapturedHeroExiledMessage(
|
||||
eagleGameId = 0xcafe,
|
||||
requestId = "exile 717 18",
|
||||
eagleGameId = 0xcafe,
|
||||
recipientFactionIds = Vector.empty,
|
||||
alwaysGenerate = false,
|
||||
capturedHeroId = 18,
|
||||
capturedHeroFactionId = 6,
|
||||
actingHeroId = 71,
|
||||
|
||||
+5
-3
@@ -3,8 +3,9 @@ package net.eagle0.eagle.library.actions.impl.action
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
FixedHeroName,
|
||||
HeroInitialBackstoryRequest
|
||||
LlmRequestT
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.HeroInitialBackstoryRequest
|
||||
import net.eagle0.eagle.model.action_result.types.HeroAppearsResultType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.hero.backstory_version.BackstoryVersion
|
||||
@@ -119,10 +120,11 @@ class UnaffiliatedHeroAppearedActionTest extends AnyFlatSpec with Matchers {
|
||||
HeroInitialBackstoryRequest(
|
||||
requestId = s"hero_23_initial_backstory_37",
|
||||
eagleGameId = 0xa1b2,
|
||||
recipientFactionIds = allFactionIds,
|
||||
alwaysGenerate = false,
|
||||
heroId = heroId,
|
||||
factionId = None,
|
||||
personalityWords = Vector("busy", "saucy", "stupid"),
|
||||
recipientFactionIds = allFactionIds
|
||||
personalityWords = Vector("busy", "saucy", "stupid")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+40
-18
@@ -1,11 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId.{
|
||||
HEAVY_CAVALRY,
|
||||
LIGHT_INFANTRY,
|
||||
LONGBOWMEN
|
||||
}
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.impl.command.ArmTroopsCommand.{
|
||||
ArmamentCost,
|
||||
@@ -65,19 +60,46 @@ class ArmTroopsCommandTest
|
||||
|
||||
private val battalionTypes = Vector(
|
||||
BattalionType(
|
||||
typeId = LIGHT_INFANTRY,
|
||||
typeId = LightInfantry,
|
||||
name = "Light Infantry",
|
||||
capacity = 1000,
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 1.0,
|
||||
monthlyFoodCost = 0.5,
|
||||
baseArmamentCostPerTroop = 0.02,
|
||||
capacity = 1000
|
||||
trainingDifficulty = 1.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 0
|
||||
),
|
||||
BattalionType(
|
||||
typeId = HEAVY_CAVALRY,
|
||||
typeId = HeavyCavalry,
|
||||
name = "Heavy Cavalry",
|
||||
capacity = 600,
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 5.0,
|
||||
monthlyFoodCost = 2.0,
|
||||
baseArmamentCostPerTroop = 0.05,
|
||||
capacity = 600
|
||||
trainingDifficulty = 3.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 2
|
||||
),
|
||||
BattalionType(
|
||||
typeId = LONGBOWMEN,
|
||||
typeId = Longbowmen,
|
||||
name = "Longbowmen",
|
||||
capacity = 800,
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = true,
|
||||
baseCost = 2.0,
|
||||
monthlyFoodCost = 1.0,
|
||||
baseArmamentCostPerTroop = 0.03,
|
||||
capacity = 800
|
||||
trainingDifficulty = 2.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 1
|
||||
)
|
||||
)
|
||||
|
||||
@@ -188,12 +210,12 @@ class ArmTroopsCommandTest
|
||||
it should "spend the gold" in {
|
||||
val expectedCost = (
|
||||
352 * (100 - 0) * battalionTypeMap(
|
||||
HEAVY_CAVALRY
|
||||
HeavyCavalry
|
||||
).baseArmamentCostPerTroop +
|
||||
220 * (21 - 20) * battalionTypeMap(
|
||||
LIGHT_INFANTRY
|
||||
LightInfantry
|
||||
).baseArmamentCostPerTroop +
|
||||
800 * (99 - 93) * battalionTypeMap(LONGBOWMEN).baseArmamentCostPerTroop
|
||||
800 * (99 - 93) * battalionTypeMap(Longbowmen).baseArmamentCostPerTroop
|
||||
).ceil.toInt
|
||||
|
||||
val command = ArmTroopsCommand.make(
|
||||
@@ -253,12 +275,12 @@ class ArmTroopsCommandTest
|
||||
it should "adjust the price index based on gold spent" in {
|
||||
val expectedCost = (
|
||||
352 * (100 - 0) * battalionTypeMap(
|
||||
HEAVY_CAVALRY
|
||||
HeavyCavalry
|
||||
).baseArmamentCostPerTroop +
|
||||
220 * (21 - 20) * battalionTypeMap(
|
||||
LIGHT_INFANTRY
|
||||
LightInfantry
|
||||
).baseArmamentCostPerTroop +
|
||||
800 * (99 - 93) * battalionTypeMap(LONGBOWMEN).baseArmamentCostPerTroop
|
||||
800 * (99 - 93) * battalionTypeMap(Longbowmen).baseArmamentCostPerTroop
|
||||
).ceil.toInt
|
||||
|
||||
val command = ArmTroopsCommand.make(
|
||||
|
||||
@@ -31,7 +31,6 @@ scala_test(
|
||||
name = "arm_troops_command_test",
|
||||
srcs = ["ArmTroopsCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:arm_troops_command",
|
||||
@@ -46,6 +45,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:arm_troops_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
@@ -142,19 +142,19 @@ scala_test(
|
||||
name = "defend_command_test",
|
||||
srcs = ["DefendCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:supplies_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:defend_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:max_combat_unit_count_per_side",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:combat_unit_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:defend_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
@@ -303,13 +303,20 @@ scala_test(
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:free_for_all_decision_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:army_advanced_to_free_for_all_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:army_withdrew_from_free_for_all_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
@@ -607,33 +614,25 @@ scala_test(
|
||||
name = "march_command_test",
|
||||
srcs = ["MarchCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:hero_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:supplies_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_proto_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:march_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:action_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:march_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:max_combat_unit_count_per_side",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:turns_to_resolve_conquest",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:vigor_to_constitution_xp_multiplier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:xp_for_stat_bump",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
"//src/test/scala/net/eagle0/eagle/library/util/validations:testing_noop_validator",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:march_action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:combat_unit",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:supplies",
|
||||
"@rules_scala//scala/scalatest",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -641,19 +640,31 @@ scala_test(
|
||||
name = "organize_troops_command_test",
|
||||
srcs = ["OrganizeTroopsCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:organize_troops_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:price_index_shift_per_gold",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_faction_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:organize_troops_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero",
|
||||
"//src/test/scala/net/eagle0/common:functional_random_test_classes",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
"@rules_scala//scala/scalatest",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -734,23 +745,23 @@ scala_test(
|
||||
name = "recon_command_test",
|
||||
srcs = ["ReconCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:changed_hero_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:changed_province_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:recon_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_agility_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:recon_wisdom_xp",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:recon_started_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
@@ -814,6 +825,22 @@ scala_test(
|
||||
],
|
||||
)
|
||||
|
||||
scala_test(
|
||||
name = "resolve_alliance_offer_command_test_protoless",
|
||||
srcs = ["ResolveAllianceOfferCommandTestProtoless.scala"],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_alliance_offer_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
|
||||
scala_test(
|
||||
name = "resolve_break_alliance_command_test",
|
||||
srcs = ["ResolveBreakAllianceCommandTest.scala"],
|
||||
@@ -841,17 +868,26 @@ scala_test(
|
||||
name = "resolve_invitation_command_test",
|
||||
srcs = ["ResolveInvitationCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_proto_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_invitation_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/test/scala/net/eagle0/eagle/library/util/validations:testing_noop_validator",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:invitation_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction/concrete",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -859,20 +895,51 @@ scala_test(
|
||||
name = "resolve_ransom_offer_command_test",
|
||||
srcs = ["ResolveRansomOfferCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_ransom_offer_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction/concrete",
|
||||
],
|
||||
)
|
||||
|
||||
scala_test(
|
||||
name = "resolve_tribute_command_test",
|
||||
srcs = ["ResolveTributeCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_tribute_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:tribute_paid_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:tribute_refused_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:tribute_amount",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
@@ -881,46 +948,28 @@ scala_test(
|
||||
name = "resolve_truce_offer_command_test",
|
||||
srcs = ["ResolveTruceOfferCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_truce_offer_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:faction_bias_from_imprisonment",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:truce_failure_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:truce_failure_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:truce_success_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:truce_success_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:trust_delta_for_imprisoning_other_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:trust_delta_for_imprisoning_own_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:offer_resolved_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
|
||||
scala_test(
|
||||
name = "resolve_tribute_command_test",
|
||||
srcs = ["ResolveTributeCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_proto_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:resolve_tribute_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
"//src/test/scala/net/eagle0/eagle/library/util/validations:testing_noop_validator",
|
||||
],
|
||||
)
|
||||
|
||||
scala_test(
|
||||
name = "rest_command_test",
|
||||
srcs = ["RestCommandTest.scala"],
|
||||
@@ -970,34 +1019,25 @@ scala_test(
|
||||
name = "send_supplies_command_test",
|
||||
srcs = ["SendSuppliesCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:hero_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:supplies_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_proto_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:send_supplies_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:action_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:send_supplies_wisdom_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:ship_supplies_loss",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:turns_to_resolve_shipment",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:vigor_to_constitution_xp_multiplier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:xp_for_stat_bump",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:sent_supplies_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:supplies",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
"//src/test/scala/net/eagle0/eagle/library/util/validations:testing_noop_validator",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1005,21 +1045,20 @@ scala_test(
|
||||
name = "start_epidemic_command_test",
|
||||
srcs = ["StartEpidemicCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:hero_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:start_epidemic_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:start_epidemic_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:start_epidemic_vigor_delta",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:epidemic_started_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:deferred_change_trait",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
@@ -1067,28 +1106,25 @@ scala_test(
|
||||
name = "swear_brotherhood_command_test",
|
||||
srcs = ["SwearBrotherhoodCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:faction_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:hero_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:supplies_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:deterministic_single_result_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:swear_brotherhood_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:accept_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:ambition_against_discord_for_swear_brotherhood_factor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:swear_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:threshold_for_swear_brotherhood",
|
||||
"//src/test/scala/net/eagle0/common:proto_matchers",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_faction_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:notification_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:swear_brotherhood_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:action_impl_pkg",
|
||||
],
|
||||
)
|
||||
@@ -1119,7 +1155,6 @@ scala_test(
|
||||
name = "train_command_test",
|
||||
srcs = ["TrainCommandTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:train_command",
|
||||
@@ -1140,6 +1175,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:train_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@ import net.eagle0.eagle.common.unaffiliated_hero_quest.{
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.ChangedHeroC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.QuestFailedMessage
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.QuestFailedMessage
|
||||
import net.eagle0.eagle.model.action_result.types.QuestDeclinedResultType
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
|
||||
+47
-106
@@ -1,13 +1,13 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.DefendAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.DefendSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.DEFEND
|
||||
import net.eagle0.eagle.common.combat_unit.CombatUnit as CombatUnitProto
|
||||
import net.eagle0.eagle.internal.army.Army as ArmyProto
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.settings.MaxCombatUnitCountPerSide
|
||||
import net.eagle0.eagle.model.proto_converters.CombatUnitConverter
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.DefendResultType
|
||||
import org.scalatest.Inside.inside
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.Attacking
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.state.{
|
||||
@@ -20,6 +20,7 @@ import net.eagle0.eagle.model.state.{
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.OptionValues.*
|
||||
|
||||
class DefendCommandTest
|
||||
extends AnyFlatSpec
|
||||
@@ -66,29 +67,17 @@ class DefendCommandTest
|
||||
private val defendingProvince =
|
||||
ProvinceC(id = 7, hostileArmies = Vector(attackers))
|
||||
|
||||
private val selectedCommand = DefendSelectedCommand()
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
MaxCombatUnitCountPerSide.setIntValue(10)
|
||||
}
|
||||
|
||||
"make" should "throw if a flee province is selected when none were available" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = 7
|
||||
)
|
||||
|
||||
val sc = DefendSelectedCommand(fleeProvinceId = Some(fleeProvinceId))
|
||||
|
||||
val exception = the[EagleCommandException] thrownBy {
|
||||
DefendCommand.make(
|
||||
actingFactionId = 1,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
defendingUnits = Vector(),
|
||||
fleeProvinceId = Some(fleeProvinceId),
|
||||
availableFleeProvinceIds = Vector(),
|
||||
actingProvince = defendingProvince
|
||||
)
|
||||
}
|
||||
@@ -98,22 +87,12 @@ class DefendCommandTest
|
||||
}
|
||||
|
||||
it should "throw if flee provinces are available and none is selected" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = 7
|
||||
)
|
||||
|
||||
val sc = DefendSelectedCommand(fleeProvinceId = None)
|
||||
|
||||
val exception = the[EagleCommandException] thrownBy {
|
||||
DefendCommand.make(
|
||||
actingFactionId = 1,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
defendingUnits = Vector(),
|
||||
fleeProvinceId = None,
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
actingProvince = defendingProvince
|
||||
)
|
||||
}
|
||||
@@ -123,22 +102,12 @@ class DefendCommandTest
|
||||
}
|
||||
|
||||
it should "throw if the selected flee province is not among the available ones" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = 7
|
||||
)
|
||||
|
||||
val sc = DefendSelectedCommand(fleeProvinceId = Some(fleeProvinceId))
|
||||
|
||||
val exception = the[EagleCommandException] thrownBy {
|
||||
DefendCommand.make(
|
||||
actingFactionId = 1,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
defendingUnits = Vector(),
|
||||
fleeProvinceId = Some(fleeProvinceId),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
actingProvince = defendingProvince
|
||||
)
|
||||
}
|
||||
@@ -148,22 +117,14 @@ class DefendCommandTest
|
||||
}
|
||||
|
||||
"Execute" should "throw if there is no hostile army in specified province" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = defendingProvince.id
|
||||
)
|
||||
|
||||
val defendingProvinceWithoutHostileArmies =
|
||||
defendingProvince.clearHostileArmies
|
||||
|
||||
val command = DefendCommand.make(
|
||||
val command: ProtolessSimpleAction = DefendCommand.make(
|
||||
actingFactionId = 4,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withFleeProvinceId(5),
|
||||
defendingUnits = Vector(),
|
||||
fleeProvinceId = Some(5),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
actingProvince = defendingProvinceWithoutHostileArmies
|
||||
)
|
||||
|
||||
@@ -176,25 +137,13 @@ class DefendCommandTest
|
||||
}
|
||||
|
||||
it should "return a single result" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = defendingProvince.id
|
||||
)
|
||||
|
||||
val command = DefendCommand.make(
|
||||
val command: ProtolessSimpleAction = DefendCommand.make(
|
||||
actingFactionId = 4,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
.withFleeProvinceId(5)
|
||||
.withDefendingUnits(
|
||||
Vector(
|
||||
CombatUnitProto(factionId = 4, heroId = 18, battalionId = Some(99))
|
||||
)
|
||||
),
|
||||
defendingUnits = Vector(
|
||||
CombatUnit(factionId = 4, heroId = 18, battalionId = Some(99))
|
||||
),
|
||||
fleeProvinceId = Some(5),
|
||||
availableFleeProvinceIds = Vector(5, 6),
|
||||
actingProvince = defendingProvince
|
||||
)
|
||||
|
||||
@@ -202,39 +151,31 @@ class DefendCommandTest
|
||||
}
|
||||
|
||||
it should "have a result with a DefendingArmy" in {
|
||||
val availableCommand = DefendAvailableCommand(
|
||||
suitableBattalionsForHeroes = Map(),
|
||||
availableFleeProvinceIds = Vector(fleeProvinceId),
|
||||
availableBattalions = Vector(),
|
||||
availableHeroIds = Vector(),
|
||||
recommendedUnits = Vector(),
|
||||
actingProvinceId = defendingProvince.id
|
||||
)
|
||||
|
||||
val command = DefendCommand.make(
|
||||
val command: ProtolessSimpleAction = DefendCommand.make(
|
||||
actingFactionId = 4,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
.withFleeProvinceId(fleeProvinceId)
|
||||
.withDefendingUnits(
|
||||
Vector(
|
||||
CombatUnitProto(factionId = 4, heroId = 18, battalionId = Some(99))
|
||||
)
|
||||
),
|
||||
defendingUnits = defenders,
|
||||
fleeProvinceId = Some(fleeProvinceId),
|
||||
availableFleeProvinceIds = Vector(fleeProvinceId),
|
||||
actingProvince = defendingProvince
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
result.player should contain(4)
|
||||
result.`type` shouldBe DEFEND
|
||||
result.changedProvinces should have size 1
|
||||
result.changedProvinces.head.newDefendingArmy should contain(
|
||||
ArmyProto(
|
||||
factionId = 4,
|
||||
units = defenders.map(CombatUnitConverter.toProto),
|
||||
fleeProvinceId = Some(fleeProvinceId)
|
||||
)
|
||||
)
|
||||
result.provinceActed should contain(7)
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actingFactionId should contain(4)
|
||||
ar.actionResultType shouldBe DefendResultType
|
||||
ar.provinceId should contain(7)
|
||||
ar.provinceIdActed should contain(7)
|
||||
|
||||
ar.changedProvinces should have size 1
|
||||
inside(ar.changedProvinces.head) { case cp: ChangedProvinceC =>
|
||||
cp.provinceId shouldBe 7
|
||||
|
||||
cp.newDefendingArmy shouldBe defined
|
||||
val defendingArmy = cp.newDefendingArmy.value
|
||||
defendingArmy.factionId shouldBe 4
|
||||
defendingArmy.units shouldBe defenders
|
||||
defendingArmy.fleeProvinceId shouldBe Some(fleeProvinceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.ExileVassalMessage
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.ExileVassalMessage
|
||||
import net.eagle0.eagle.model.action_result.types.VassalExiledResultType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.hero.ExiledBackstoryEvent
|
||||
|
||||
+39
-35
@@ -1,26 +1,34 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.ProtoMatchers
|
||||
import net.eagle0.eagle.api.available_command.FreeForAllDecisionAvailableCommand
|
||||
import net.eagle0.eagle.api.command.util.attack_decision_type.{
|
||||
AdvanceDecision,
|
||||
WithdrawDecision
|
||||
}
|
||||
import net.eagle0.eagle.api.selected_command.FreeForAllDecisionSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.army.{AwaitingFreeForAll, Withdrawing}
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince.HostileArmyGroupStatusChange
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.{
|
||||
ChangedProvinceC,
|
||||
HostileArmyStatusChange
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.concrete.ActionResultC
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
ArmyAdvancedToFreeForAllResultType,
|
||||
ArmyWithdrewFromFreeForAllResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.{
|
||||
AwaitingFreeForAll,
|
||||
Withdrawing
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import org.scalatest.Inside
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class FreeForAllDecisionCommandTest
|
||||
extends AnyFlatSpec
|
||||
with Matchers
|
||||
with ProtoMatchers {
|
||||
with Inside {
|
||||
val actingFactionId: FactionId = 18
|
||||
val pid: ProvinceId = 23
|
||||
val originPid: ProvinceId = 22
|
||||
@@ -50,24 +58,22 @@ class FreeForAllDecisionCommandTest
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result should equalProto(
|
||||
ActionResult(
|
||||
`type` = ActionResultType.ARMY_ADVANCED_TO_FREE_FOR_ALL,
|
||||
player = Some(actingFactionId),
|
||||
province = Some(pid),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = pid,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = actingFactionId,
|
||||
newStatus = AwaitingFreeForAll()
|
||||
)
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe ArmyAdvancedToFreeForAllResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
ar.provinceId shouldBe Some(pid)
|
||||
ar.changedProvinces shouldBe Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = pid,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyStatusChange(
|
||||
factionId = actingFactionId,
|
||||
newStatus = AwaitingFreeForAll
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"execute WithdrawDecision()" should "set the armies as withdrawn" in {
|
||||
@@ -79,24 +85,22 @@ class FreeForAllDecisionCommandTest
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result should equalProto(
|
||||
ActionResult(
|
||||
`type` = ActionResultType.ARMY_WITHDREW_FROM_FREE_FOR_ALL,
|
||||
player = Some(actingFactionId),
|
||||
province = Some(pid),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = pid,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = actingFactionId,
|
||||
newStatus = Withdrawing()
|
||||
)
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe ArmyWithdrewFromFreeForAllResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
ar.provinceId shouldBe Some(pid)
|
||||
ar.changedProvinces shouldBe Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = pid,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyStatusChange(
|
||||
factionId = actingFactionId,
|
||||
newStatus = Withdrawing
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"make" should "throw if the selected decision is not in the available list" in {
|
||||
|
||||
+216
-272
@@ -1,36 +1,27 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
MarchAvailableCommand,
|
||||
MarchCommandFromOneProvince
|
||||
}
|
||||
import net.eagle0.eagle.api.command.util.battalion_with_food_cost.BattalionWithFoodCost
|
||||
import net.eagle0.eagle.api.selected_command.MarchSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.MARCH_ACTION
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId.{
|
||||
HEAVY_CAVALRY,
|
||||
LIGHT_INFANTRY
|
||||
}
|
||||
import net.eagle0.eagle.common.combat_unit.CombatUnit
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.common.province_order_type.ProvinceOrderType
|
||||
import net.eagle0.eagle.internal.battalion.Battalion
|
||||
import net.eagle0.eagle.internal.faction.Faction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.hero.Hero
|
||||
import net.eagle0.eagle.internal.province.Province
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplierImpl
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
MarchWisdomXp,
|
||||
MaxCombatUnitCountPerSide,
|
||||
TurnsToResolveConquest,
|
||||
VigorToConstitutionXpMultiplier,
|
||||
XpForStatBump
|
||||
TurnsToResolveConquest
|
||||
}
|
||||
import net.eagle0.eagle.library.util.IDable
|
||||
import net.eagle0.eagle.library.util.validations.TestingNoopValidator
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.MarchActionResultType
|
||||
import net.eagle0.eagle.model.state.CombatUnit
|
||||
import net.eagle0.eagle.{
|
||||
BattalionId,
|
||||
FactionId,
|
||||
GameId,
|
||||
HeroId,
|
||||
ProvinceId,
|
||||
RoundId
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@@ -40,277 +31,230 @@ class MarchCommandTest
|
||||
with Matchers
|
||||
with BeforeAndAfterEach {
|
||||
|
||||
private val actingFactionId = 5
|
||||
// Test data for new protoless API
|
||||
private val actingFactionId: FactionId = 5
|
||||
private val originProvinceId: ProvinceId = 7
|
||||
private val destinationProvinceId: ProvinceId = 3
|
||||
private val availableDestinationProvinceIds = Vector[ProvinceId](3, 4, 5)
|
||||
private val availableHeroIds = Vector[HeroId](1, 27)
|
||||
private val availableBattalionIds = Vector[BattalionId](98, 99)
|
||||
private val goldAvailable = 3500
|
||||
private val foodAvailable = 4000
|
||||
private val currentRoundId: RoundId = 3
|
||||
private val gameId: GameId = 0xcafe
|
||||
|
||||
private val heroes: Vector[Hero] = Vector(
|
||||
Hero(
|
||||
id = 1,
|
||||
nameTextId = "hn_1",
|
||||
factionId = Some(actingFactionId)
|
||||
),
|
||||
Hero(
|
||||
id = 27,
|
||||
nameTextId = "hn_27",
|
||||
factionId = Some(actingFactionId)
|
||||
)
|
||||
)
|
||||
private val gold = 3212
|
||||
private val food = 3535
|
||||
|
||||
private val battalions: Vector[Battalion] = Vector(
|
||||
Battalion(
|
||||
id = 99,
|
||||
`type` = LIGHT_INFANTRY,
|
||||
size = 200
|
||||
),
|
||||
Battalion(
|
||||
id = 98,
|
||||
`type` = HEAVY_CAVALRY,
|
||||
size = 100
|
||||
)
|
||||
)
|
||||
|
||||
private val provinces: Vector[Province] = Vector(
|
||||
Province(
|
||||
id = 7,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
rulingHeroId = Some(1),
|
||||
rulingFactionHeroIds = heroes.map(_.id)
|
||||
),
|
||||
Province(
|
||||
id = 3
|
||||
)
|
||||
)
|
||||
|
||||
private val battalionTypes =
|
||||
Vector(
|
||||
BattalionType(typeId = LIGHT_INFANTRY, monthlyFoodCost = 0.05),
|
||||
BattalionType(typeId = HEAVY_CAVALRY, monthlyFoodCost = 0.15)
|
||||
)
|
||||
|
||||
private val startingState = GameState(
|
||||
randomSeed = 1L,
|
||||
currentDate = Some(Date(year = 1501, month = 6)),
|
||||
currentRoundId = 3,
|
||||
heroes = IDable.mapifyHeroes(heroes*),
|
||||
battalions = IDable.mapifyBattalions(battalions*),
|
||||
provinces = IDable.mapifyProvinces(provinces*),
|
||||
factions = IDable.mapifyFactions(Faction(id = actingFactionId)),
|
||||
battalionTypes = battalionTypes
|
||||
)
|
||||
|
||||
private val units: Vector[CombatUnit] = Vector(
|
||||
private val marchingUnits: Vector[CombatUnit] = Vector(
|
||||
CombatUnit(factionId = actingFactionId, heroId = 1, battalionId = Some(99)),
|
||||
CombatUnit(factionId = actingFactionId, heroId = 27, battalionId = Some(98))
|
||||
)
|
||||
|
||||
val gold = 3212
|
||||
val food = 3535
|
||||
|
||||
private val actionResultProtoApplier = new ActionResultProtoApplierImpl(
|
||||
validator = TestingNoopValidator
|
||||
)
|
||||
|
||||
private val availableCommand = MarchAvailableCommand(
|
||||
actingProvinceId = 7,
|
||||
oneProvinceCommands = Vector(
|
||||
MarchCommandFromOneProvince(
|
||||
originProvinceId = 7,
|
||||
availableDestinationProvinces = Vector(3),
|
||||
availableHeroIds = Vector(1, 27),
|
||||
availableBattalions = Vector(
|
||||
BattalionWithFoodCost(battalionId = 98, monthlyFood = 50),
|
||||
BattalionWithFoodCost(battalionId = 99, monthlyFood = 60)
|
||||
),
|
||||
goldAvailable = 3500,
|
||||
foodAvailable = 4000
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private val selectedCommand = MarchSelectedCommand(
|
||||
marchingUnits = units,
|
||||
gold = gold,
|
||||
food = food,
|
||||
originProvince = 7,
|
||||
destinationProvinceId = 3
|
||||
)
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
TurnsToResolveConquest.setIntValue(2)
|
||||
MaxCombatUnitCountPerSide.setIntValue(10)
|
||||
ActionVigorCost.setIntValue(15)
|
||||
MarchWisdomXp.setIntValue(7)
|
||||
VigorToConstitutionXpMultiplier.setDoubleValue(0.2)
|
||||
XpForStatBump.setIntValue(100)
|
||||
}
|
||||
|
||||
"Execute result" should "be of type MARCH_ACTION" in {
|
||||
val command = MarchCommand.make(
|
||||
"make" should "throw if destination province is not available" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = 99, // Not in availableDestinationProvinceIds
|
||||
marchingUnits = marchingUnits,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage should include("Destination province 99 is not in")
|
||||
}
|
||||
|
||||
it should "throw if gold exceeds available" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = marchingUnits,
|
||||
gold = 4000, // Exceeds goldAvailable (3500)
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage should include("Specified 4000 gold but only 3500 available")
|
||||
}
|
||||
|
||||
it should "throw if no marching units provided" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = Vector.empty,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage should include(
|
||||
"Must supply at least one acting unit for MarchCommand"
|
||||
)
|
||||
}
|
||||
|
||||
"immediateExecute" should "set the basic action result fields" in {
|
||||
val action = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = marchingUnits,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
result.`type` shouldEqual MARCH_ACTION
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
actionResult.actionResultType.shouldBe(MarchActionResultType)
|
||||
actionResult.actingFactionId.should(contain(actingFactionId))
|
||||
actionResult.provinceId.should(contain(originProvinceId))
|
||||
actionResult.provinceIdActed.should(contain(originProvinceId))
|
||||
}
|
||||
|
||||
"Execute result" should "have moving army arrival round equal to start round plus settings result" in {
|
||||
val command = MarchCommand.make(
|
||||
it should "give wisdom XP and cost vigor to marching heroes" in {
|
||||
val action = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = marchingUnits,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.arrivalRound shouldBe 5
|
||||
}
|
||||
|
||||
"Execute result" should "have moving army with passed-in units" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.getArmy.units should contain theSameElementsAs units
|
||||
}
|
||||
|
||||
"Execute result" should "have origin province equal to attacking province" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.originProvince shouldBe 7
|
||||
}
|
||||
|
||||
"Execute result" should "have destination province equal to defending province" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.destinationProvince shouldBe 3
|
||||
}
|
||||
|
||||
it should "set the gold amount in the army" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.getSupplies.gold shouldBe gold
|
||||
}
|
||||
|
||||
it should "set the food amount in the army" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
newIncomingArmies.head.getSupplies.food shouldBe food
|
||||
}
|
||||
|
||||
it should "remove the moved heroes from the origin province" in {
|
||||
val command = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = startingState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
val newIncomingArmies =
|
||||
result.changedProvinces.find(_.id == 3).get.addedIncomingArmies
|
||||
|
||||
newIncomingArmies.size shouldBe 1
|
||||
}
|
||||
|
||||
it should "mark the acting province as acted" in {
|
||||
val gs = startingState.update(
|
||||
_.provinces :+= 8 -> Province(
|
||||
id = 8,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
rulingHeroId = Some(22),
|
||||
rulingFactionHeroIds = Vector(22),
|
||||
provinceOrders = ProvinceOrderType.ENTRUST
|
||||
),
|
||||
_.heroes :+= 22 -> Hero(id = 22, factionId = Some(actingFactionId))
|
||||
)
|
||||
|
||||
// Make an AC where the origin province is different from the acting province
|
||||
val ac = MarchAvailableCommand(
|
||||
actingProvinceId = 7,
|
||||
oneProvinceCommands = Vector(
|
||||
MarchCommandFromOneProvince(
|
||||
originProvinceId = 8,
|
||||
availableDestinationProvinces = Vector(3),
|
||||
availableHeroIds = Vector(22),
|
||||
availableBattalions = Vector(
|
||||
BattalionWithFoodCost(battalionId = 98, monthlyFood = 50),
|
||||
BattalionWithFoodCost(battalionId = 99, monthlyFood = 60)
|
||||
)
|
||||
actionResult.changedHeroes.shouldBe(
|
||||
Vector(
|
||||
ChangedHeroC(
|
||||
heroId = 1,
|
||||
vigorChange = StatDelta(-15),
|
||||
wisdomXpDelta = Some(7)
|
||||
),
|
||||
ChangedHeroC(
|
||||
heroId = 27,
|
||||
vigorChange = StatDelta(-15),
|
||||
wisdomXpDelta = Some(7)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val sc = MarchSelectedCommand(
|
||||
marchingUnits = Vector(CombatUnit(heroId = 22)),
|
||||
originProvince = 8,
|
||||
destinationProvinceId = 3
|
||||
it should "remove heroes and battalions from origin province and deduct supplies" in {
|
||||
val action = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = marchingUnits,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
MarchCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc
|
||||
)
|
||||
.execute(actionResultProtoApplier = actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
.provinceActed should contain(7)
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
val originProvinceChange = actionResult.changedProvinces
|
||||
.find(_.provinceId == originProvinceId)
|
||||
.get
|
||||
.asInstanceOf[ChangedProvinceC]
|
||||
originProvinceChange.removedRulingFactionHeroIds.shouldBe(Vector(1, 27))
|
||||
originProvinceChange.removedBattalionIds.shouldBe(Vector(99, 98))
|
||||
originProvinceChange.goldDelta.shouldBe(Some(-3212))
|
||||
originProvinceChange.foodDelta.shouldBe(Some(-3535))
|
||||
}
|
||||
|
||||
it should "add incoming army to destination province" in {
|
||||
val action = MarchCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
marchingUnits = marchingUnits,
|
||||
gold = gold,
|
||||
food = food,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableBattalionIds = availableBattalionIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
val destinationProvinceChange = actionResult.changedProvinces
|
||||
.find(_.provinceId == destinationProvinceId)
|
||||
.get
|
||||
.asInstanceOf[ChangedProvinceC]
|
||||
val incomingArmy = destinationProvinceChange.newIncomingArmies.head
|
||||
|
||||
incomingArmy.army.factionId.shouldBe(actingFactionId)
|
||||
incomingArmy.army.units.shouldBe(marchingUnits)
|
||||
incomingArmy.army.fleeProvinceId.shouldBe(Some(originProvinceId))
|
||||
incomingArmy.originProvinceId.shouldBe(originProvinceId)
|
||||
incomingArmy.destinationProvinceId.shouldBe(destinationProvinceId)
|
||||
incomingArmy.arrivalRound.shouldBe(
|
||||
currentRoundId + 2
|
||||
) // TurnsToResolveConquest = 2
|
||||
incomingArmy.supplies.gold.shouldBe(gold)
|
||||
incomingArmy.supplies.food.shouldBe(food)
|
||||
}
|
||||
}
|
||||
|
||||
+122
-83
@@ -1,15 +1,16 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.JankyRandom
|
||||
import net.eagle0.common.ProtoMatchers.equalProto
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId.{
|
||||
HEAVY_CAVALRY,
|
||||
HEAVY_INFANTRY,
|
||||
LIGHT_INFANTRY,
|
||||
LONGBOWMEN
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId.{
|
||||
HeavyCavalry,
|
||||
HeavyInfantry,
|
||||
LightInfantry,
|
||||
Longbowmen
|
||||
}
|
||||
import net.eagle0.eagle.internal.battalion.Battalion
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.battalion.concrete.BattalionC
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.impl.command.OrganizeTroopsCommand.{
|
||||
ChangedBattalion,
|
||||
@@ -19,6 +20,8 @@ import net.eagle0.eagle.library.actions.impl.command.OrganizeTroopsCommand.{
|
||||
}
|
||||
import net.eagle0.eagle.library.settings.PriceIndexShiftPerGold
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.ChangedBattalionC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@@ -26,31 +29,34 @@ import org.scalatest.matchers.should.Matchers
|
||||
class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
private val actingFactionId = 4
|
||||
|
||||
private val battalion1: Battalion = Battalion(
|
||||
private val battalion1: BattalionT = BattalionC(
|
||||
id = 99,
|
||||
size = 150,
|
||||
training = 50.0,
|
||||
armament = 80.0,
|
||||
`type` = LIGHT_INFANTRY
|
||||
typeId = LightInfantry,
|
||||
name = "Battalion 1"
|
||||
)
|
||||
private val battalion2: Battalion = Battalion(
|
||||
private val battalion2: BattalionT = BattalionC(
|
||||
id = 25,
|
||||
size = 500,
|
||||
training = 100.0,
|
||||
armament = 20.0,
|
||||
`type` = HEAVY_INFANTRY
|
||||
typeId = HeavyInfantry,
|
||||
name = "Battalion 2"
|
||||
)
|
||||
private val battalion3: Battalion = Battalion(
|
||||
private val battalion3: BattalionT = BattalionC(
|
||||
id = 150,
|
||||
size = 200,
|
||||
training = 20.0,
|
||||
armament = 90.0,
|
||||
`type` = LIGHT_INFANTRY
|
||||
typeId = LightInfantry,
|
||||
name = "Battalion 3"
|
||||
)
|
||||
|
||||
private val troopCosts: Vector[TroopCost] = Vector(
|
||||
TroopCost(LIGHT_INFANTRY, 1.2),
|
||||
TroopCost(HEAVY_CAVALRY, 2.3)
|
||||
TroopCost(LightInfantry, 1.2),
|
||||
TroopCost(HeavyCavalry, 2.3)
|
||||
)
|
||||
|
||||
val startingGold = 2000
|
||||
@@ -58,16 +64,32 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
private val battalionTypes =
|
||||
Vector(
|
||||
BattalionType(
|
||||
typeId = LIGHT_INFANTRY,
|
||||
typeId = LightInfantry,
|
||||
name = "Light Infantry",
|
||||
capacity = 950,
|
||||
baseCost = 1.0
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 1.0,
|
||||
monthlyFoodCost = 0.5,
|
||||
baseArmamentCostPerTroop = 0.2,
|
||||
trainingDifficulty = 1.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 0
|
||||
),
|
||||
BattalionType(
|
||||
typeId = HEAVY_CAVALRY,
|
||||
typeId = HeavyCavalry,
|
||||
name = "Heavy Cavalry",
|
||||
capacity = 550,
|
||||
baseCost = 2.0
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 2.0,
|
||||
monthlyFoodCost = 1.0,
|
||||
baseArmamentCostPerTroop = 0.5,
|
||||
trainingDifficulty = 2.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 0
|
||||
)
|
||||
)
|
||||
|
||||
@@ -79,7 +101,8 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
priceIndex = 1.0
|
||||
)
|
||||
|
||||
private val existingBattalions = Vector(battalion1, battalion2, battalion3)
|
||||
private val existingBattalions: Vector[BattalionT] =
|
||||
Vector(battalion1, battalion2, battalion3)
|
||||
|
||||
private val functionalRandom = JankyRandom.shared
|
||||
|
||||
@@ -101,9 +124,8 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
newBattalions = Vector(),
|
||||
troopCosts = troopCosts
|
||||
)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
command.immediateExecute(functionalRandom)
|
||||
command.immediateExecute(functionalRandom).newValue
|
||||
}
|
||||
ex.getMessage shouldBe "requirement failed: Attempting to change battalions that are not in province 7"
|
||||
}
|
||||
@@ -113,7 +135,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
actingFactionId = actingFactionId,
|
||||
province = province,
|
||||
existingBattalions = existingBattalions,
|
||||
constructibleBattalionTypeIds = Vector(LONGBOWMEN),
|
||||
constructibleBattalionTypeIds = Vector(Longbowmen),
|
||||
allBattalionTypes = battalionTypes,
|
||||
changedBattalions = Vector(
|
||||
ChangedBattalion(
|
||||
@@ -130,7 +152,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
command.immediateExecute(functionalRandom)
|
||||
}
|
||||
ex.getMessage shouldBe "requirement failed: LIGHT_INFANTRY was not among constructible battalion types Vector(LONGBOWMEN)"
|
||||
ex.getMessage shouldBe "requirement failed: LightInfantry was not among constructible battalion types Vector(Longbowmen)"
|
||||
}
|
||||
|
||||
it should "not throw if a changed battalion without any new troops has a non-supported type" in {
|
||||
@@ -139,7 +161,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
province =
|
||||
province.copy(battalionIds = Vector(battalion1.id, battalion3.id)),
|
||||
existingBattalions = existingBattalions,
|
||||
constructibleBattalionTypeIds = Vector(LONGBOWMEN),
|
||||
constructibleBattalionTypeIds = Vector(Longbowmen),
|
||||
allBattalionTypes = battalionTypes,
|
||||
changedBattalions = Vector(
|
||||
ChangedBattalion(
|
||||
@@ -168,12 +190,12 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
actingFactionId = actingFactionId,
|
||||
province = province,
|
||||
existingBattalions = existingBattalions,
|
||||
constructibleBattalionTypeIds = Vector(LONGBOWMEN),
|
||||
constructibleBattalionTypeIds = Vector(Longbowmen),
|
||||
allBattalionTypes = battalionTypes,
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 300,
|
||||
troopsFromOtherBattalion = Vector.empty
|
||||
)
|
||||
@@ -184,7 +206,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
command.immediateExecute(functionalRandom)
|
||||
}
|
||||
ex.getMessage shouldBe "requirement failed: LIGHT_INFANTRY was not among constructible battalion types Vector(LONGBOWMEN)"
|
||||
ex.getMessage shouldBe "requirement failed: LightInfantry was not among constructible battalion types Vector(Longbowmen)"
|
||||
}
|
||||
|
||||
it should "throw if an existing battalion would go over capacity" in {
|
||||
@@ -222,7 +244,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = HEAVY_CAVALRY,
|
||||
`type` = HeavyCavalry,
|
||||
newTroops = 900,
|
||||
troopsFromOtherBattalion = Vector.empty
|
||||
)
|
||||
@@ -246,7 +268,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = HEAVY_CAVALRY,
|
||||
`type` = HeavyCavalry,
|
||||
newTroops = 500,
|
||||
troopsFromOtherBattalion = Vector.empty
|
||||
)
|
||||
@@ -270,7 +292,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -280,7 +302,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
),
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -309,7 +331,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -319,7 +341,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
),
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -348,7 +370,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -358,7 +380,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
),
|
||||
NewBattalion(
|
||||
`type` = HEAVY_CAVALRY,
|
||||
`type` = HeavyCavalry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -374,7 +396,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
command.immediateExecute(functionalRandom)
|
||||
}
|
||||
ex.getMessage shouldBe "requirement failed: Can't change LIGHT_INFANTRY troops into HEAVY_CAVALRY"
|
||||
ex.getMessage shouldBe "requirement failed: Can't change LightInfantry troops into HeavyCavalry"
|
||||
}
|
||||
|
||||
it should "remove the troops from the merged-from battalion" in {
|
||||
@@ -387,7 +409,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -397,7 +419,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
),
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -412,7 +434,9 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should contain(
|
||||
result.changedBattalions.collect { case cb: ChangedBattalionC =>
|
||||
cb.to
|
||||
} should contain(
|
||||
battalion1.withSize(10)
|
||||
)
|
||||
}
|
||||
@@ -444,13 +468,16 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should contain(battalion1.withSize(130))
|
||||
val changedBattalion3 =
|
||||
result.changedBattalions.find(_.id == battalion3.id).get
|
||||
result.changedBattalions.collect { case cb: ChangedBattalionC =>
|
||||
cb.to
|
||||
} should contain(battalion1.withSize(130))
|
||||
val changedBattalion3 = result.changedBattalions.collectFirst {
|
||||
case cb: ChangedBattalionC if cb.to.id == battalion3.id => cb
|
||||
}.get
|
||||
|
||||
changedBattalion3.size shouldBe 270
|
||||
changedBattalion3.training shouldBe (18.5185 +- 0.001) // ((200 * 20.0) + (20 * 50.0) + (50 * 0.0)) / 270
|
||||
changedBattalion3.armament shouldBe (72.5926 +- 0.001) // ((200 * 90.0) + (20 * 80.0) + (50 * 0.0)) / 270
|
||||
changedBattalion3.to.size shouldBe 270
|
||||
changedBattalion3.to.training shouldBe (18.5185 +- 0.001) // ((200 * 20.0) + (20 * 50.0) + (50 * 0.0)) / 270
|
||||
changedBattalion3.to.armament shouldBe (72.5926 +- 0.001) // ((200 * 90.0) + (20 * 80.0) + (50 * 0.0)) / 270
|
||||
}
|
||||
|
||||
it should "throw if a ChangedBattalion id is duplicated" in {
|
||||
@@ -590,7 +617,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 900,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -630,7 +657,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.provinceActed shouldBe Some(7)
|
||||
result.provinceIdActed shouldBe Some(7)
|
||||
}
|
||||
|
||||
"Adding to an existing battalion" should "adjust the battalion size" in {
|
||||
@@ -655,9 +682,11 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should have size 1
|
||||
result.changedBattalions.head.size shouldBe 600
|
||||
result.changedBattalions.head.id shouldBe battalion1.id
|
||||
result.changedBattalions.head.`type` shouldBe battalion1.`type`
|
||||
inside(result.changedBattalions.head) { case cb: ChangedBattalionC =>
|
||||
cb.to.size shouldBe 600
|
||||
cb.to.id shouldBe battalion1.id
|
||||
cb.to.typeId shouldBe battalion1.typeId
|
||||
}
|
||||
}
|
||||
|
||||
it should "reduce training" in {
|
||||
@@ -682,9 +711,11 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should have size 1
|
||||
result.changedBattalions.head.training shouldBe 12.5 // 150 / 600 * 50.0
|
||||
result.changedBattalions.head.id shouldBe battalion1.id
|
||||
result.changedBattalions.head.`type` shouldBe battalion1.`type`
|
||||
inside(result.changedBattalions.head) { case cb: ChangedBattalionC =>
|
||||
cb.to.training shouldBe 12.5 // 150 / 600 * 50.0
|
||||
cb.to.id shouldBe battalion1.id
|
||||
cb.to.typeId shouldBe battalion1.typeId
|
||||
}
|
||||
}
|
||||
|
||||
it should "reduce armament" in {
|
||||
@@ -709,9 +740,11 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should have size 1
|
||||
result.changedBattalions.head.armament shouldBe 20.0 // 150 / 600 * 80.0
|
||||
result.changedBattalions.head.id shouldBe battalion1.id
|
||||
result.changedBattalions.head.`type` shouldBe battalion1.`type`
|
||||
inside(result.changedBattalions.head) { case cb: ChangedBattalionC =>
|
||||
cb.to.armament shouldBe 20.0 // 150 / 600 * 80.0
|
||||
cb.to.id shouldBe battalion1.id
|
||||
cb.to.typeId shouldBe battalion1.typeId
|
||||
}
|
||||
}
|
||||
|
||||
it should "spend gold based on new troop count" in {
|
||||
@@ -736,9 +769,9 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedProvinces should have size 1
|
||||
result.changedProvinces.head.goldDelta should contain(
|
||||
-450.0 * 1.2
|
||||
)
|
||||
inside(result.changedProvinces.head) { case cp: ChangedProvinceC =>
|
||||
cp.goldDelta should contain(-450.0 * 1.2)
|
||||
}
|
||||
}
|
||||
|
||||
it should "adjust price index based on spend" in {
|
||||
@@ -766,8 +799,8 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
result.changedProvinces should have size 1
|
||||
|
||||
inside(result.changedProvinces.head) { case p =>
|
||||
p.newPriceIndex shouldBe Some(1.054) // 1.0 + 0.0001 * 450.0 * 1.2
|
||||
inside(result.changedProvinces.head) { case cp: ChangedProvinceC =>
|
||||
cp.newPriceIndex shouldBe Some(1.054) // 1.0 + 0.0001 * 450.0 * 1.2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,7 +814,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 324,
|
||||
troopsFromOtherBattalion = Vector.empty
|
||||
)
|
||||
@@ -793,7 +826,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
result.newBattalions should have size 1
|
||||
val nb = result.newBattalions.head
|
||||
nb.`type` shouldBe LIGHT_INFANTRY
|
||||
nb.typeId shouldBe LightInfantry
|
||||
nb.size shouldBe 324
|
||||
}
|
||||
|
||||
@@ -807,7 +840,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 324,
|
||||
troopsFromOtherBattalion = Vector.empty
|
||||
)
|
||||
@@ -818,9 +851,9 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedProvinces should have size 1
|
||||
result.changedProvinces.head.goldDelta should contain(
|
||||
-(324 * 1.2).ceil
|
||||
)
|
||||
inside(result.changedProvinces.head) { case cp: ChangedProvinceC =>
|
||||
cp.goldDelta should contain(-(324 * 1.2).ceil)
|
||||
}
|
||||
}
|
||||
|
||||
"reducing a battalion to 0 size" should "remove the battalion" in {
|
||||
@@ -833,7 +866,7 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
changedBattalions = Vector(),
|
||||
newBattalions = Vector(
|
||||
NewBattalion(
|
||||
`type` = LIGHT_INFANTRY,
|
||||
`type` = LightInfantry,
|
||||
newTroops = 0,
|
||||
troopsFromOtherBattalion = Vector(
|
||||
TroopsFromOtherBattalion(
|
||||
@@ -873,15 +906,13 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
val result = command.immediateExecute(functionalRandom).newValue
|
||||
|
||||
result.changedBattalions should have size 1
|
||||
result.changedBattalions.head should equalProto(
|
||||
Battalion(
|
||||
id = battalion1.id,
|
||||
`type` = battalion1.`type`,
|
||||
size = battalion1.size - 53,
|
||||
training = battalion1.training,
|
||||
armament = battalion1.armament
|
||||
)
|
||||
)
|
||||
inside(result.changedBattalions.head) { case cb: ChangedBattalionC =>
|
||||
cb.to.id shouldBe battalion1.id
|
||||
cb.to.typeId shouldBe battalion1.typeId
|
||||
cb.to.size shouldBe (battalion1.size - 53)
|
||||
cb.to.training shouldBe battalion1.training
|
||||
cb.to.armament shouldBe battalion1.armament
|
||||
}
|
||||
}
|
||||
|
||||
"dismissing more than all the troops in a battalion" should "throw" in {
|
||||
@@ -936,15 +967,23 @@ class OrganizeTroopsCommandTest extends AnyFlatSpec with Matchers {
|
||||
"moving troops out and in at the same time" should "pass the checks" in {
|
||||
val battalionTypes = Vector(
|
||||
BattalionType(
|
||||
typeId = LIGHT_INFANTRY,
|
||||
typeId = LightInfantry,
|
||||
name = "Light Infantry",
|
||||
capacity = 1000,
|
||||
baseCost = 1.0
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 1.0,
|
||||
monthlyFoodCost = 1.0,
|
||||
baseArmamentCostPerTroop = 1.0,
|
||||
trainingDifficulty = 1.0,
|
||||
minimumAgriculture = 1,
|
||||
minimumEconomy = 1
|
||||
)
|
||||
)
|
||||
|
||||
val batt1 = Battalion(id = 29, size = 800, `type` = LIGHT_INFANTRY)
|
||||
val batt2 = Battalion(id = 39, size = 500, `type` = LIGHT_INFANTRY)
|
||||
val batt1 = BattalionC(id = 29, typeId = LightInfantry, size = 800)
|
||||
val batt2 = BattalionC(id = 39, typeId = LightInfantry, size = 500)
|
||||
|
||||
noException shouldBe thrownBy {
|
||||
OrganizeTroopsCommand
|
||||
|
||||
+55
-58
@@ -1,15 +1,17 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.ReconAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ReconSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.RECON_STARTED
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.province.IncomingEndTurnAction
|
||||
import net.eagle0.eagle.internal.province.IncomingEndTurnAction.IncomingRecon
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.ReconStartedResultType
|
||||
import net.eagle0.eagle.model.state.province.{
|
||||
IncomingEndTurnAction,
|
||||
IncomingRecon
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ReconAgilityXp,
|
||||
@@ -19,20 +21,16 @@ import net.eagle0.eagle.library.settings.{
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
|
||||
class ReconCommandTest
|
||||
extends AnyFlatSpec
|
||||
with BeforeAndAfterEach
|
||||
with Matchers {
|
||||
import net.eagle0.common.ProtoMatchers.*
|
||||
|
||||
val gameState: GameState = GameState()
|
||||
|
||||
private val availableCommand = ReconAvailableCommand(
|
||||
actingProvinceId = 5,
|
||||
availableHeroIds = Vector(1, 2, 3),
|
||||
availableTargetProvinces = Vector(9, 10, 11)
|
||||
)
|
||||
private val actingProvinceId = 5
|
||||
private val availableHeroIds = Vector(1, 2, 3)
|
||||
private val availableTargetProvinces = Vector(9, 10, 11)
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
ReconVigorCost.setDoubleValue(30)
|
||||
@@ -41,14 +39,14 @@ class ReconCommandTest
|
||||
}
|
||||
|
||||
"make" should "throw if the acting hero is not in the available list" in {
|
||||
val selected = ReconSelectedCommand(actingHeroId = 8, targetProvinceId = 9)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ReconCommand.make(
|
||||
actingFactionId = 7,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selected
|
||||
actingProvinceId = actingProvinceId,
|
||||
actingHeroId = 8,
|
||||
destinationProvinceId = 9,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinces = availableTargetProvinces
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,14 +54,14 @@ class ReconCommandTest
|
||||
}
|
||||
|
||||
it should "throw if the destination province is not in the available list" in {
|
||||
val selected = ReconSelectedCommand(actingHeroId = 3, targetProvinceId = 13)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ReconCommand.make(
|
||||
actingFactionId = 7,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selected
|
||||
actingProvinceId = actingProvinceId,
|
||||
actingHeroId = 3,
|
||||
destinationProvinceId = 13,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinces = availableTargetProvinces
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,47 +69,46 @@ class ReconCommandTest
|
||||
}
|
||||
|
||||
"immediateExecute" should "return an action result" in {
|
||||
val selected = ReconSelectedCommand(actingHeroId = 3, targetProvinceId = 11)
|
||||
|
||||
val results =
|
||||
ReconCommand
|
||||
.make(
|
||||
actingFactionId = 7,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selected
|
||||
actingProvinceId = actingProvinceId,
|
||||
actingHeroId = 3,
|
||||
destinationProvinceId = 11,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinces = availableTargetProvinces
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
results should equalProto(
|
||||
ActionResult(
|
||||
`type` = RECON_STARTED,
|
||||
player = Some(7),
|
||||
province = Some(5),
|
||||
provinceActed = Some(5),
|
||||
changedHeroes = Vector(
|
||||
ChangedHero(
|
||||
id = 3,
|
||||
vigor = VigorDelta(-30),
|
||||
agilityXpDelta = Some(20),
|
||||
wisdomXpDelta = Some(10)
|
||||
)
|
||||
inside(results) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe ReconStartedResultType
|
||||
ar.actingFactionId shouldBe Some(7)
|
||||
ar.provinceId shouldBe Some(5)
|
||||
ar.changedHeroes shouldBe Vector(
|
||||
ChangedHeroC(
|
||||
heroId = 3,
|
||||
vigorChange = StatDelta(-30),
|
||||
agilityXpDelta = Some(20),
|
||||
wisdomXpDelta = Some(10)
|
||||
)
|
||||
)
|
||||
ar.changedProvinces shouldBe Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = 5,
|
||||
removedRulingFactionHeroIds = Vector(3)
|
||||
),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(id = 5, removedRulingPlayerHeroIds = Vector(3)),
|
||||
ChangedProvince(
|
||||
id = 11,
|
||||
addedIncomingEndTurnActions = Vector(
|
||||
IncomingEndTurnAction(
|
||||
fromFactionId = 7,
|
||||
fromProvinceId = 5,
|
||||
action =
|
||||
IncomingEndTurnAction.Action.Recon(IncomingRecon(heroId = 3))
|
||||
)
|
||||
ChangedProvinceC(
|
||||
provinceId = 11,
|
||||
newIncomingEndTurnActions = Vector(
|
||||
IncomingEndTurnAction(
|
||||
fromFactionId = 7,
|
||||
fromProvinceId = 5,
|
||||
details = IncomingRecon(heroId = 3)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+193
-276
@@ -1,313 +1,230 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.ProtoMatchers
|
||||
import net.eagle0.eagle.api.available_command.ResolveInvitationAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveInvitationSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.INVITATION_RESOLVED
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
DiplomacyOffer,
|
||||
InvitationDetails
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_INVALIDATED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
import net.eagle0.eagle.model.action_result.types.InvitationResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{DiplomacyOffer, Invitation}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Accepted,
|
||||
Rejected,
|
||||
Invalidated
|
||||
}
|
||||
import net.eagle0.eagle.common.province_order_type.ProvinceOrderType
|
||||
import net.eagle0.eagle.internal.battalion.Battalion
|
||||
import net.eagle0.eagle.internal.faction.Faction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.hero.Hero
|
||||
import net.eagle0.eagle.internal.province.Province
|
||||
import net.eagle0.eagle.library.EagleClientException
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplierImpl
|
||||
import net.eagle0.eagle.library.util.IDable.{
|
||||
mapifyBattalions,
|
||||
mapifyFactions,
|
||||
mapifyHeroes,
|
||||
mapifyProvinces
|
||||
}
|
||||
import net.eagle0.eagle.library.util.validations.TestingNoopValidator
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.faction.concrete.FactionC
|
||||
import net.eagle0.eagle.FactionId
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
|
||||
class ResolveInvitationCommandTest
|
||||
extends AnyFlatSpec
|
||||
with Matchers
|
||||
with ProtoMatchers {
|
||||
class ResolveInvitationCommandTest extends AnyFlatSpec with Matchers {
|
||||
private val actingFactionId = 4
|
||||
private val firstInvitingFid = 3
|
||||
private val secondInvitingFid = 8
|
||||
private val originatingFactionId = 8
|
||||
private val currentRoundId = 873
|
||||
private val gameId = 0xfeed
|
||||
|
||||
private val actionResultProtoApplier = new ActionResultProtoApplierImpl(
|
||||
validator = TestingNoopValidator
|
||||
)
|
||||
|
||||
private val actingFidProvince = Province(
|
||||
id = 100,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
rulingHeroId = Some(19),
|
||||
rulingFactionHeroIds = Vector(19, 20, 21),
|
||||
battalionIds = Vector(100, 101, 102),
|
||||
provinceOrders = ProvinceOrderType.ENTRUST
|
||||
)
|
||||
|
||||
private val firstInvitingFidProvince = Province(
|
||||
id = 101,
|
||||
rulingFactionId = Some(firstInvitingFid),
|
||||
rulingHeroId = Some(29),
|
||||
rulingFactionHeroIds = Vector(29, 31),
|
||||
provinceOrders = ProvinceOrderType.ENTRUST
|
||||
)
|
||||
|
||||
private val secondInvitingFidProvince = Province(
|
||||
id = 102,
|
||||
rulingFactionId = Some(secondInvitingFid),
|
||||
rulingHeroId = Some(39),
|
||||
rulingFactionHeroIds = Vector(40, 41),
|
||||
provinceOrders = ProvinceOrderType.ENTRUST
|
||||
)
|
||||
|
||||
private val firstInvitation = DiplomacyOffer(
|
||||
originatingFactionId = firstInvitingFid,
|
||||
private val invitation = Invitation(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = 30,
|
||||
messengerOriginProvinceId = 101,
|
||||
offerDetails = InvitationDetails(),
|
||||
eligibleStatuses = Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
messengerHeroId = 29,
|
||||
messengerOriginProvinceId = 2,
|
||||
status = Accepted,
|
||||
eligibleStatuses = Vector(Accepted, Rejected),
|
||||
offerTextId = "test_invitation"
|
||||
)
|
||||
|
||||
private val secondInvitation = DiplomacyOffer(
|
||||
originatingFactionId = secondInvitingFid,
|
||||
// Additional invitation for testing invalidation logic
|
||||
private val secondInvitation = Invitation(
|
||||
originatingFactionId = 15,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = 39,
|
||||
messengerOriginProvinceId = 102,
|
||||
offerDetails = InvitationDetails(),
|
||||
eligibleStatuses = Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
messengerHeroId = 31,
|
||||
messengerOriginProvinceId = 5,
|
||||
status = Accepted,
|
||||
eligibleStatuses = Vector(Accepted, Rejected),
|
||||
offerTextId = "test_invitation_2"
|
||||
)
|
||||
|
||||
private val gameState = GameState(
|
||||
currentDate = Some(Date(year = 2525, month = 4)),
|
||||
provinces = mapifyProvinces(
|
||||
actingFidProvince,
|
||||
firstInvitingFidProvince,
|
||||
secondInvitingFidProvince
|
||||
),
|
||||
heroes = mapifyHeroes(
|
||||
Vector(
|
||||
actingFidProvince,
|
||||
firstInvitingFidProvince,
|
||||
secondInvitingFidProvince
|
||||
).flatMap(p =>
|
||||
p.rulingFactionHeroIds
|
||||
.map(hid => Hero(id = hid, factionId = p.rulingFactionId))
|
||||
)*
|
||||
) ++ Vector(
|
||||
30 -> Hero(id = 30, factionId = Some(firstInvitingFid)),
|
||||
39 -> Hero(id = 39, factionId = Some(secondInvitingFid))
|
||||
),
|
||||
battalions = mapifyBattalions(
|
||||
Vector(
|
||||
actingFidProvince,
|
||||
firstInvitingFidProvince,
|
||||
secondInvitingFidProvince
|
||||
).flatMap(_.battalionIds).map(bid => Battalion(id = bid))*
|
||||
),
|
||||
factions = mapifyFactions(
|
||||
Faction(id = firstInvitingFid),
|
||||
Faction(
|
||||
id = actingFactionId,
|
||||
incomingDiplomacyOffers = Vector(firstInvitation, secondInvitation)
|
||||
),
|
||||
Faction(id = secondInvitingFid)
|
||||
)
|
||||
// Third offer from accepting faction to another faction (for outgoing invalidation)
|
||||
private val outgoingOffer = Invitation(
|
||||
originatingFactionId = actingFactionId,
|
||||
targetFactionId = 10,
|
||||
messengerHeroId = 33,
|
||||
messengerOriginProvinceId = 7,
|
||||
status = Accepted,
|
||||
eligibleStatuses = Vector(Accepted, Rejected),
|
||||
offerTextId = "outgoing_invitation"
|
||||
)
|
||||
|
||||
private val availableCommand = ResolveInvitationAvailableCommand(
|
||||
invitations = Vector(firstInvitation, secondInvitation)
|
||||
// Test faction data
|
||||
private val acceptingFaction = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = 100,
|
||||
name = "Accepting Faction",
|
||||
leaderIds = Vector(100),
|
||||
incomingDiplomacyOffers = Vector(invitation, secondInvitation)
|
||||
)
|
||||
|
||||
private val acceptSc = ResolveInvitationSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_ACCEPTED
|
||||
private val originatingFaction = FactionC(
|
||||
id = originatingFactionId,
|
||||
factionHeadId = 101,
|
||||
name = "Originating Faction",
|
||||
leaderIds = Vector(101)
|
||||
)
|
||||
|
||||
"execute with accept==true" should "return a result of type INVITATION_RESOLVED" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = acceptSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
results should have size 1
|
||||
results.head.actionResult.`type` shouldBe INVITATION_RESOLVED
|
||||
}
|
||||
|
||||
it should "remove all incoming invitations" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = acceptSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
val actingFactionAfter = results.head.actionResult.changedFactions
|
||||
.findLast(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
firstInvitation.originatingFactionId,
|
||||
secondInvitation.originatingFactionId
|
||||
)
|
||||
}
|
||||
|
||||
it should "put the incoming invitation back with status ACCEPTED" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = acceptSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
val actingFactionAfter = results.head.actionResult.changedFactions
|
||||
.findLast(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers should contain(
|
||||
secondInvitation.withStatus(DIPLOMACY_OFFER_STATUS_ACCEPTED)
|
||||
)
|
||||
}
|
||||
|
||||
it should "set the other invitation to INVALIDATED" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = acceptSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
val actingFactionAfter = results.head.actionResult.changedFactions
|
||||
.findLast(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers should contain(
|
||||
firstInvitation.withStatus(DIPLOMACY_OFFER_STATUS_INVALIDATED)
|
||||
)
|
||||
}
|
||||
|
||||
private val rejectSc = ResolveInvitationSelectedCommand(
|
||||
originatingFactionId = secondInvitingFid,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
private val secondOfferFaction = FactionC(
|
||||
id = 15,
|
||||
factionHeadId = 102,
|
||||
name = "Second Offer Faction",
|
||||
leaderIds = Vector(102)
|
||||
)
|
||||
|
||||
"execute with accept==false" should "return a result of type INVITATION_REJECTED" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = rejectSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
private val targetOfOutgoingFaction = FactionC(
|
||||
id = 10,
|
||||
factionHeadId = 103,
|
||||
name = "Target of Outgoing Faction",
|
||||
leaderIds = Vector(103),
|
||||
incomingDiplomacyOffers = Vector(outgoingOffer)
|
||||
)
|
||||
|
||||
results should have size 1
|
||||
results.head.actionResult.`type` shouldBe INVITATION_RESOLVED
|
||||
}
|
||||
private val allFactions: Map[Int, FactionT] = Map(
|
||||
actingFactionId -> acceptingFaction,
|
||||
originatingFactionId -> originatingFaction,
|
||||
15 -> secondOfferFaction,
|
||||
10 -> targetOfOutgoingFaction
|
||||
)
|
||||
|
||||
it should "remove the incoming invitation" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = rejectSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
results should have size 1
|
||||
val actingFactionAfter = results.head.actionResult.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
secondInvitation.originatingFactionId
|
||||
"execute with Accepted" should "return a result of type InvitationResolvedResultType" in {
|
||||
val command = ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
val result = command.immediateExecute
|
||||
|
||||
it should "put the incoming invitation back with status REJECTED" in {
|
||||
val results = ResolveInvitationCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = rejectSc
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
val actingFactionAfter = results.head.actionResult.changedFactions
|
||||
.findLast(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers shouldBe Vector(
|
||||
secondInvitation.withStatus(DIPLOMACY_OFFER_STATUS_REJECTED)
|
||||
)
|
||||
}
|
||||
|
||||
"make" should "throw if the selected fid was not an option" in {
|
||||
val sc = ResolveInvitationSelectedCommand(
|
||||
originatingFactionId = 4
|
||||
)
|
||||
|
||||
val ex = the[EagleClientException] thrownBy {
|
||||
ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc
|
||||
)
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe InvitationResolvedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected faction ID 4 was not among options List(3, 8)"
|
||||
}
|
||||
|
||||
it should "throw if the selected resolution was not an option" in {
|
||||
val sc = ResolveInvitationSelectedCommand(
|
||||
originatingFactionId = firstInvitingFid,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
it should "contain the accepted invitation in new incoming diplomacy offers" in {
|
||||
val command = ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
val ex = the[EagleClientException] thrownBy {
|
||||
ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = availableCommand.withInvitations(
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
// Should have 2 changed factions: accepting faction + target of outgoing faction
|
||||
ar.changedFactions should have length 2
|
||||
|
||||
// Find the accepting faction change
|
||||
val acceptingFactionChange =
|
||||
ar.changedFactions.find(_.factionId == actingFactionId).get
|
||||
inside(acceptingFactionChange) { case faction: ChangedFactionC =>
|
||||
faction.removedIncomingDiplomacyOfferFactionIds.shouldBe(
|
||||
Vector(
|
||||
firstInvitation.withEligibleStatuses(
|
||||
Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
)
|
||||
originatingFactionId,
|
||||
15 // Second invitation faction ID
|
||||
)
|
||||
),
|
||||
selectedCommand = sc,
|
||||
gameState = gameState
|
||||
)
|
||||
}
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers.shouldBe(
|
||||
Vector[DiplomacyOffer](
|
||||
invitation.copy(status = Accepted),
|
||||
secondInvitation.copy(status = Invalidated)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected invitation resolution DIPLOMACY_OFFER_STATUS_IMPRISONED was not among options Vector(DIPLOMACY_OFFER_STATUS_ACCEPTED, DIPLOMACY_OFFER_STATUS_REJECTED)"
|
||||
// Find the target of outgoing faction change (faction 10)
|
||||
val outgoingTargetChange = ar.changedFactions.find(_.factionId == 10).get
|
||||
inside(outgoingTargetChange) { case faction: ChangedFactionC =>
|
||||
faction.removedIncomingDiplomacyOfferFactionIds.shouldBe(
|
||||
Vector(actingFactionId)
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers.shouldBe(
|
||||
Vector[DiplomacyOffer](
|
||||
outgoingOffer.copy(status = Invalidated)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"execute with Rejected" should "return a result of type InvitationResolvedResultType" in {
|
||||
val command = ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Rejected,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe InvitationResolvedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "contain the rejected invitation in new incoming diplomacy offers" in {
|
||||
val command = ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Rejected,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers.shouldBe(
|
||||
Vector[DiplomacyOffer](
|
||||
invitation.copy(status = Rejected)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "invalidate outgoing offers when accepting an invitation" in {
|
||||
val command = ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
// Should invalidate outgoing offers from accepting faction
|
||||
val outgoingTargetChange = ar.changedFactions.find(_.factionId == 10)
|
||||
outgoingTargetChange.shouldBe(defined)
|
||||
inside(outgoingTargetChange.get) { case faction: ChangedFactionC =>
|
||||
faction.newIncomingDiplomacyOffers.should(
|
||||
contain(
|
||||
outgoingOffer.copy(status = Invalidated): DiplomacyOffer
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+244
-124
@@ -1,164 +1,284 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.WaitingAction
|
||||
import net.eagle0.common.ProtoMatchers.equalProto
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.ResolveRansomOfferAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveRansomOfferSelectedCommand
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{
|
||||
DiplomacyOffer,
|
||||
HostageOfferedInExchange,
|
||||
PrisonerOfferedInExchange,
|
||||
PrisonerToBeRansomed,
|
||||
RansomOfferDetails
|
||||
RansomOffer
|
||||
}
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.faction.Faction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{Accepted, Rejected}
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.faction.concrete.FactionC
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.util.IDable.mapifyFactions
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import net.eagle0.eagle.FactionId
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
|
||||
class ResolveRansomOfferCommandTest
|
||||
extends AnyFlatSpec
|
||||
with Matchers
|
||||
with BeforeAndAfterEach {
|
||||
class ResolveRansomOfferCommandTest extends AnyFlatSpec with Matchers {
|
||||
private val actingFactionId = 4
|
||||
private val originatingFactionId = 8
|
||||
private val currentRoundId = 873
|
||||
private val gameId = 0xfeed
|
||||
|
||||
private val actingFactionId: FactionId = 12
|
||||
private val offeringFactionId: FactionId = 7
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.RansomOfferDetails.*
|
||||
|
||||
private val prisonerToBeRansomed =
|
||||
PrisonerToBeRansomed(prisonerHeroId = 101, provinceIdForPrisoner = 22)
|
||||
|
||||
private val ransomOffer = DiplomacyOffer(
|
||||
originatingFactionId = offeringFactionId,
|
||||
private val ransomOffer = RansomOffer(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerOriginProvinceId = 21,
|
||||
offerDetails = RansomOfferDetails(
|
||||
prisonerToBeRansomed = Some(prisonerToBeRansomed),
|
||||
prisonersOffered = Vector(PrisonerOfferedInExchange(heroId = 200)),
|
||||
hostagesOffered = Vector(HostageOfferedInExchange(heroId = 300)),
|
||||
goldOffered = 500
|
||||
messengerHeroId = 29,
|
||||
messengerOriginProvinceId = 2,
|
||||
status = Accepted,
|
||||
eligibleStatuses = Vector(Accepted, Rejected),
|
||||
offerTextId = "test_ransom_offer",
|
||||
prisonerToBeRansomed = PrisonerToBeRansomed(
|
||||
prisonerHeroId = 101,
|
||||
provinceIdForPrisoner = 22
|
||||
),
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
eligibleStatuses = Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
)
|
||||
|
||||
private val availableCommand =
|
||||
ResolveRansomOfferAvailableCommand(offers = Vector(ransomOffer))
|
||||
|
||||
private val acceptedCommand = ResolveRansomOfferSelectedCommand(
|
||||
offeringFactionId = offeringFactionId,
|
||||
ransomOffer = Some(ransomOffer),
|
||||
resolution = DIPLOMACY_OFFER_STATUS_ACCEPTED
|
||||
)
|
||||
|
||||
private val rejectedCommand = ResolveRansomOfferSelectedCommand(
|
||||
offeringFactionId = offeringFactionId,
|
||||
ransomOffer = Some(ransomOffer),
|
||||
resolution = DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
|
||||
private val gameState = GameState(
|
||||
currentDate = Some(Date(year = 1501, month = 6)),
|
||||
randomSeed = 1L,
|
||||
factions = mapifyFactions(
|
||||
Faction(id = offeringFactionId),
|
||||
Faction(
|
||||
id = actingFactionId,
|
||||
incomingDiplomacyOffers = Vector(ransomOffer)
|
||||
prisonersOffered = Vector(
|
||||
PrisonerOfferedInExchange(
|
||||
heroId = 200,
|
||||
factionIdForPrisoner = 9,
|
||||
provinceIdWithHero = 23
|
||||
)
|
||||
)
|
||||
),
|
||||
hostagesOffered = Vector(
|
||||
HostageOfferedInExchange(
|
||||
heroId = 300,
|
||||
provinceIdWithHero = 24
|
||||
)
|
||||
),
|
||||
goldOffered = 500
|
||||
)
|
||||
|
||||
"make" should "throw if the offering faction ID is not in the available list" in {
|
||||
val scWithBadOfferingFid = acceptedCommand.withOfferingFactionId(15)
|
||||
// Test faction data
|
||||
private val acceptingFaction = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = 100,
|
||||
name = "Accepting Faction",
|
||||
leaderIds = Vector(100),
|
||||
incomingDiplomacyOffers = Vector(ransomOffer)
|
||||
)
|
||||
|
||||
private val originatingFaction = FactionC(
|
||||
id = originatingFactionId,
|
||||
factionHeadId = 101,
|
||||
name = "Originating Faction",
|
||||
leaderIds = Vector(101)
|
||||
)
|
||||
|
||||
private val allFactions: Map[Int, FactionT] = Map(
|
||||
actingFactionId -> acceptingFaction,
|
||||
originatingFactionId -> originatingFaction
|
||||
)
|
||||
|
||||
"execute with Accepted" should "return a result of type OfferResolvedResultType" in {
|
||||
val command = ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe OfferResolvedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "contain the accepted ransom offer in new incoming diplomacy offers" in {
|
||||
val command = ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers.shouldBe(
|
||||
Vector[DiplomacyOffer](
|
||||
ransomOffer.copy(status = Accepted)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"execute with Rejected" should "return a result of type OfferResolvedResultType" in {
|
||||
val command = ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Rejected,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe OfferResolvedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "contain the rejected ransom offer in new incoming diplomacy offers" in {
|
||||
val command = ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Rejected,
|
||||
allFactions = allFactions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers.shouldBe(
|
||||
Vector[DiplomacyOffer](
|
||||
ransomOffer.copy(status = Rejected)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validation error tests
|
||||
"make() validation" should "throw when acting faction is not found" in {
|
||||
val factionsWithoutActingFaction = Map(
|
||||
originatingFactionId -> originatingFaction
|
||||
)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = scWithBadOfferingFid
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = factionsWithoutActingFaction,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected faction ID 15 was not among options Vector(7)"
|
||||
ex.getMessage should include(
|
||||
s"Acting faction $actingFactionId not found in faction data"
|
||||
)
|
||||
}
|
||||
|
||||
it should "throw if IMPRISONED selected" in {
|
||||
val scWithBadOfferingFid =
|
||||
acceptedCommand.withResolution(DIPLOMACY_OFFER_STATUS_IMPRISONED)
|
||||
it should "throw when ransom offer from originating faction is not found" in {
|
||||
val actingFactionWithoutRansomOffer = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = 100,
|
||||
name = "Accepting Faction",
|
||||
leaderIds = Vector(100),
|
||||
incomingDiplomacyOffers = Vector() // No ransom offer
|
||||
)
|
||||
|
||||
val factionsWithoutRansomOffer = Map(
|
||||
actingFactionId -> actingFactionWithoutRansomOffer,
|
||||
originatingFactionId -> originatingFaction
|
||||
)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = scWithBadOfferingFid
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = factionsWithoutRansomOffer,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected ransom resolution DIPLOMACY_OFFER_STATUS_IMPRISONED was not among options Vector(DIPLOMACY_OFFER_STATUS_ACCEPTED, DIPLOMACY_OFFER_STATUS_REJECTED)"
|
||||
}
|
||||
|
||||
"execute with accepted" should "remove the incoming ransom offer and add it back with ACCEPTED" in {
|
||||
val results = ResolveRansomOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = acceptedCommand
|
||||
)
|
||||
.resultsOfExecute()
|
||||
|
||||
results should have size 1
|
||||
results.head.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get should equalProto(
|
||||
ChangedFaction(
|
||||
id = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(ransomOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(ransomOffer.withStatus(DIPLOMACY_OFFER_STATUS_ACCEPTED))
|
||||
)
|
||||
ex.getMessage should include(
|
||||
s"Ransom offer from faction $originatingFactionId not found"
|
||||
)
|
||||
}
|
||||
|
||||
"execute with rejected" should "remove the incoming ransom offer and add it back with REJECTED" in {
|
||||
val results = ResolveRansomOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = rejectedCommand
|
||||
)
|
||||
.resultsOfExecute()
|
||||
it should "throw when ransom offer from different originating faction exists" in {
|
||||
val differentOriginatingFactionId = 999
|
||||
val ransomOfferFromDifferentFaction =
|
||||
ransomOffer.copy(originatingFactionId = differentOriginatingFactionId)
|
||||
|
||||
results should have size 1
|
||||
results.head.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get should equalProto(
|
||||
ChangedFaction(
|
||||
id = actingFactionId,
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
Vector(ransomOffer.originatingFactionId),
|
||||
addedIncomingDiplomacyOffers =
|
||||
Vector(ransomOffer.withStatus(DIPLOMACY_OFFER_STATUS_REJECTED))
|
||||
val actingFactionWithDifferentRansomOffer = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = 100,
|
||||
name = "Accepting Faction",
|
||||
leaderIds = Vector(100),
|
||||
incomingDiplomacyOffers = Vector(ransomOfferFromDifferentFaction)
|
||||
)
|
||||
|
||||
val factionsWithWrongRansomOffer = Map(
|
||||
actingFactionId -> actingFactionWithDifferentRansomOffer,
|
||||
originatingFactionId -> originatingFaction
|
||||
)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution = Accepted,
|
||||
allFactions = factionsWithWrongRansomOffer,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage should include(
|
||||
s"Ransom offer from faction $originatingFactionId not found"
|
||||
)
|
||||
}
|
||||
|
||||
it should "throw when resolution is not in eligible statuses" in {
|
||||
val ransomOfferWithLimitedStatuses = ransomOffer.copy(eligibleStatuses =
|
||||
Vector(Accepted)
|
||||
) // Only Accepted allowed
|
||||
val actingFactionWithLimitedOffer = FactionC(
|
||||
id = actingFactionId,
|
||||
factionHeadId = 100,
|
||||
name = "Accepting Faction",
|
||||
leaderIds = Vector(100),
|
||||
incomingDiplomacyOffers = Vector(ransomOfferWithLimitedStatuses)
|
||||
)
|
||||
|
||||
val factionsWithLimitedOffer = Map(
|
||||
actingFactionId -> actingFactionWithLimitedOffer,
|
||||
originatingFactionId -> originatingFaction
|
||||
)
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
resolution =
|
||||
Rejected, // Not allowed since eligibleStatuses only contains Accepted
|
||||
allFactions = factionsWithLimitedOffer,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage should include(
|
||||
s"Selected ransom offer resolution $Rejected was not among options Vector($Accepted)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+300
-329
@@ -1,377 +1,348 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
ResolveTributeAvailableCommand,
|
||||
TributeAndFaction
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC
|
||||
}
|
||||
import net.eagle0.eagle.api.selected_command.ResolveTributeSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.{
|
||||
TRIBUTE_PAID,
|
||||
TRIBUTE_REFUSED
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.{
|
||||
ChangedProvinceC,
|
||||
HostileArmyStatusChange
|
||||
}
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.internal.faction_relationship.FactionRelationship
|
||||
import net.eagle0.eagle.internal.faction_relationship.FactionRelationship.RelationshipLevel.TRUCE
|
||||
import net.eagle0.eagle.common.tribute_amount.TributeAmount
|
||||
import net.eagle0.eagle.internal.army.{
|
||||
Army,
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
TributePaidResultType,
|
||||
TributeRefusedResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.state.TributeAmount
|
||||
import net.eagle0.eagle.model.state.HostileArmyGroupStatus.{
|
||||
Attacking,
|
||||
HostileArmyGroup,
|
||||
MovingArmy,
|
||||
TributeDemanded,
|
||||
TributePaid
|
||||
}
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince.HostileArmyGroupStatusChange
|
||||
import net.eagle0.eagle.internal.faction.Faction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.province.Province
|
||||
import net.eagle0.eagle.internal.supplies.Supplies
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplierImpl
|
||||
import net.eagle0.eagle.library.util.validations.TestingNoopValidator
|
||||
import net.eagle0.eagle.{FactionId, GameId, ProvinceId, RoundId}
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
|
||||
class ResolveTributeCommandTest extends AnyFlatSpec with Matchers {
|
||||
val actingFactionId = 3
|
||||
val actingProvinceId = 7
|
||||
val attackingFactionId = 9
|
||||
private val actingFactionId: FactionId = 12
|
||||
private val demandingFactionId: FactionId = 7
|
||||
private val actingProvinceId: ProvinceId = 22
|
||||
private val gameId: GameId = 0xfeed
|
||||
private val currentRoundId: RoundId = 873
|
||||
private val currentDate = Date(year = 1425, month = Date.Month.June)
|
||||
|
||||
val actionResultProtoApplier = new ActionResultProtoApplierImpl(
|
||||
validator = TestingNoopValidator
|
||||
)
|
||||
private val tributeAmount = TributeAmount(gold = 500, food = 300)
|
||||
private val availableDemandingFactionIds = Vector(demandingFactionId, 15, 20)
|
||||
|
||||
private val demandedGold = 400
|
||||
private val demandedFood = 700
|
||||
|
||||
private val currentDate = Date(year = 499, month = 7)
|
||||
|
||||
private val tributeAmount =
|
||||
TributeAmount(gold = demandedGold, food = demandedFood)
|
||||
|
||||
private val availableCommand = ResolveTributeAvailableCommand(
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 500,
|
||||
availableFood = 1000,
|
||||
demands = Vector(
|
||||
TributeAndFaction(
|
||||
demandingFactionId = attackingFactionId,
|
||||
tributeDemanded = Some(tributeAmount)
|
||||
)
|
||||
"make" should "successfully create command when paying tribute with sufficient resources" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
)
|
||||
|
||||
private val paidCommand = ResolveTributeSelectedCommand(
|
||||
demandingFactionId = attackingFactionId,
|
||||
paid = true
|
||||
)
|
||||
command should not be null
|
||||
}
|
||||
|
||||
private val refusedCommand = ResolveTributeSelectedCommand(
|
||||
demandingFactionId = attackingFactionId,
|
||||
paid = false
|
||||
)
|
||||
|
||||
val movingArmyId = 67
|
||||
val originatingProvinceId = 99
|
||||
|
||||
private val tributeDemandingArmy = HostileArmyGroup(
|
||||
factionId = attackingFactionId,
|
||||
armies = Vector(
|
||||
MovingArmy(
|
||||
id = movingArmyId,
|
||||
army = Some(
|
||||
Army(
|
||||
factionId = attackingFactionId
|
||||
)
|
||||
),
|
||||
originProvince = originatingProvinceId,
|
||||
supplies = Some(Supplies(food = 2000, gold = 1000))
|
||||
)
|
||||
),
|
||||
status = TributeDemanded(Some(tributeAmount))
|
||||
)
|
||||
|
||||
private val actingProvince = Province(
|
||||
id = actingProvinceId,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
gold = 500,
|
||||
food = 1000,
|
||||
hostileArmies = Vector(tributeDemandingArmy)
|
||||
)
|
||||
|
||||
private val gameState = GameState(
|
||||
randomSeed = 1L,
|
||||
provinces = Map(
|
||||
actingProvinceId -> actingProvince,
|
||||
originatingProvinceId -> Province(id = originatingProvinceId)
|
||||
),
|
||||
factions = Map(
|
||||
actingFactionId -> Faction(id = actingFactionId),
|
||||
attackingFactionId -> Faction(id = attackingFactionId)
|
||||
),
|
||||
currentDate = Some(currentDate)
|
||||
)
|
||||
|
||||
"responding to a nonexistent demand" should "throw with appropriate message" in {
|
||||
val ac = availableCommand
|
||||
val sc = ResolveTributeSelectedCommand(
|
||||
demandingFactionId = 11,
|
||||
paid = true
|
||||
it should "successfully create command when rejecting tribute" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = false,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 0, // Resources don't matter when rejecting
|
||||
availableFood = 0,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
command should not be null
|
||||
}
|
||||
|
||||
it should "throw when demanding faction ID is not in available list" in {
|
||||
val invalidDemandingFactionId = 999
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc
|
||||
demandingFactionId = invalidDemandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected faction ID 11 was not among options List(9)"
|
||||
ex.getMessage should include(
|
||||
s"Selected demanding faction ID $invalidDemandingFactionId was not among options $availableDemandingFactionIds"
|
||||
)
|
||||
}
|
||||
|
||||
"accepting without enough food" should "throw with appropriate message" in {
|
||||
val ac = availableCommand.withAvailableFood(200)
|
||||
val sc = paidCommand
|
||||
|
||||
it should "throw when paying tribute but insufficient gold" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 400, // Less than tributeAmount.gold (500)
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Trying to pay 700 food, but only 200 available"
|
||||
ex.getMessage should include(
|
||||
s"Not enough gold to pay tribute: have 400, need ${tributeAmount.gold}"
|
||||
)
|
||||
}
|
||||
|
||||
"accepting without enough gold" should "throw with appropriate message" in {
|
||||
val ac = availableCommand.withAvailableGold(123)
|
||||
val sc = paidCommand
|
||||
|
||||
it should "throw when paying tribute but insufficient food" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 200, // Less than tributeAmount.food (300)
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Trying to pay 400 gold, but only 123 available"
|
||||
}
|
||||
|
||||
"paying a tribute demand" should "set the basics" in {
|
||||
val results = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
results should have size 1
|
||||
val result = results.head.actionResult
|
||||
result.`type` shouldBe TRIBUTE_PAID
|
||||
result.player shouldBe Some(actingFactionId)
|
||||
}
|
||||
|
||||
it should "set the hostile army to status TributePaid" in {
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedProvinces.exists { cp =>
|
||||
cp.id == actingProvinceId && cp.hostileArmyStatusChanges
|
||||
.contains(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = TributePaid(tributeAmount = Some(tributeAmount))
|
||||
)
|
||||
)
|
||||
} shouldBe true
|
||||
}
|
||||
|
||||
it should "set another tribute demanding army for same attacker & defender to TributePaid" in {
|
||||
val gameStateWithAnotherTributeDemandingArmy = gameState.update(
|
||||
_.provinces :+= (91 -> Province(
|
||||
id = 91,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
hostileArmies = Vector(
|
||||
HostileArmyGroup(
|
||||
factionId = attackingFactionId,
|
||||
armies = Vector(),
|
||||
status = TributeDemanded(Some(TributeAmount(food = 10, gold = 100)))
|
||||
)
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameStateWithAnotherTributeDemandingArmy,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedProvinces.exists { cp =>
|
||||
cp.id == 91 && cp.hostileArmyStatusChanges
|
||||
.contains(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = TributePaid(tributeAmount = Some(TributeAmount()))
|
||||
)
|
||||
)
|
||||
} shouldBe true
|
||||
}
|
||||
|
||||
it should "does not change a tribute demanding army from another faction" in {
|
||||
val gameStateWithAnotherTributeDemandingArmy = gameState.update(
|
||||
_.provinces :+= (91 -> Province(
|
||||
id = 91,
|
||||
rulingFactionId = Some(actingFactionId),
|
||||
hostileArmies = Vector(
|
||||
HostileArmyGroup(
|
||||
factionId = 111,
|
||||
armies = Vector(),
|
||||
status = TributeDemanded(Some(TributeAmount(food = 10, gold = 100)))
|
||||
)
|
||||
)
|
||||
)),
|
||||
_.factions :+= (111 -> Faction(id = 111))
|
||||
)
|
||||
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameStateWithAnotherTributeDemandingArmy,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedProvinces.exists(_.id == 91) shouldBe false
|
||||
}
|
||||
|
||||
it should "remove resources from the defender" in {
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedProvinces.exists { cp =>
|
||||
cp.id == actingProvinceId && cp.goldDelta.contains(
|
||||
-demandedGold
|
||||
) && cp.foodDelta
|
||||
.contains(-demandedFood)
|
||||
} shouldBe true
|
||||
}
|
||||
|
||||
it should "create a new truce" in {
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = paidCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedFactions should have size 2
|
||||
result.changedFactions should contain(
|
||||
ChangedFaction(
|
||||
id = actingFactionId,
|
||||
changedFactionRelationships = Vector(
|
||||
FactionRelationship(
|
||||
targetFactionId = attackingFactionId,
|
||||
relationshipLevel = TRUCE,
|
||||
resetDate = Some(Date(year = 500, month = 7))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
result.changedFactions should contain(
|
||||
ChangedFaction(
|
||||
id = attackingFactionId,
|
||||
changedFactionRelationships = Vector(
|
||||
FactionRelationship(
|
||||
targetFactionId = actingFactionId,
|
||||
relationshipLevel = TRUCE,
|
||||
resetDate = Some(Date(year = 500, month = 7))
|
||||
)
|
||||
)
|
||||
)
|
||||
ex.getMessage should include(
|
||||
s"Not enough food to pay tribute: have 200, need ${tributeAmount.food}"
|
||||
)
|
||||
}
|
||||
|
||||
it should "create the appropriate resolution message" in {}
|
||||
|
||||
"refusing a tribute demand" should "set the basics" in {
|
||||
val results = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = refusedCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
|
||||
results should have size 1
|
||||
val result = results.head.actionResult
|
||||
result.`type` shouldBe TRIBUTE_REFUSED
|
||||
result.player shouldBe Some(actingFactionId)
|
||||
}
|
||||
|
||||
it should "set the army to Attacking()" in {
|
||||
val result = ResolveTributeCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = refusedCommand
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
|
||||
result.changedProvinces should contain(
|
||||
ChangedProvince(
|
||||
id = actingProvinceId,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = tributeDemandingArmy.factionId,
|
||||
newStatus = Attacking()
|
||||
)
|
||||
)
|
||||
)
|
||||
"execute with paid = true" should "return TributePaidResultType" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe TributePaidResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "create the appropriate resolution message" in {}
|
||||
it should "deduct gold and food from the acting province" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedProvinces.loneElement) {
|
||||
case province: ChangedProvinceC =>
|
||||
province.provinceId shouldBe actingProvinceId
|
||||
province.goldDelta shouldBe Some(-tributeAmount.gold)
|
||||
province.foodDelta shouldBe Some(-tributeAmount.food)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"execute with paid = false" should "return TributeRefusedResultType" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = false,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 0, // Resources don't matter when rejecting
|
||||
availableFood = 0,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe TributeRefusedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "not change gold or food in the acting province" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = false,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 0,
|
||||
availableFood = 0,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedProvinces.loneElement) {
|
||||
case province: ChangedProvinceC =>
|
||||
province.provinceId shouldBe actingProvinceId
|
||||
province.goldDelta shouldBe None
|
||||
province.foodDelta shouldBe None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "set hostile army status to TributePaid for demanding faction" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedProvinces.loneElement) {
|
||||
case province: ChangedProvinceC =>
|
||||
inside(province.hostileArmyStatusChanges.loneElement) {
|
||||
case statusChange: HostileArmyStatusChange =>
|
||||
statusChange.factionId shouldBe demandingFactionId
|
||||
statusChange.newStatus shouldBe TributePaid(tributeAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "create a 12-month truce between factions when tribute is paid" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = true,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 1000,
|
||||
availableFood = 500,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.changedFactions should have size 2
|
||||
|
||||
// Check the paying faction's relationship
|
||||
val payingFactionChange = ar.changedFactions.collectFirst {
|
||||
case faction: ChangedFactionC if faction.factionId == actingFactionId =>
|
||||
faction
|
||||
}.get
|
||||
payingFactionChange.changedFactionRelationships should have size 1
|
||||
val payingRelationship =
|
||||
payingFactionChange.changedFactionRelationships.head
|
||||
payingRelationship.targetFactionId shouldBe demandingFactionId
|
||||
payingRelationship.relationshipLevel shouldBe FactionRelationship.RelationshipLevel.Truce
|
||||
payingRelationship.resetDate shouldBe Some(currentDate.addMonths(12))
|
||||
|
||||
// Check the demanding faction's relationship
|
||||
val demandingFactionChange = ar.changedFactions.collectFirst {
|
||||
case faction: ChangedFactionC
|
||||
if faction.factionId == demandingFactionId =>
|
||||
faction
|
||||
}.get
|
||||
demandingFactionChange.changedFactionRelationships should have size 1
|
||||
val demandingRelationship =
|
||||
demandingFactionChange.changedFactionRelationships.head
|
||||
demandingRelationship.targetFactionId shouldBe actingFactionId
|
||||
demandingRelationship.relationshipLevel shouldBe FactionRelationship.RelationshipLevel.Truce
|
||||
demandingRelationship.resetDate shouldBe Some(currentDate.addMonths(12))
|
||||
}
|
||||
}
|
||||
|
||||
"execute with paid = false" should "set hostile army status to Attacking for demanding faction" in {
|
||||
val command = ResolveTributeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
demandingFactionId = demandingFactionId,
|
||||
tributeAmount = tributeAmount,
|
||||
paid = false,
|
||||
availableDemandingFactionIds = availableDemandingFactionIds,
|
||||
actingProvinceId = actingProvinceId,
|
||||
availableGold = 0,
|
||||
availableFood = 0,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
val result = command.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedProvinces.loneElement) {
|
||||
case province: ChangedProvinceC =>
|
||||
inside(province.hostileArmyStatusChanges.loneElement) {
|
||||
case statusChange: HostileArmyStatusChange =>
|
||||
statusChange.factionId shouldBe demandingFactionId
|
||||
statusChange.newStatus shouldBe Attacking
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+269
-214
@@ -1,264 +1,319 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.ResolveTruceOfferAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.ResolveTruceOfferSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.OFFER_RESOLVED
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
DiplomacyOffer,
|
||||
TruceOfferDetails
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.{
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_UNRESOLVED
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleClientException
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
FactionBiasFromImprisonment,
|
||||
TruceFailureCharismaXp,
|
||||
TruceFailureWisdomXp,
|
||||
TruceSuccessCharismaXp,
|
||||
TruceSuccessWisdomXp,
|
||||
TrustDeltaForImprisoningOtherHero,
|
||||
TrustDeltaForImprisoningOwnHero
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.TruceResolutionMessage
|
||||
import net.eagle0.eagle.model.action_result.types.OfferResolvedResultType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.TruceOffer
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.{
|
||||
Accepted,
|
||||
Imprisoned,
|
||||
Rejected,
|
||||
Unresolved
|
||||
}
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
|
||||
class ResolveTruceOfferCommandTest
|
||||
extends AnyFlatSpec
|
||||
with Matchers
|
||||
with BeforeAndAfterEach {
|
||||
|
||||
val actingFactionId = 4
|
||||
|
||||
private val firstOffer = DiplomacyOffer(
|
||||
originatingFactionId = 8,
|
||||
targetFactionId = actingFactionId,
|
||||
offerDetails =
|
||||
TruceOfferDetails(endDate = Some(Date(year = 2525, month = 10))),
|
||||
messengerHeroId = 29,
|
||||
messengerOriginProvinceId = 2,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
eligibleStatuses = Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
)
|
||||
|
||||
private val secondOffer = DiplomacyOffer(
|
||||
originatingFactionId = 3,
|
||||
targetFactionId = actingFactionId,
|
||||
offerDetails =
|
||||
TruceOfferDetails(endDate = Some(Date(year = 2527, month = 4))),
|
||||
messengerHeroId = 19,
|
||||
messengerOriginProvinceId = 1,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
eligibleStatuses = Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED,
|
||||
DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
)
|
||||
|
||||
private val actingFactionId = 4
|
||||
private val originatingFactionId = 8
|
||||
private val messengerHeroId = 29
|
||||
private val messengerOriginProvinceId = 2
|
||||
private val currentRoundId = 873
|
||||
private val gameId = 0xfeed
|
||||
|
||||
private val availableCommand = ResolveTruceOfferAvailableCommand(
|
||||
offers = Vector(
|
||||
secondOffer,
|
||||
firstOffer
|
||||
)
|
||||
private val truceOffer = TruceOffer(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
status = Unresolved,
|
||||
eligibleStatuses = Vector(Accepted, Rejected, Imprisoned),
|
||||
endDate = Date(year = 2525, month = Date.Month.October),
|
||||
offerTextId = "test-truce-offer"
|
||||
)
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
TruceSuccessCharismaXp.setIntValue(25)
|
||||
TruceSuccessWisdomXp.setIntValue(20)
|
||||
TruceFailureCharismaXp.setIntValue(10)
|
||||
TruceFailureWisdomXp.setIntValue(20)
|
||||
FactionBiasFromImprisonment.setDoubleValue(-100)
|
||||
TrustDeltaForImprisoningOwnHero.setIntValue(-150)
|
||||
TrustDeltaForImprisoningOtherHero.setIntValue(-40)
|
||||
}
|
||||
private val availableOriginatingFactionIds = Vector(3, 8, 15)
|
||||
private val availableResolutions = Vector(Accepted, Rejected, Imprisoned)
|
||||
|
||||
"execute with resolution ACCEPT" should "return a result of type OFFER_RESOLVED" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_ACCEPTED
|
||||
)
|
||||
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.`type` shouldBe OFFER_RESOLVED
|
||||
}
|
||||
|
||||
it should "set the ACCEPTED resolution on the truce offer on the acting faction" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_ACCEPTED
|
||||
)
|
||||
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
val actingFactionAfter = result.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get
|
||||
|
||||
actingFactionAfter.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
firstOffer.originatingFactionId
|
||||
)
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers shouldBe Vector(
|
||||
firstOffer.withStatus(DIPLOMACY_OFFER_STATUS_ACCEPTED)
|
||||
)
|
||||
}
|
||||
|
||||
"execute with resolution REJECT" should "return a result of type OFFER_RESOLVED" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.`type` shouldBe OFFER_RESOLVED
|
||||
}
|
||||
|
||||
it should "set the REJECTED resolution on the truce offer on the acting faction" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
val actingFactionAfter = result.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
firstOffer.originatingFactionId
|
||||
)
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers shouldBe Vector(
|
||||
firstOffer.withStatus(DIPLOMACY_OFFER_STATUS_REJECTED)
|
||||
)
|
||||
}
|
||||
|
||||
"make" should "throw if the selected fid was not an option" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 4
|
||||
)
|
||||
|
||||
val ex = the[EagleClientException] thrownBy {
|
||||
"make" should "throw if the selected originating faction is not among options" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveTruceOfferCommand.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = 99, // not in available list
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected faction ID 4 was not among options Vector(3, 8)"
|
||||
ex.getMessage shouldBe "requirement failed: Selected faction ID 99 was not among options Vector(3, 8, 15)"
|
||||
}
|
||||
|
||||
it should "throw if the selected resolution was not an option" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
|
||||
val ex = the[EagleClientException] thrownBy {
|
||||
it should "throw if the selected resolution is not among options" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
ResolveTruceOfferCommand.make(
|
||||
availableCommand = availableCommand.withOffers(
|
||||
Vector(
|
||||
firstOffer.withEligibleStatuses(
|
||||
Vector(
|
||||
DIPLOMACY_OFFER_STATUS_ACCEPTED,
|
||||
DIPLOMACY_OFFER_STATUS_REJECTED
|
||||
)
|
||||
)
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions =
|
||||
Vector(Rejected, Imprisoned), // Accepted not available
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected truce resolution Accepted was not among options Vector(Rejected, Imprisoned)"
|
||||
}
|
||||
|
||||
"immediateExecute" should "return a result of type OFFER_RESOLVED" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe OfferResolvedResultType
|
||||
ar.actingFactionId shouldBe Some(actingFactionId)
|
||||
}
|
||||
}
|
||||
|
||||
it should "update the faction with the accepted truce offer" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers shouldBe Vector(
|
||||
truceOffer.copy(status = Accepted)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "create appropriate notification for accepted truce" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.newNotifications.loneElement) {
|
||||
case notification: NotificationC =>
|
||||
notification.details shouldBe NotificationDetails.TruceAccepted(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
),
|
||||
selectedCommand = sc,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
notification.affectedHeroIds shouldBe Vector(messengerHeroId)
|
||||
notification.deferred shouldBe true
|
||||
}
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected truce resolution DIPLOMACY_OFFER_STATUS_IMPRISONED was not among options Vector(DIPLOMACY_OFFER_STATUS_ACCEPTED, DIPLOMACY_OFFER_STATUS_REJECTED)"
|
||||
}
|
||||
|
||||
"execute with resolution IMPRISON" should "return a result of type OFFER_RESOLVED" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
|
||||
it should "create LLM request for accepted truce" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Accepted,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.`type` shouldBe OFFER_RESOLVED
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.newGeneratedTextRequests.loneElement) {
|
||||
case llm: TruceResolutionMessage =>
|
||||
llm.requestId shouldBe s"$currentRoundId resolve truce $messengerHeroId"
|
||||
llm.eagleGameId shouldBe gameId
|
||||
llm.offeringFactionId shouldBe originatingFactionId
|
||||
llm.targetFactionId shouldBe actingFactionId
|
||||
llm.messengerHeroId shouldBe messengerHeroId
|
||||
llm.resolution shouldBe Accepted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "set the IMPRISONED resolution on the truce offer on the acting faction" in {
|
||||
val sc = ResolveTruceOfferSelectedCommand(
|
||||
originatingFactionId = 8,
|
||||
resolution = DIPLOMACY_OFFER_STATUS_IMPRISONED
|
||||
)
|
||||
|
||||
"execute with resolution REJECT" should "update the faction with the rejected truce offer" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = sc,
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Rejected,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
val actingFactionAfter = result.changedFactions
|
||||
.find(_.id == actingFactionId)
|
||||
.get
|
||||
actingFactionAfter.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
firstOffer.originatingFactionId
|
||||
)
|
||||
actingFactionAfter.addedIncomingDiplomacyOffers shouldBe Vector(
|
||||
firstOffer.withStatus(DIPLOMACY_OFFER_STATUS_IMPRISONED)
|
||||
)
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers shouldBe Vector(
|
||||
truceOffer.copy(status = Rejected)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "create appropriate notification for rejected truce" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Rejected,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.newNotifications.loneElement) {
|
||||
case notification: NotificationC =>
|
||||
notification.details shouldBe NotificationDetails.TruceRejected(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
notification.affectedHeroIds shouldBe Vector(messengerHeroId)
|
||||
notification.deferred shouldBe true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"execute with resolution IMPRISON" should "update the faction with the imprisoned ambassador" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Imprisoned,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.changedFactions.loneElement) { case faction: ChangedFactionC =>
|
||||
faction.factionId shouldBe actingFactionId
|
||||
faction.removedIncomingDiplomacyOfferFactionIds shouldBe Vector(
|
||||
originatingFactionId
|
||||
)
|
||||
faction.newIncomingDiplomacyOffers shouldBe Vector(
|
||||
truceOffer.copy(status = Imprisoned)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "create appropriate notification for imprisoned ambassador" in {
|
||||
val result = ResolveTruceOfferCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = originatingFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
truceOffer = truceOffer,
|
||||
resolution = Imprisoned,
|
||||
availableOriginatingFactionIds = availableOriginatingFactionIds,
|
||||
availableResolutions = availableResolutions,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
inside(result) { case ar: ActionResultC =>
|
||||
inside(ar.newNotifications.loneElement) {
|
||||
case notification: NotificationC =>
|
||||
notification.details shouldBe NotificationDetails
|
||||
.TruceAmbassadorImprisoned(
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = messengerHeroId
|
||||
)
|
||||
notification.affectedHeroIds shouldBe Vector(messengerHeroId)
|
||||
notification.deferred shouldBe true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+165
-133
@@ -1,18 +1,9 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.SendSuppliesAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SendSuppliesSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.SENT_SUPPLIES
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.hero.Hero
|
||||
import net.eagle0.eagle.internal.province.{Neighbor, Province}
|
||||
import net.eagle0.eagle.internal.supplies.{MovingSupplies, Supplies}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplierImpl
|
||||
import net.eagle0.eagle.model.action_result.types.SentSuppliesResultType
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ChangedHeroC, StatDelta}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
SendSuppliesWisdomXp,
|
||||
@@ -21,7 +12,6 @@ import net.eagle0.eagle.library.settings.{
|
||||
VigorToConstitutionXpMultiplier,
|
||||
XpForStatBump
|
||||
}
|
||||
import net.eagle0.eagle.library.util.validations.TestingNoopValidator
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@@ -31,46 +21,17 @@ class SendSuppliesCommandTest
|
||||
with Matchers
|
||||
with BeforeAndAfterEach {
|
||||
|
||||
val actionResultProtoApplier = new ActionResultProtoApplierImpl(
|
||||
validator = TestingNoopValidator
|
||||
)
|
||||
|
||||
private val actingFactionId = 9
|
||||
private val actingHeroId = 15
|
||||
private val originProvinceId = 14
|
||||
private val originProvince: Province = Province(
|
||||
id = 14,
|
||||
neighbors = Vector(25, 26, 27).map(pid => Neighbor(provinceId = pid)),
|
||||
gold = 5000,
|
||||
food = 6000
|
||||
)
|
||||
|
||||
private val gameState = GameState(
|
||||
currentDate = Some(Date(year = 1501, month = 6)),
|
||||
randomSeed = 1L,
|
||||
provinces = Map(
|
||||
originProvinceId -> originProvince,
|
||||
25 -> Province().withId(25),
|
||||
26 -> Province().withId(26),
|
||||
27 -> Province().withId(27)
|
||||
),
|
||||
heroes = Map(15 -> Hero().withId(15).withConstitution(90).withVigor(70))
|
||||
)
|
||||
|
||||
private val availableCommand = SendSuppliesAvailableCommand(
|
||||
actingProvinceId = originProvinceId,
|
||||
availableHeroIds = Vector(12, 15, 18),
|
||||
goldAvailable = 2500,
|
||||
foodAvailable = 3500,
|
||||
availableDestinationProvinceIds = Vector(25, 26, 27)
|
||||
)
|
||||
|
||||
private val selectedCommand: SendSuppliesSelectedCommand =
|
||||
SendSuppliesSelectedCommand(
|
||||
gold = 1500,
|
||||
food = 2750,
|
||||
actingHeroId = 15,
|
||||
destinationProvinceId = 25
|
||||
)
|
||||
private val destinationProvinceId = 25
|
||||
private val availableDestinationProvinceIds = Vector(25, 26, 27)
|
||||
private val availableHeroIds = Vector(12, 15, 18)
|
||||
private val goldAvailable = 2500
|
||||
private val foodAvailable = 3500
|
||||
private val gold = 1500
|
||||
private val food = 2750
|
||||
private val currentRoundId = 0
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
TurnsToResolveShipment.setIntValue(1)
|
||||
@@ -85,9 +46,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withFood(-5)
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = -5,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -98,9 +66,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withFood(3501)
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = 3501,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -111,9 +86,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withGold(-3)
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = -3,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -124,9 +106,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withGold(2698)
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = 2698,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -137,9 +126,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withActingHeroId(19)
|
||||
actingHeroId = 19,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -150,9 +146,16 @@ class SendSuppliesCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SendSuppliesCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withDestinationProvinceId(4)
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = 4,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -160,109 +163,138 @@ class SendSuppliesCommandTest
|
||||
}
|
||||
|
||||
"execute" should "set the basics" in {
|
||||
val results = SendSuppliesCommand
|
||||
val result = SendSuppliesCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.immediateExecute
|
||||
|
||||
results should have size 1
|
||||
val result = results.head.actionResult
|
||||
result.`type` shouldBe SENT_SUPPLIES
|
||||
result.province should contain(originProvinceId)
|
||||
result.player should contain(actingFactionId)
|
||||
result.provinceActed should contain(originProvinceId)
|
||||
result.actionResultType shouldBe SentSuppliesResultType
|
||||
result.provinceId should contain(originProvinceId)
|
||||
result.actingFactionId should contain(actingFactionId)
|
||||
result.provinceIdActed should contain(originProvinceId)
|
||||
}
|
||||
|
||||
it should "add incoming supplies to the destination province" in {
|
||||
val resultState = SendSuppliesCommand
|
||||
it should "add incoming supplies to the destination province in the ActionResult" in {
|
||||
val result = SendSuppliesCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.gameState
|
||||
.immediateExecute
|
||||
|
||||
resultState.provinces(25) shouldBe Province()
|
||||
.withId(25)
|
||||
.withIncomingShipments(
|
||||
Vector(
|
||||
MovingSupplies(
|
||||
id = 1,
|
||||
factionId = actingFactionId,
|
||||
supplies = Some(Supplies(gold = 1500, food = 2750)),
|
||||
arrivalRound = 1,
|
||||
originProvinceId = Some(originProvinceId),
|
||||
destinationProvinceId = 25,
|
||||
suppliesLoss = 0.15
|
||||
)
|
||||
)
|
||||
)
|
||||
// Check that the destination province gets the moving supplies
|
||||
val destinationProvinceChange =
|
||||
result.changedProvinces.find(_.provinceId == destinationProvinceId)
|
||||
destinationProvinceChange should be(defined)
|
||||
|
||||
// Cast to concrete type to access newIncomingShipments
|
||||
val concreteChange =
|
||||
destinationProvinceChange.get.asInstanceOf[ChangedProvinceC]
|
||||
val incomingShipments = concreteChange.newIncomingShipments
|
||||
incomingShipments.should(have).size(1)
|
||||
|
||||
val movingSupplies = incomingShipments.head
|
||||
movingSupplies.factionId.shouldBe(actingFactionId)
|
||||
movingSupplies.supplies.gold.shouldBe(gold)
|
||||
movingSupplies.supplies.food.shouldBe(food)
|
||||
movingSupplies.arrivalRound.shouldBe(
|
||||
currentRoundId + TurnsToResolveShipment.intValue
|
||||
)
|
||||
movingSupplies.originProvinceId.should(contain(originProvinceId))
|
||||
movingSupplies.destinationProvinceId.shouldBe(destinationProvinceId)
|
||||
movingSupplies.suppliesLoss.shouldBe(ShipSuppliesLoss.doubleValue)
|
||||
}
|
||||
|
||||
it should "remove the supplies from the origin province in the ActionResult" in {
|
||||
val result = SendSuppliesCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.changedProvinces should contain(
|
||||
ChangedProvince(
|
||||
id = originProvinceId,
|
||||
ChangedProvinceC(
|
||||
provinceId = originProvinceId,
|
||||
goldDelta = Some(-1500),
|
||||
foodDelta = Some(-2750)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
it should "remove the supplies from the origin province" in {
|
||||
val resultState = SendSuppliesCommand
|
||||
it should "indicate the province has acted in the ActionResult" in {
|
||||
val result = SendSuppliesCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.gameState
|
||||
.immediateExecute
|
||||
|
||||
resultState.provinces(originProvinceId) shouldBe originProvince.update(
|
||||
_.food := originProvince.food - 2750,
|
||||
_.gold := originProvince.gold - 1500,
|
||||
_.hasActed := true,
|
||||
_.lastCommand := selectedCommand
|
||||
)
|
||||
// The framework will mark the province as having acted based on provinceIdActed
|
||||
result.provinceIdActed should contain(originProvinceId)
|
||||
result.actingHeroId should contain(actingHeroId)
|
||||
}
|
||||
|
||||
it should "cost vigor and give xp for the actor" in {
|
||||
val result = SendSuppliesCommand
|
||||
.make(
|
||||
actingFactionId = actingFactionId,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHeroId,
|
||||
originProvinceId = originProvinceId,
|
||||
destinationProvinceId = destinationProvinceId,
|
||||
availableDestinationProvinceIds = availableDestinationProvinceIds,
|
||||
availableHeroIds = availableHeroIds,
|
||||
goldAvailable = goldAvailable,
|
||||
foodAvailable = foodAvailable,
|
||||
goldSent = gold,
|
||||
foodSent = food,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
.execute(actionResultProtoApplier)
|
||||
.head
|
||||
.actionResult
|
||||
.immediateExecute
|
||||
|
||||
result.changedHeroes should contain(
|
||||
ChangedHero(
|
||||
id = 15,
|
||||
vigor = VigorDelta(-18),
|
||||
wisdomXpDelta = Some(15),
|
||||
constitutionXpDelta = Some(4)
|
||||
ChangedHeroC(
|
||||
heroId = 15,
|
||||
vigorChange = StatDelta(-18),
|
||||
wisdomXpDelta = Some(15)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+88
-97
@@ -1,23 +1,24 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.ProtoMatchers.equalProto
|
||||
import net.eagle0.eagle.api.available_command.StartEpidemicAvailableCommand
|
||||
import net.eagle0.eagle.api.available_command.StartEpidemicAvailableCommand.StartEpidemicOptions
|
||||
import net.eagle0.eagle.api.selected_command.StartEpidemicSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.EPIDEMIC_STARTED
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.deferred_change.EpidemicStarted
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
StartEpidemicCharismaXp,
|
||||
StartEpidemicVigorDelta
|
||||
}
|
||||
import net.eagle0.eagle.{HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.types.EpidemicStartedResultType
|
||||
import net.eagle0.eagle.model.state.province.DeferredChange
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside.inside
|
||||
import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
|
||||
class StartEpidemicCommandTest
|
||||
extends AnyFlatSpec
|
||||
@@ -26,51 +27,30 @@ class StartEpidemicCommandTest
|
||||
|
||||
behavior of "StartEpidemicCommandTest"
|
||||
|
||||
val charismaXpDelta: Int = 25
|
||||
val vigorDelta: Int = -40
|
||||
private val charismaXpDelta: Int = 25
|
||||
private val vigorDelta: Int = -40
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
StartEpidemicVigorDelta.setDoubleValue(vigorDelta)
|
||||
StartEpidemicCharismaXp.setIntValue(charismaXpDelta)
|
||||
}
|
||||
|
||||
val gameState: GameState = GameState()
|
||||
|
||||
val actingPid = 17
|
||||
val actingFid = 2
|
||||
val availableCommand: StartEpidemicAvailableCommand =
|
||||
StartEpidemicAvailableCommand(
|
||||
actingProvinceId = actingPid,
|
||||
availableHeroIds = Vector(10, 20, 30),
|
||||
options = Vector(
|
||||
StartEpidemicOptions(
|
||||
targetProvinceId = 17
|
||||
),
|
||||
StartEpidemicOptions(
|
||||
targetProvinceId = 4
|
||||
),
|
||||
StartEpidemicOptions(
|
||||
targetProvinceId = 19
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actingHid: HeroId = 10
|
||||
val targetedPid: ProvinceId = 19
|
||||
|
||||
private val selectedCommand: StartEpidemicSelectedCommand =
|
||||
StartEpidemicSelectedCommand(
|
||||
selectedProvinceId = targetedPid,
|
||||
actingHeroId = actingHid
|
||||
)
|
||||
private val actingPid: ProvinceId = 17
|
||||
private val actingFid: FactionId = 2
|
||||
private val availableHeroIds = Vector[HeroId](10, 20, 30)
|
||||
private val availableTargetProvinceIds = Vector[ProvinceId](17, 4, 19)
|
||||
private val actingHid: HeroId = 10
|
||||
private val targetedPid: ProvinceId = 19
|
||||
|
||||
"make" should "throw if the hero was not among options" in {
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
StartEpidemicCommand.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand.withActingHeroId(11)
|
||||
actingHeroId = 11,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
}
|
||||
|
||||
@@ -81,12 +61,11 @@ class StartEpidemicCommandTest
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
StartEpidemicCommand.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = StartEpidemicSelectedCommand(
|
||||
selectedProvinceId = 6,
|
||||
actingHeroId = actingHid
|
||||
)
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = 6,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,84 +73,96 @@ class StartEpidemicCommandTest
|
||||
}
|
||||
|
||||
"immediateExecute" should "set the basics" in {
|
||||
val result = StartEpidemicCommand
|
||||
val action = StartEpidemicCommand
|
||||
.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.`type` shouldBe EPIDEMIC_STARTED
|
||||
result.leader shouldBe Some(actingHid)
|
||||
result.province shouldBe Some(actingPid)
|
||||
inside(action.immediateExecute) { case ar: ActionResultC =>
|
||||
ar.actionResultType shouldBe EpidemicStartedResultType
|
||||
ar.actingHeroId shouldBe Some(actingHid)
|
||||
ar.provinceId shouldBe Some(actingPid)
|
||||
}
|
||||
}
|
||||
|
||||
it should "give charisma XP to the actor" in {
|
||||
val result = StartEpidemicCommand
|
||||
val action = StartEpidemicCommand
|
||||
.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.changedHeroes should have size 1
|
||||
result.changedHeroes.head.id shouldBe actingHid
|
||||
result.changedHeroes.head.charismaXpDelta shouldBe Some(charismaXpDelta)
|
||||
inside(action.immediateExecute) { case ar: ActionResultC =>
|
||||
inside(ar.changedHeroes.loneElement) { case hero: ChangedHeroC =>
|
||||
hero.heroId shouldBe actingHid
|
||||
hero.charismaXpDelta shouldBe Some(charismaXpDelta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "cost vigor for the actor" in {
|
||||
val result = StartEpidemicCommand
|
||||
val action = StartEpidemicCommand
|
||||
.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.changedHeroes should have size 1
|
||||
result.changedHeroes.head.id shouldBe actingHid
|
||||
result.changedHeroes.head.vigor shouldBe VigorDelta(vigorDelta)
|
||||
inside(action.immediateExecute) { case ar: ActionResultC =>
|
||||
inside(ar.changedHeroes.loneElement) { case hero: ChangedHeroC =>
|
||||
hero.heroId shouldBe actingHid
|
||||
hero.vigorChange shouldBe StatDelta(vigorDelta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "mark the province as acted" in {
|
||||
val result = StartEpidemicCommand
|
||||
val action = StartEpidemicCommand
|
||||
.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.provinceActed shouldBe Some(actingPid)
|
||||
inside(action.immediateExecute) { case ar: ActionResultC =>
|
||||
ar.provinceIdActed shouldBe Some(actingPid)
|
||||
}
|
||||
}
|
||||
|
||||
it should "add an epidemic to the target province" in {
|
||||
val result = StartEpidemicCommand
|
||||
val action = StartEpidemicCommand
|
||||
.make(
|
||||
actingFactionId = actingFid,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = StartEpidemicSelectedCommand(
|
||||
actingHeroId = actingHid,
|
||||
selectedProvinceId = targetedPid
|
||||
)
|
||||
actingHeroId = actingHid,
|
||||
actingProvinceId = actingPid,
|
||||
targetProvinceId = targetedPid,
|
||||
availableHeroIds = availableHeroIds,
|
||||
availableTargetProvinceIds = availableTargetProvinceIds
|
||||
)
|
||||
.immediateExecute
|
||||
|
||||
result.changedProvinces should have size 1
|
||||
result.changedProvinces.head should equalProto(
|
||||
ChangedProvince(
|
||||
id = targetedPid,
|
||||
addedDeferredChange = EpidemicStarted(
|
||||
responsibleFaction = actingFid
|
||||
)
|
||||
)
|
||||
)
|
||||
inside(action.immediateExecute) { case ar: ActionResultC =>
|
||||
inside(ar.changedProvinces.loneElement) {
|
||||
case province: ChangedProvinceC =>
|
||||
province.provinceId shouldBe targetedPid
|
||||
province.newDeferredChange shouldBe Some(
|
||||
DeferredChange.EpidemicStarted(responsibleFaction = actingFid)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+128
-144
@@ -1,36 +1,23 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.ProtoMatchers.equalProto
|
||||
import net.eagle0.eagle.api.available_command.SwearBrotherhoodAvailableCommand
|
||||
import net.eagle0.eagle.api.available_command.SwearBrotherhoodAvailableCommand.HeroAndBackstory
|
||||
import net.eagle0.eagle.api.selected_command.SwearBrotherhoodSelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_notification_details.Notification.Llm
|
||||
import net.eagle0.eagle.common.action_result_notification_details.{
|
||||
Notification,
|
||||
SwearBrotherhoodDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.SWEAR_BROTHERHOOD
|
||||
import net.eagle0.eagle.internal.changed_faction.ChangedFaction
|
||||
import net.eagle0.eagle.internal.changed_hero.ChangedHero
|
||||
import net.eagle0.eagle.internal.event_for_hero_backstory.{
|
||||
EventForHeroBackstory,
|
||||
SworeBrotherhoodBackstoryEvent
|
||||
}
|
||||
import net.eagle0.eagle.internal.faction.Faction
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.hero.Hero
|
||||
import net.eagle0.eagle.common.hero_backstory_version.BackstoryVersion
|
||||
import net.eagle0.eagle.internal.generated_text_request.{
|
||||
GeneratedTextRequest,
|
||||
SwearBrotherhoodMessage
|
||||
}
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
AcceptBrotherhoodCharismaXp,
|
||||
AmbitionAgainstDiscordForSwearBrotherhoodFactor,
|
||||
SwearBrotherhoodCharismaXp,
|
||||
ThresholdForSwearBrotherhood
|
||||
SwearBrotherhoodCharismaXp
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC,
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.SwearBrotherhoodMessage
|
||||
import net.eagle0.eagle.model.action_result.types.SwearBrotherhoodResultType
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.hero.SworeBrotherhoodBackstoryEvent
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@@ -40,97 +27,100 @@ class SwearBrotherhoodCommandTest
|
||||
with Matchers
|
||||
with BeforeAndAfterEach {
|
||||
override def beforeEach(): Unit = {
|
||||
AmbitionAgainstDiscordForSwearBrotherhoodFactor.setDoubleValue(1.0)
|
||||
ThresholdForSwearBrotherhood.setIntValue(50)
|
||||
SwearBrotherhoodCharismaXp.setIntValue(75)
|
||||
AcceptBrotherhoodCharismaXp.setIntValue(50)
|
||||
}
|
||||
|
||||
private val availableCommand = SwearBrotherhoodAvailableCommand(
|
||||
availableHeroes = Vector(5, 6, 7).map(hid =>
|
||||
HeroAndBackstory(heroId = hid, backstoryTextId = "backstoryUpdate-6-0-1")
|
||||
),
|
||||
actingProvinceId = 17
|
||||
)
|
||||
// Test data for new protoless API
|
||||
private val actingFactionId: FactionId = 3
|
||||
private val actingProvinceId: ProvinceId = 17
|
||||
private val newBrotherHeroId: HeroId = 6
|
||||
private val factionHeadHeroId: HeroId = 101
|
||||
private val availableHeroIds = Vector[HeroId](5, 6, 7)
|
||||
private val currentDate = Date(year = 1500, month = Date.Month.January)
|
||||
private val currentRoundId: RoundId = 0
|
||||
private val gameId: GameId = 0xcafe
|
||||
|
||||
private val goodSelectedCommand = SwearBrotherhoodSelectedCommand(
|
||||
newBrotherHeroId = 6
|
||||
)
|
||||
|
||||
private val faction =
|
||||
Faction(id = 3, factionHeadId = 101, leaders = Vector(101, 105))
|
||||
|
||||
private val gameState = GameState(
|
||||
gameId = 0xcafe,
|
||||
factions = Map(
|
||||
3 -> faction
|
||||
),
|
||||
heroes = Map(
|
||||
6 -> Hero(
|
||||
id = 6,
|
||||
ambition = 60,
|
||||
backstoryVersions = Vector(BackstoryVersion("backstoryUpdate-6-0-1"))
|
||||
),
|
||||
101 -> Hero(id = 101)
|
||||
)
|
||||
)
|
||||
|
||||
"immediateExecute" should "throw if the selected brother is not among the options" in {
|
||||
val badSelectedCommand = goodSelectedCommand.withNewBrotherHeroId(9)
|
||||
"make" should "throw if the selected brother is not among the options" in {
|
||||
val invalidBrotherHeroId: HeroId = 9
|
||||
|
||||
val ex = the[EagleCommandException] thrownBy {
|
||||
SwearBrotherhoodCommand.make(
|
||||
actingFactionId = 3,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = badSelectedCommand
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = invalidBrotherHeroId,
|
||||
availableHeroIds = availableHeroIds,
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
}
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Tried to swear brotherhood with 9, but options were Vector(5, 6, 7)"
|
||||
}
|
||||
|
||||
"immediateExecute with an ambitious hero" should "set the basics" in {
|
||||
val result = SwearBrotherhoodCommand
|
||||
.make(
|
||||
actingFactionId = 3,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = goodSelectedCommand
|
||||
)
|
||||
.immediateExecute
|
||||
"immediateExecute" should "set the basic action result fields" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
availableHeroIds = availableHeroIds,
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
result.`type` shouldBe SWEAR_BROTHERHOOD
|
||||
result.player should contain(3)
|
||||
result.province should contain(17)
|
||||
result.provinceActed should contain(17)
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
actionResult.actionResultType.shouldBe(SwearBrotherhoodResultType)
|
||||
actionResult.actingFactionId.should(contain(actingFactionId))
|
||||
actionResult.actingHeroId.should(contain(newBrotherHeroId))
|
||||
actionResult.provinceId.should(contain(actingProvinceId))
|
||||
actionResult.provinceIdActed.should(contain(actingProvinceId))
|
||||
}
|
||||
|
||||
it should "add the new brother to the faction leaders" in {
|
||||
val result = SwearBrotherhoodCommand
|
||||
.make(
|
||||
actingFactionId = 3,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = goodSelectedCommand
|
||||
)
|
||||
.immediateExecute
|
||||
it should "add the new brother to faction leaders and give charisma XP" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
availableHeroIds = availableHeroIds,
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
result.changedFactions shouldBe Vector(
|
||||
ChangedFaction(id = faction.id, addedLeaders = Vector(6))
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
actionResult.changedFactions.shouldBe(
|
||||
Vector(
|
||||
ChangedFactionC(
|
||||
factionId = actingFactionId,
|
||||
newLeaderHeroIds = Vector(newBrotherHeroId)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
result.changedHeroes shouldBe Vector(
|
||||
ChangedHero(id = 101, charismaXpDelta = Some(75)),
|
||||
ChangedHero(
|
||||
id = 6,
|
||||
charismaXpDelta = Some(50),
|
||||
newBackstoryEvents = Vector(
|
||||
EventForHeroBackstory(
|
||||
date = gameState.currentDate,
|
||||
details = SworeBrotherhoodBackstoryEvent(
|
||||
sworeWithFactionId = 3,
|
||||
sworeInProvinceId = 17
|
||||
actionResult.changedHeroes.shouldBe(
|
||||
Vector(
|
||||
ChangedHeroC(
|
||||
heroId = factionHeadHeroId,
|
||||
charismaXpDelta = Some(SwearBrotherhoodCharismaXp.intValue)
|
||||
),
|
||||
ChangedHeroC(
|
||||
heroId = newBrotherHeroId,
|
||||
charismaXpDelta = Some(AcceptBrotherhoodCharismaXp.intValue),
|
||||
newEventsForHeroBackstory = Vector(
|
||||
SworeBrotherhoodBackstoryEvent(
|
||||
date = currentDate,
|
||||
sworeWithFactionId = actingFactionId,
|
||||
sworeInProvinceId = actingProvinceId
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -138,58 +128,52 @@ class SwearBrotherhoodCommandTest
|
||||
)
|
||||
}
|
||||
|
||||
it should "include the notification details" in {
|
||||
val result = SwearBrotherhoodCommand
|
||||
.make(
|
||||
actingFactionId = 3,
|
||||
gameState = gameState,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = goodSelectedCommand
|
||||
)
|
||||
.immediateExecute
|
||||
it should "create notification and LLM request for the brotherhood event" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
availableHeroIds = availableHeroIds,
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
|
||||
result.newDeferredNotification.get should equalProto(
|
||||
Notification(
|
||||
details = SwearBrotherhoodDetails(
|
||||
factionId = faction.id,
|
||||
newBrotherHeroId = 6
|
||||
),
|
||||
llm = Llm.LlmId("0 3 swear brotherhood 6")
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
val expectedLlmId =
|
||||
s"${currentRoundId} swear brotherhood ${newBrotherHeroId}"
|
||||
|
||||
actionResult.newNotifications.shouldBe(
|
||||
Vector(
|
||||
NotificationC(
|
||||
details = NotificationDetails.SwearBrotherhood(
|
||||
factionId = actingFactionId,
|
||||
newBrotherHeroId = newBrotherHeroId
|
||||
),
|
||||
affectedProvinceIds = Vector(actingProvinceId),
|
||||
affectedHeroIds = Vector(newBrotherHeroId, factionHeadHeroId),
|
||||
llm = NotificationT.Llm.Id(expectedLlmId),
|
||||
deferred = true
|
||||
)
|
||||
)
|
||||
)
|
||||
result.newGeneratedTextRequests should have size 1
|
||||
result.newGeneratedTextRequests.head should equalProto(
|
||||
GeneratedTextRequest(
|
||||
id = "0 3 swear brotherhood 6",
|
||||
eagleGameId = 0xcafe,
|
||||
details = SwearBrotherhoodMessage(
|
||||
factionId = faction.id,
|
||||
swornBrotherHeroId = 6
|
||||
|
||||
actionResult.newGeneratedTextRequests.shouldBe(
|
||||
Vector(
|
||||
SwearBrotherhoodMessage(
|
||||
requestId = expectedLlmId,
|
||||
eagleGameId = gameId,
|
||||
factionId = actingFactionId,
|
||||
swornBrotherHeroId = newBrotherHeroId
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// "immediateExecute with a discordant hero" should "not set any changed factions or heroes" in {
|
||||
// val result = SwearBrotherhoodCommand
|
||||
// .make(
|
||||
// gameState = gameState.update(
|
||||
// _.heroes(6).modify(
|
||||
// _.withIntegrity(100).withBravery(100).withGregariousness(100)
|
||||
// )
|
||||
// ),
|
||||
// availableCommand = availableCommand,
|
||||
// selectedCommand = goodSelectedCommand
|
||||
// )
|
||||
// .immediateExecute
|
||||
//
|
||||
// result.`type` shouldBe FAILED_SWEAR_BROTHERHOOD
|
||||
// result.player should contain(3)
|
||||
// result.province should contain(17)
|
||||
// result.provinceActed should contain(17)
|
||||
//
|
||||
// result.changedFactions shouldBe empty
|
||||
//
|
||||
// result.changedHeroes shouldBe empty
|
||||
// }
|
||||
// Note: Hero acceptance logic temporarily simplified during migration
|
||||
// Currently accepts() always returns true - will be re-implemented with proper domain models
|
||||
}
|
||||
|
||||
+29
-7
@@ -1,11 +1,7 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionType
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId.{
|
||||
LIGHT_INFANTRY,
|
||||
LONGBOWMEN
|
||||
}
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
ActionVigorCost,
|
||||
@@ -64,10 +60,36 @@ class TrainCommandTest
|
||||
)
|
||||
|
||||
private val easyType =
|
||||
BattalionType(typeId = LIGHT_INFANTRY, trainingDifficulty = 1.0)
|
||||
BattalionType(
|
||||
typeId = LightInfantry,
|
||||
name = "Light Infantry",
|
||||
capacity = 1000,
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = false,
|
||||
baseCost = 1.0,
|
||||
monthlyFoodCost = 0.5,
|
||||
baseArmamentCostPerTroop = 0.02,
|
||||
trainingDifficulty = 1.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 0
|
||||
)
|
||||
|
||||
private val difficultType =
|
||||
BattalionType(typeId = LONGBOWMEN, trainingDifficulty = 5.0)
|
||||
BattalionType(
|
||||
typeId = Longbowmen,
|
||||
name = "Longbowmen",
|
||||
capacity = 800,
|
||||
allowsCasting = false,
|
||||
allowsStealth = false,
|
||||
alwaysArcheryCapable = true,
|
||||
baseCost = 2.0,
|
||||
monthlyFoodCost = 1.0,
|
||||
baseArmamentCostPerTroop = 0.03,
|
||||
trainingDifficulty = 5.0,
|
||||
minimumAgriculture = 0,
|
||||
minimumEconomy = 1
|
||||
)
|
||||
|
||||
private val battalionTypes = Vector(easyType, difficultType)
|
||||
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ChangedHeroC,
|
||||
NotificationC
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT.{
|
||||
QuestFailedMessage,
|
||||
QuestFulfilledMessage
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user