mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 11:55:42 +00:00
Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d8f05ef99 | ||
|
|
846d0e85aa | ||
|
|
3135265913 | ||
|
|
974715cf8f | ||
|
|
6f01df5a47 | ||
|
|
cb750fa0c8 | ||
|
|
9696490ec8 | ||
|
|
e7b64040a3 | ||
|
|
4a12dc852c | ||
|
|
e9ab085ce6 | ||
|
|
babd2dd286 | ||
|
|
fcab1cb9e4 | ||
|
|
a995cbbece | ||
|
|
6dce8624f3 | ||
|
|
c060ec92bd | ||
|
|
77c315dd04 | ||
|
|
85823be558 | ||
|
|
790a54d3a3 | ||
|
|
686a27571d | ||
|
|
df9993eb9e | ||
|
|
d269efb18b | ||
|
|
7fe998564e | ||
|
|
ef0ea28f2b | ||
|
|
c2d38fcaf4 | ||
|
|
19f54545c1 | ||
|
|
5b29ff40bc | ||
|
|
dc09ae768a | ||
|
|
ecd652d8ef | ||
|
|
27f2f07e8f | ||
|
|
21117aff42 | ||
|
|
8034474edc | ||
|
|
4b1cf06b5a | ||
|
|
fc56b5dde9 | ||
|
|
86e2212511 | ||
|
|
446d483d24 | ||
|
|
055449043f | ||
|
|
1d60e186f4 | ||
|
|
51479e9c75 | ||
|
|
ade98d20cd | ||
|
|
7820e63fe9 | ||
|
|
06f24631ff | ||
|
|
996a53b9d0 |
@@ -178,4 +178,6 @@ 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
|
||||
- *ALWAYS ALWAYS* run "bazel run gazelle" after any change that modifies a BUILD.bazel file
|
||||
+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,293 @@
|
||||
# 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-16):
|
||||
- **Total Commands Analyzed:** 41
|
||||
- **Commands Fully Migrated (No Protobuf):** 41 (100%) ✅
|
||||
- **Commands Still Using Protobuf:** 0 (0%) ✅
|
||||
- **Total Actions Analyzed:** 48
|
||||
- **Actions Fully Migrated (No Protobuf):** 4 (8.3%)
|
||||
- **Actions Partially Migrated:** 20 (41.7%)
|
||||
- **Actions Still Using Protobuf:** 24 (50%)
|
||||
- **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
|
||||
|
||||
### ✅ Fully Migrated Actions (No Protobuf Dependencies)
|
||||
|
||||
These actions have been successfully migrated to use Scala models only:
|
||||
|
||||
| File | Base Class | Notes |
|
||||
|------|------------|-------|
|
||||
| HeroBackstoryUpdateAction.scala | ProtolessSequentialResultsAction | Processes hero backstory updates with LLM integration |
|
||||
| ProvinceHeldAction.scala | ProtolessSimpleAction | Uses specific components (gameId, currentRoundId, defendingProvince, etc.) instead of full GameState |
|
||||
| UnaffiliatedHeroAppearedAction.scala | ProtolessSimpleAction | Handles unaffiliated hero appearance with name generation |
|
||||
| WithdrawnArmiesReturnHomeAction.scala | ProtolessSequentialResultsAction | Manages army withdrawal and return mechanics |
|
||||
|
||||
### 🔄 Actions Partially Migrated (Using Protoless Base Classes)
|
||||
|
||||
These actions use protoless base classes but still have some protobuf dependencies:
|
||||
|
||||
| File | Model Usage | Notes |
|
||||
|------|-------------|-------|
|
||||
| CheckForFactionChangesAction.scala | ProtolessSequentialResultsAction | Still has some protobuf dependencies |
|
||||
| CheckForFailedQuestsAction.scala | ProtolessSequentialResultsAction | Depends on `unaffiliated_hero_quest_scala_proto` |
|
||||
| CheckForFulfilledQuestsAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndAttackDecisionPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndBattleAftermathPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllDecisionPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndPlayerCommandsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndUnaffiliatedHeroActionsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| EndVassalCommandsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| FreeForAllDrawAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets |
|
||||
| FriendlyMoveAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets |
|
||||
| PerformUncontestedConquestAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| ProvinceConqueredAction.scala | ProtolessSimpleAction | Depends on `common_unit_scala_proto` |
|
||||
| SafePassageArmiesProceedAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| ShipmentArrivedAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets |
|
||||
| TruceTurnBackPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets |
|
||||
| UnaffiliatedHeroRejoinedAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets |
|
||||
| WonFreeForAllAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets |
|
||||
|
||||
### ❌ Actions Still Using Protobuf (Not Yet Using Protoless Base Classes)
|
||||
|
||||
| File | Notes |
|
||||
|------|-------|
|
||||
| ChronicleEventGenerator.scala | Depends on multiple protobuf targets |
|
||||
| EndBattleRequestPhaseAction.scala | Depends on `diplomacy_offer_status_scala_proto` |
|
||||
| EndBattleResolutionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndDefenseDecisionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndDiplomacyResolutionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllBattleRequestPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndFreeForAllBattleResolutionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndHandleRiotsPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndPleaseRecruitMePhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| EndProvinceMoveResolutionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| NewRoundAction.scala | Depends on multiple protobuf targets |
|
||||
| NewYearAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformFoodConsumptionPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformForcedTurnBackAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformHeroDeparturesAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformHostileArmySetupAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformProvinceEventsAction.scala | Depends on `province_event_scala_proto` |
|
||||
| PerformProvinceMoveResolutionAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformReconResolutionAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformUnaffiliatedHeroesAction.scala | Depends on `unaffiliated_hero_quest_scala_proto` |
|
||||
| PerformVassalCommandsPhaseAction.scala | Depends on multiple protobuf targets |
|
||||
| PerformVassalDefenseDecisionsAction.scala | Depends on multiple protobuf targets |
|
||||
| PrisonerEscapeAction.scala | Depends on `game_state_scala_proto` |
|
||||
| PrisonerExchangeAction.scala | Depends on multiple protobuf targets |
|
||||
| RequestBattlesAction.scala | Depends on multiple protobuf targets |
|
||||
| RequestFreeForAllBattlesAction.scala | Depends on multiple protobuf targets |
|
||||
| ResolveBattleAction.scala | Depends on `shardok_internal_interface_scala_grpc` |
|
||||
| UnaffiliatedHeroMovedAction.scala | Depends on multiple protobuf targets |
|
||||
| UnaffiliatedHeroesChangedAction.scala | Depends on multiple protobuf targets |
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
✅ **ALL COMMANDS FULLY MIGRATED** (100% - 41/41 commands)
|
||||
|
||||
All 41 commands in the codebase have been successfully migrated to use Scala models only, with no protobuf dependencies. This includes:
|
||||
|
||||
- **Simple Actions**: Use `ProtolessSimpleAction` base class
|
||||
- **Random Actions**: Use `ProtolessRandomSimpleAction` base class
|
||||
- **Complex Domain Models**: Successfully integrated with LLM systems, diplomacy, quest fulfillment, and state management
|
||||
- **Complete Type Safety**: All commands now use type-safe Scala domain models
|
||||
|
||||
**Key Migration Achievements:**
|
||||
- ✅ All military commands (ArmTroops, Train, Organize, etc.)
|
||||
- ✅ All diplomacy commands (Resolve Alliance/Truce/Ransom offers, etc.)
|
||||
- ✅ All LLM-integrated commands (backstory generation, diplomacy resolution)
|
||||
- ✅ All quest and event commands
|
||||
- ✅ Final remaining command (FreeForAllDecisionCommand) migrated
|
||||
|
||||
---
|
||||
|
||||
## 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:**
|
||||
- ✅ **100% of commands fully migrated** (41/41) 🎉
|
||||
- ✅ **All diplomacy helpers use Scala models**
|
||||
- ✅ **All protoless base classes available**
|
||||
- ✅ **ALL command migration completed**
|
||||
|
||||
**Completed 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 **COMPLETED**
|
||||
- ✅ **95% target:** Complete diplomacy migration **COMPLETED**
|
||||
- ✅ **100% target:** Migrate final remaining command (FreeForAllDecisionCommand) **COMPLETED**
|
||||
|
||||
### 🎯 Action Migration Progress
|
||||
|
||||
**Migration Statistics:**
|
||||
- 4/48 Actions fully migrated (8.3%)
|
||||
- 20/48 Actions using protoless base classes but with protobuf dependencies (41.7%)
|
||||
- 24/48 Actions still fully on protobuf (50%)
|
||||
|
||||
**Successfully Migrated Actions:**
|
||||
1. **HeroBackstoryUpdateAction** - LLM integration for hero backstories
|
||||
2. **ProvinceHeldAction** - Component-based design pattern (gameId, currentRoundId, specific models)
|
||||
3. **UnaffiliatedHeroAppearedAction** - Hero appearance with name generation
|
||||
4. **WithdrawnArmiesReturnHomeAction** - Army withdrawal mechanics
|
||||
|
||||
**Key Migration Patterns:**
|
||||
- ✅ Use specific components instead of full GameState (see ProvinceHeldAction)
|
||||
- ✅ Convert protobuf models to Scala models at Action boundaries
|
||||
- ✅ Update BUILD.bazel to remove protobuf dependencies
|
||||
- ✅ Update all call sites and tests
|
||||
|
||||
**Next Migration Candidates (Simple Actions with Protoless Base):**
|
||||
1. **FreeForAllDrawAction** - Already uses ProtolessSimpleAction
|
||||
2. **FriendlyMoveAction** - Already uses ProtolessSimpleAction
|
||||
3. **ShipmentArrivedAction** - Already uses ProtolessSimpleAction
|
||||
4. **WonFreeForAllAction** - Already uses ProtolessSimpleAction
|
||||
5. **ProvinceConqueredAction** - Already uses ProtolessSimpleAction, only needs `common_unit` 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-16 - Analysis based on BUILD.bazel dependencies and code review*
|
||||
@@ -1,5 +0,0 @@
|
||||
//src/test/scala/net/eagle0/eagle/ai:ai_client_utils_test ✓ FIXED
|
||||
//src/test/scala/net/eagle0/eagle/ai:faction_leader_province_ranker_test ✓ FIXED
|
||||
//src/test/scala/net/eagle0/eagle/ai:fix_leader_alone_command_selector_test ✓ FIXED
|
||||
//src/test/scala/net/eagle0/eagle/ai:invitation_command_selector_test ✓ FIXED
|
||||
//src/test/scala/net/eagle0/eagle/ai:mid_game_ai_client_test
|
||||
@@ -89,8 +89,8 @@ auto ContextFreeUnitValue(const Unit *unit) -> ScoreValue {
|
||||
break;
|
||||
}
|
||||
|
||||
const double battalionValue = battalionTypeMultiplier * (0.5 + armament / 100.0) *
|
||||
(0.5 + training / 100.0) * (0.5 + morale / 100.0) *
|
||||
const double battalionValue = battalionTypeMultiplier * (1.0 + armament / 100.0) *
|
||||
(1.0 + training / 100.0) * (0.5 + morale / 100.0) *
|
||||
unit->battalion().size();
|
||||
|
||||
const double heroValue =
|
||||
|
||||
@@ -8,7 +8,7 @@ import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
|
||||
object AIClientUtils {
|
||||
def extraHeroCount(pid: ProvinceId, fid: FactionId, gs: GameState): Int =
|
||||
(gs.provinces(pid.value).rulingFactionHeroIds.size - desiredHeroCount(
|
||||
(gs.provinces(pid).rulingFactionHeroIds.size - desiredHeroCount(
|
||||
pid,
|
||||
fid,
|
||||
gs
|
||||
@@ -16,7 +16,7 @@ object AIClientUtils {
|
||||
|
||||
def desiredHeroCount(pid: ProvinceId, fid: FactionId, gs: GameState): Int = {
|
||||
if LegacyFactionUtils.hostileNeighbors(pid, fid, gs).nonEmpty then 3
|
||||
else if gs.provinces(pid.value).support < 65 then 2
|
||||
else if gs.provinces(pid).support < 65 then 2
|
||||
else 1
|
||||
}
|
||||
|
||||
@@ -55,11 +55,8 @@ object AIClientUtils {
|
||||
originProvince = originProvince,
|
||||
destinationProvince = destinationProvince,
|
||||
availableHeroIds = availableHeroIds,
|
||||
factionLeaders = gs
|
||||
.factions(originProvince.rulingFactionId.get)
|
||||
.leaders
|
||||
.toVector
|
||||
.map(HeroId(_)),
|
||||
factionLeaders =
|
||||
gs.factions(originProvince.rulingFactionId.get).leaders.toVector,
|
||||
favorLeaders = favorLeaders
|
||||
),
|
||||
gs,
|
||||
@@ -74,21 +71,20 @@ object AIClientUtils {
|
||||
favorLeaders: Boolean
|
||||
): Vector[HeroId] = {
|
||||
val availableHeroes = availableHeroIds
|
||||
.map(hid => gs.heroes(hid.value))
|
||||
.map(gs.heroes)
|
||||
|
||||
if availableHeroes.size <= desiredCount then
|
||||
availableHeroes.map(h => HeroId(h.id))
|
||||
if availableHeroes.size <= desiredCount then availableHeroes.map(_.id)
|
||||
else
|
||||
availableHeroes
|
||||
.sortBy(hero =>
|
||||
(
|
||||
if favorLeaders then
|
||||
!LegacyFactionUtils.isFactionLeader(HeroId(hero.id), gs)
|
||||
else LegacyFactionUtils.isFactionLeader(HeroId(hero.id), gs),
|
||||
!LegacyFactionUtils.isFactionLeader(hero.id, gs)
|
||||
else LegacyFactionUtils.isFactionLeader(hero.id, gs),
|
||||
-LegacyHeroUtils.power(hero)
|
||||
)
|
||||
)
|
||||
.map(h => HeroId(h.id))
|
||||
.map(_.id)
|
||||
.take(desiredCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ object FactionLeaderProvinceRanker {
|
||||
): Ordering[Province] = Ordering.by((p: Province) =>
|
||||
ProvinceDistances.distanceThroughFriendliesOption(
|
||||
fromProvinceId,
|
||||
ProvinceId(p.id),
|
||||
p.id,
|
||||
factionId,
|
||||
gameState
|
||||
)
|
||||
@@ -76,7 +76,7 @@ object FactionLeaderProvinceRanker {
|
||||
LegacyFactionUtils
|
||||
.provinces(factionId, gameState)
|
||||
.sorted(ordering)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
def bestProvinceId(
|
||||
@@ -90,7 +90,7 @@ object FactionLeaderProvinceRanker {
|
||||
LegacyFactionUtils
|
||||
.provinces(factionId, gameState)
|
||||
.minOption(ordering)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
def bestProvinceId(
|
||||
@@ -106,7 +106,7 @@ object FactionLeaderProvinceRanker {
|
||||
LegacyFactionUtils
|
||||
.provinces(factionId, gameState)
|
||||
.minOption(ordering)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
def rankedProvinceIds(
|
||||
@@ -122,7 +122,7 @@ object FactionLeaderProvinceRanker {
|
||||
LegacyFactionUtils
|
||||
.provinces(factionId, gameState)
|
||||
.sorted(ordering)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
def bestSettlementPidForFactionLeader(
|
||||
@@ -133,7 +133,7 @@ object FactionLeaderProvinceRanker {
|
||||
val ordering = factionLeaderProvinceOrdering(
|
||||
factionId = factionId,
|
||||
gameState = gameState,
|
||||
fromProvinceId = ProvinceId(currentProvince.id)
|
||||
fromProvinceId = currentProvince.id
|
||||
)
|
||||
|
||||
LegacyFactionUtils
|
||||
@@ -141,7 +141,7 @@ object FactionLeaderProvinceRanker {
|
||||
.filter(ordering.lt(_, currentProvince))
|
||||
.filterNot(LegacyProvinceUtils.ruledByFactionLeader(_, gameState))
|
||||
.minOption(ordering)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
def bestSettlementPidForFactionLeader(
|
||||
@@ -151,7 +151,7 @@ object FactionLeaderProvinceRanker {
|
||||
): Option[ProvinceId] =
|
||||
bestSettlementPidForFactionLeader(
|
||||
factionId = factionId,
|
||||
currentProvince = gameState.provinces(currentProvinceId.value),
|
||||
currentProvince = gameState.provinces(currentProvinceId),
|
||||
gameState = gameState
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.eagle0.eagle.ai
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
AvailableCommand,
|
||||
MarchAvailableCommand
|
||||
@@ -30,9 +30,7 @@ object FixLeaderAloneCommandSelector {
|
||||
gameState
|
||||
.provinces(opmc.originProvinceId)
|
||||
.rulingFactionHeroIds
|
||||
.filterNot(hid =>
|
||||
LegacyFactionUtils.isFactionLeader(HeroId(hid), gameState)
|
||||
)
|
||||
.filterNot(LegacyFactionUtils.isFactionLeader(_, gameState))
|
||||
.size > 1
|
||||
)
|
||||
) { opmc => fr =>
|
||||
@@ -44,21 +42,18 @@ object FixLeaderAloneCommandSelector {
|
||||
.filter(_.rulingFactionHeroIds.size == 1)
|
||||
.filter(dest =>
|
||||
LegacyFactionUtils
|
||||
.isFactionLeader(
|
||||
HeroId(dest.rulingFactionHeroIds.head),
|
||||
gameState
|
||||
)
|
||||
.isFactionLeader(dest.rulingFactionHeroIds.head, gameState)
|
||||
)
|
||||
.map { destination =>
|
||||
fr.nextRandomElement(opmc.availableHeroIds)
|
||||
.map { hid =>
|
||||
CombatUnit(factionId = actingFactionId.value, heroId = hid)
|
||||
CombatUnit(factionId = actingFactionId, heroId = hid)
|
||||
}
|
||||
.map { combatUnit =>
|
||||
Some(
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(ac.actingProvinceId),
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
available = ac,
|
||||
selected = MarchSelectedCommand(
|
||||
gold = 0,
|
||||
|
||||
@@ -13,7 +13,7 @@ import net.eagle0.eagle.library.util.command_choice_helpers.{
|
||||
ProvinceGoldSurplusCalculator,
|
||||
TrustForDiplomacy
|
||||
}
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.library.settings.MinChanceForAIInvite
|
||||
|
||||
object InvitationCommandSelector {
|
||||
@@ -34,13 +34,13 @@ object InvitationCommandSelector {
|
||||
.filter { invitationOption =>
|
||||
TrustForDiplomacy.meetsConditionsForInvitation(
|
||||
actingFactionId = actingFactionId,
|
||||
targetFactionId = FactionId(invitationOption.targetFactionId),
|
||||
targetFactionId = invitationOption.targetFactionId,
|
||||
gameState = gameState
|
||||
)
|
||||
}
|
||||
.filter { invitationOption =>
|
||||
ProvinceGoldSurplusCalculator.provinceGoldSurplus(
|
||||
ProvinceId(diplomacyAvailableCommand.actingProvinceId),
|
||||
diplomacyAvailableCommand.actingProvinceId,
|
||||
gameState
|
||||
) >= invitationOption.goldCost
|
||||
}
|
||||
@@ -50,7 +50,7 @@ object InvitationCommandSelector {
|
||||
acceptanceChance =
|
||||
ResolveDiplomacyCommandSelector.invitationAcceptanceChance(
|
||||
actingFactionId,
|
||||
FactionId(invitationOption.targetFactionId),
|
||||
invitationOption.targetFactionId,
|
||||
gameState
|
||||
)
|
||||
)
|
||||
@@ -60,8 +60,7 @@ object InvitationCommandSelector {
|
||||
.map { iowc =>
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId =
|
||||
ProvinceId(diplomacyAvailableCommand.actingProvinceId),
|
||||
actingProvinceId = diplomacyAvailableCommand.actingProvinceId,
|
||||
available = diplomacyAvailableCommand,
|
||||
selected = DiplomacySelectedCommand(
|
||||
selectedOption = iowc.invitationOption,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.eagle0.eagle.ai
|
||||
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
MarchAvailableCommand,
|
||||
MarchCommandFromOneProvince
|
||||
@@ -32,7 +32,7 @@ object MarchTowardProvinceCommandChooser {
|
||||
ProvinceDistances
|
||||
.distanceThroughFriendliesOption(
|
||||
destinationProvinceId,
|
||||
ProvinceId(p.id),
|
||||
p.id,
|
||||
fid,
|
||||
gs
|
||||
)
|
||||
@@ -44,7 +44,7 @@ object MarchTowardProvinceCommandChooser {
|
||||
|
||||
bestCommand.flatMap { case (opmc, dest, _) =>
|
||||
internalRequire(
|
||||
ProvinceId(opmc.originProvinceId) != destinationProvinceId,
|
||||
opmc.originProvinceId != destinationProvinceId,
|
||||
s"Marching away from $destinationProvinceId in an effort to get to that province"
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ object MarchTowardProvinceCommandChooser {
|
||||
AIClientUtils.takenHeroIdsForMarchTowardFocus(
|
||||
originProvince = originProvince,
|
||||
destinationProvince = dest,
|
||||
availableHeroIds = opmc.availableHeroIds.toVector.map(HeroId(_)),
|
||||
availableHeroIds = opmc.availableHeroIds.toVector,
|
||||
favorLeaders = favorLeaders,
|
||||
gs = gs
|
||||
)
|
||||
@@ -72,38 +72,33 @@ object MarchTowardProvinceCommandChooser {
|
||||
val takenUnits = takenHeroIds
|
||||
.zipAll(
|
||||
takenBattalions.map(batt => Some(batt.id)),
|
||||
HeroId(0),
|
||||
0,
|
||||
None
|
||||
)
|
||||
.map { case (hid, bid) =>
|
||||
CombatUnit(
|
||||
factionId = fid.value,
|
||||
heroId = hid.value,
|
||||
battalionId = bid
|
||||
)
|
||||
CombatUnit(factionId = fid, heroId = hid, battalionId = bid)
|
||||
}
|
||||
|
||||
val foodToTake = 2 * LegacyBattalionUtils.monthlyConsumedFood(
|
||||
takenBattalions,
|
||||
gs.battalionTypes.toVector
|
||||
)
|
||||
val goldToTake = provinceGoldSurplus(ProvinceId(originProvince.id), gs)
|
||||
val goldToTake = provinceGoldSurplus(originProvince.id, gs)
|
||||
CommandSelection(
|
||||
actingFactionId = fid,
|
||||
actingProvinceId = ProvinceId(actingProvinceId),
|
||||
actingProvinceId = actingProvinceId,
|
||||
available = ac,
|
||||
selected = MarchSelectedCommand(
|
||||
marchingUnits = takenUnits, // Check the food cost here?
|
||||
destinationProvinceId = dest.id,
|
||||
originProvince = opmc.originProvinceId,
|
||||
gold = Math.min(goldToTake, opmc.goldAvailable),
|
||||
food = Math.min(foodToTake, opmc.foodAvailable),
|
||||
unknownFields = scalapb.UnknownFieldSet.empty
|
||||
food = Math.min(foodToTake, opmc.foodAvailable)
|
||||
),
|
||||
reason = if favorLeaders then
|
||||
s"marching leaders toward ${gs.provinces(destinationProvinceId.value).name}"
|
||||
s"marching leaders toward ${gs.provinces(destinationProvinceId).name}"
|
||||
else
|
||||
s"marching heroes toward ${gs.provinces(destinationProvinceId.value).name}"
|
||||
s"marching heroes toward ${gs.provinces(destinationProvinceId).name}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.eagle0.eagle.ai
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
AvailableCommand,
|
||||
ResolveAllianceOfferAvailableCommand,
|
||||
@@ -59,10 +59,10 @@ object ResolveDiplomacyCommandSelector {
|
||||
gameState = gameState,
|
||||
availableCommands = availableCommands,
|
||||
rankedChoosers = Vector[CommandChooser](
|
||||
resolveInvitationSelectedCommand,
|
||||
resolveAllianceOfferSelectedCommand,
|
||||
resolveBreakAllianceSelectedCommand,
|
||||
resolveTruceOfferSelectedCommand,
|
||||
resolveInvitationSelectedCommand _,
|
||||
resolveAllianceOfferSelectedCommand _,
|
||||
resolveBreakAllianceSelectedCommand _,
|
||||
resolveTruceOfferSelectedCommand _,
|
||||
resolveRansomOfferSelectedCommand _
|
||||
),
|
||||
functionalRandom = functionalRandom
|
||||
@@ -87,7 +87,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
Some(
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(0),
|
||||
actingProvinceId = 0,
|
||||
available = resolveInvitationAc,
|
||||
selected = resolveInviteSelection,
|
||||
reason = "resolving invitation"
|
||||
@@ -105,11 +105,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
val invitedFid = actingFactionId
|
||||
val bestInvitation = ac.invitations
|
||||
.maxBy(inv =>
|
||||
invitationAcceptanceChance(
|
||||
FactionId(inv.originatingFactionId),
|
||||
invitedFid,
|
||||
gs
|
||||
)
|
||||
invitationAcceptanceChance(inv.originatingFactionId, invitedFid, gs)
|
||||
)
|
||||
|
||||
internalRequire(
|
||||
@@ -127,7 +123,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
originatingFactionId = bestOriginatingFid,
|
||||
resolution =
|
||||
if 100.0 * roll < invitationAcceptanceChance(
|
||||
FactionId(bestOriginatingFid),
|
||||
bestOriginatingFid,
|
||||
invitedFid,
|
||||
gs
|
||||
)
|
||||
@@ -164,7 +160,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
Some(
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(0),
|
||||
actingProvinceId = 0,
|
||||
available = resolveTruceAc,
|
||||
selected = resolveTruceOfferSelection,
|
||||
reason = "resolving truce offer"
|
||||
@@ -182,11 +178,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
val actingFid = actingFactionId
|
||||
val bestOffer = ac.offers
|
||||
.maxBy(inv =>
|
||||
truceOfferAcceptanceChance(
|
||||
FactionId(inv.originatingFactionId),
|
||||
actingFid,
|
||||
gs
|
||||
)
|
||||
truceOfferAcceptanceChance(inv.originatingFactionId, actingFid, gs)
|
||||
)
|
||||
|
||||
internalRequire(
|
||||
@@ -204,7 +196,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
originatingFactionId = bestOriginatingFid,
|
||||
resolution =
|
||||
if 100.0 * roll < truceOfferAcceptanceChance(
|
||||
originatingFid = FactionId(bestOriginatingFid),
|
||||
originatingFid = bestOriginatingFid,
|
||||
targetFid = actingFid,
|
||||
gs = gs
|
||||
)
|
||||
@@ -236,7 +228,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
): Int = {
|
||||
// Always reject if the faction already has an alliance
|
||||
if gs
|
||||
.factions(targetFid.value)
|
||||
.factions(targetFid)
|
||||
.factionRelationships
|
||||
.exists(_.relationshipLevel == ALLY)
|
||||
then 0
|
||||
@@ -273,7 +265,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
resolveRansomAc =>
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(0),
|
||||
actingProvinceId = 0,
|
||||
available = resolveRansomAc,
|
||||
selected = selectionForResolveRansomOfferSelectedCommand(
|
||||
actingFactionId = actingFactionId,
|
||||
@@ -318,7 +310,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
Some(
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(0),
|
||||
actingProvinceId = 0,
|
||||
available = resolveAllianceAc,
|
||||
selected = resolveAllianceOfferSelection,
|
||||
reason = "resolving alliance offer"
|
||||
@@ -346,7 +338,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
Some(
|
||||
CommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ProvinceId(0),
|
||||
actingProvinceId = 0,
|
||||
available = resolveBreakAllianceAc,
|
||||
selected = resolveBreakAllianceSelection,
|
||||
reason = "resolving break alliance"
|
||||
@@ -364,11 +356,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
val actingFid = actingFactionId
|
||||
val bestOffer = ac.offers
|
||||
.maxBy(inv =>
|
||||
allianceOfferAcceptanceChance(
|
||||
FactionId(inv.originatingFactionId),
|
||||
actingFid,
|
||||
gs
|
||||
)
|
||||
allianceOfferAcceptanceChance(inv.originatingFactionId, actingFid, gs)
|
||||
)
|
||||
|
||||
internalRequire(
|
||||
@@ -386,7 +374,7 @@ object ResolveDiplomacyCommandSelector {
|
||||
originatingFactionId = bestOriginatingFid,
|
||||
resolution =
|
||||
if 100.0 * roll < allianceOfferAcceptanceChance(
|
||||
originatingFid = FactionId(bestOriginatingFid),
|
||||
originatingFid = bestOriginatingFid,
|
||||
targetFid = actingFid,
|
||||
gs = gs
|
||||
)
|
||||
|
||||
@@ -38,25 +38,24 @@ case class ClientTextStoreImpl(
|
||||
requestedAfterHistoryCount: Int
|
||||
): ClientTextStore = {
|
||||
internalRequire(
|
||||
pregenerated.getText(id.value).isEmpty,
|
||||
pregenerated.getText(id).isEmpty,
|
||||
s"Text with id $id is pregenerated"
|
||||
)
|
||||
|
||||
if completeTexts.contains(id.value) then {
|
||||
if completeTexts.contains(id) then {
|
||||
println(s"Text with id $id already exists")
|
||||
this
|
||||
} else if incompleteTexts.contains(id.value) then {
|
||||
} else if incompleteTexts.contains(id) then {
|
||||
println(s"Incomplete text with id $id already exists")
|
||||
this
|
||||
} else {
|
||||
copy(
|
||||
unrequestedTexts =
|
||||
unrequestedTexts + (id.value -> UnrequestedClientText(
|
||||
id = id,
|
||||
requestedAfterHistoryCount = requestedAfterHistoryCount,
|
||||
llmRequest = llmRequest
|
||||
)),
|
||||
accessibleTo = this.accessibleTo + (id.value -> accessibleTo),
|
||||
unrequestedTexts = unrequestedTexts + (id -> UnrequestedClientText(
|
||||
id = id,
|
||||
requestedAfterHistoryCount = requestedAfterHistoryCount,
|
||||
llmRequest = llmRequest
|
||||
)),
|
||||
accessibleTo = this.accessibleTo + (id -> accessibleTo),
|
||||
accessibleToIsSaved = false,
|
||||
incompleteTextsAreSaved = false
|
||||
)
|
||||
@@ -65,10 +64,10 @@ case class ClientTextStoreImpl(
|
||||
|
||||
def withMarkedRequested(id: ClientTextId): ClientTextStore =
|
||||
unrequestedTexts
|
||||
.get(id.value)
|
||||
.get(id)
|
||||
.map { unrequested =>
|
||||
copy(
|
||||
incompleteTexts = incompleteTexts + (id.value ->
|
||||
incompleteTexts = incompleteTexts + (id ->
|
||||
IncompleteClientText(
|
||||
id = id,
|
||||
partialText = "",
|
||||
@@ -76,7 +75,7 @@ case class ClientTextStoreImpl(
|
||||
requestedAfterHistoryCount =
|
||||
unrequested.requestedAfterHistoryCount
|
||||
)),
|
||||
unrequestedTexts = unrequestedTexts - id.value,
|
||||
unrequestedTexts = unrequestedTexts - id,
|
||||
incompleteTextsAreSaved = false
|
||||
)
|
||||
}
|
||||
@@ -88,7 +87,7 @@ case class ClientTextStoreImpl(
|
||||
|
||||
def withBypassed(id: ClientTextId): ClientTextStore =
|
||||
copy(
|
||||
unrequestedTexts = unrequestedTexts - id.value,
|
||||
unrequestedTexts = unrequestedTexts - id,
|
||||
incompleteTextsAreSaved = false
|
||||
)
|
||||
|
||||
@@ -96,18 +95,18 @@ case class ClientTextStoreImpl(
|
||||
pregenerated
|
||||
.getText(id)
|
||||
.orElse {
|
||||
completeTexts.get(id.value).map(_.text)
|
||||
completeTexts.get(id).map(_.text)
|
||||
}
|
||||
.map { text => TextGenerationSuccess(text) }
|
||||
.getOrElse {
|
||||
incompleteTexts
|
||||
.get(id.value)
|
||||
.get(id)
|
||||
.map { ict =>
|
||||
TextGenerationDependencyInProgress(ict.id, ict.text)
|
||||
}
|
||||
.getOrElse {
|
||||
unrequestedTexts
|
||||
.get(id.value)
|
||||
.get(id)
|
||||
.map { ut =>
|
||||
TextGenerationDependencyWaiting(ut.id)
|
||||
}
|
||||
@@ -123,19 +122,19 @@ case class ClientTextStoreImpl(
|
||||
complete: Boolean
|
||||
): ClientTextStoreWithUpdate = {
|
||||
internalRequire(
|
||||
!unrequestedTexts.contains(id.value),
|
||||
!unrequestedTexts.contains(id),
|
||||
s"Text with id $id is unrequested"
|
||||
)
|
||||
internalRequire(
|
||||
!completeTexts.contains(id.value),
|
||||
!completeTexts.contains(id),
|
||||
s"Text with id $id is already complete"
|
||||
)
|
||||
internalRequire(
|
||||
pregenerated.getText(id.value).isEmpty,
|
||||
pregenerated.getText(id).isEmpty,
|
||||
s"Text with id $id is pregenerated"
|
||||
)
|
||||
val update = incompleteTexts
|
||||
.get(id.value)
|
||||
.get(id)
|
||||
.map(t => t.append(newText))
|
||||
.getOrElse {
|
||||
throw new EagleInternalException(s"Text with id $id not found")
|
||||
@@ -150,8 +149,8 @@ case class ClientTextStoreImpl(
|
||||
|
||||
ClientTextStoreWithUpdate(
|
||||
copy(
|
||||
completeTexts = completeTexts + (id.value -> updatedText),
|
||||
incompleteTexts = incompleteTexts - id.value,
|
||||
completeTexts = completeTexts + (id -> updatedText),
|
||||
incompleteTexts = incompleteTexts - id,
|
||||
incompleteTextsAreSaved = false
|
||||
),
|
||||
updatedText
|
||||
@@ -159,7 +158,7 @@ case class ClientTextStoreImpl(
|
||||
} else {
|
||||
ClientTextStoreWithUpdate(
|
||||
copy(
|
||||
incompleteTexts = incompleteTexts + (id.value -> update),
|
||||
incompleteTexts = incompleteTexts + (id -> update),
|
||||
incompleteTextsAreSaved = false
|
||||
),
|
||||
update
|
||||
@@ -178,24 +177,22 @@ case class ClientTextStoreImpl(
|
||||
if updatedFactionIds == originalFactionIds then this
|
||||
else
|
||||
copy(
|
||||
accessibleTo = accessibleTo + (id.value -> updatedFactionIds),
|
||||
accessibleTo = accessibleTo + (id -> updatedFactionIds),
|
||||
accessibleToIsSaved = false
|
||||
)
|
||||
}
|
||||
|
||||
def withMovedBackToUnrequested(id: ClientTextId): ClientTextStore =
|
||||
incompleteTexts
|
||||
.get(id.value)
|
||||
.get(id)
|
||||
.map { incomplete =>
|
||||
copy(
|
||||
unrequestedTexts =
|
||||
unrequestedTexts + (id.value -> UnrequestedClientText(
|
||||
id = id,
|
||||
requestedAfterHistoryCount =
|
||||
incomplete.requestedAfterHistoryCount,
|
||||
llmRequest = incomplete.llmRequest
|
||||
)),
|
||||
incompleteTexts = incompleteTexts - id.value,
|
||||
unrequestedTexts = unrequestedTexts + (id -> UnrequestedClientText(
|
||||
id = id,
|
||||
requestedAfterHistoryCount = incomplete.requestedAfterHistoryCount,
|
||||
llmRequest = incomplete.llmRequest
|
||||
)),
|
||||
incompleteTexts = incompleteTexts - id,
|
||||
incompleteTextsAreSaved = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,9 +68,10 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types/base:action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//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/state/battalion",
|
||||
|
||||
@@ -20,6 +20,7 @@ import net.eagle0.eagle.library.actions.impl.command.{
|
||||
AvailableCommandTypeMap,
|
||||
CommandFactory
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ActionWithResultingState,
|
||||
RandomStateProtoSequencer
|
||||
@@ -28,7 +29,7 @@ import net.eagle0.eagle.library.util.EagleRequire.internalRequire
|
||||
import net.eagle0.eagle.library.util.hero_generator.HeroGenerator
|
||||
import net.eagle0.eagle.library.util.validations.RuntimeValidator
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.proto_converters.BattalionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.battalion.BattalionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.date.DateConverter
|
||||
import net.eagle0.eagle.model.proto_converters.faction.FactionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.hero.HeroConverter
|
||||
@@ -148,7 +149,7 @@ final case class EngineAndResultsImpl(
|
||||
): EngineAndResultsImpl = recursiveTransform(eng => {
|
||||
val results = f(eng)
|
||||
RandomStateProtoSequencer(
|
||||
initialState = eng.currentState,
|
||||
initialStateProto = eng.currentState,
|
||||
actionResultProtoApplier = eng.actionResultProtoApplier,
|
||||
functionalRandom = SeededRandom(eng.currentState.randomSeed)
|
||||
).withActionResultTs(_ => results).results.newValue
|
||||
@@ -300,14 +301,14 @@ case class EngineImpl(
|
||||
val availableCommand = availableCommandOpt.get
|
||||
|
||||
val sequencer = RandomStateProtoSequencer(
|
||||
initialState = this.currentState,
|
||||
initialStateProto = this.currentState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = SeededRandom(this.currentState.randomSeed)
|
||||
).withActionResults { gs =>
|
||||
val results = commandFactory
|
||||
.makeCommand(
|
||||
actingFactionId = factionId,
|
||||
gameState = gs,
|
||||
gameState = GameStateConverter.fromProto(gs),
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
|
||||
+8
-14
@@ -8,16 +8,12 @@ import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
object AvailableAlmsCommandFactory extends AvailableCommandsFactoryForType {
|
||||
|
||||
def availableHeroIds(gs: GameState, pid: ProvinceId): Vector[HeroId] =
|
||||
gs.provinces(pid.value)
|
||||
gs.provinces(pid)
|
||||
.rulingFactionHeroIds
|
||||
.toVector
|
||||
.map(HeroId(_))
|
||||
.filter(hid => gs.heroes(hid.value).vigor >= MinVigorForAlms.doubleValue)
|
||||
.filter(hid => gs.heroes(hid).vigor >= MinVigorForAlms.doubleValue)
|
||||
.sortBy(hid =>
|
||||
(
|
||||
!gs.heroes(hid.value).profession.isPaladin,
|
||||
-gs.heroes(hid.value).vigor
|
||||
)
|
||||
(!gs.heroes(hid).profession.isPaladin, -gs.heroes(hid).vigor)
|
||||
)
|
||||
|
||||
override def availableCommand(
|
||||
@@ -26,16 +22,14 @@ object AvailableAlmsCommandFactory extends AvailableCommandsFactoryForType {
|
||||
provinceId: ProvinceId
|
||||
): Option[AlmsAvailableCommand] = {
|
||||
val hids = availableHeroIds(gameState, provinceId)
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
Option.when(hids.nonEmpty && province.food > 0) {
|
||||
AlmsAvailableCommand(
|
||||
availableHeroIds = hids.map(_.value),
|
||||
actingProvinceId = provinceId.value,
|
||||
foodAvailable = Math.min(
|
||||
MaxAlmsFood.intValue,
|
||||
gameState.provinces(provinceId.value).food
|
||||
)
|
||||
availableHeroIds = hids,
|
||||
actingProvinceId = provinceId,
|
||||
foodAvailable =
|
||||
Math.min(MaxAlmsFood.intValue, gameState.provinces(provinceId).food)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,13 +35,13 @@ object AvailableApprehendOutlawCommandFactory
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ApprehendOutlawAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
val outlaws = availableToCapture(province)
|
||||
val actors = availableActors(gameState, province)
|
||||
|
||||
Option.when(outlaws.nonEmpty && actors.nonEmpty) {
|
||||
ApprehendOutlawAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
availableHeroIds = actors.map(_.id),
|
||||
outlaws = outlaws.map(outlaw =>
|
||||
ResidentOutlaw(
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ object AvailableArmTroopsCommandFactory
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ArmTroopsAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
if !province.rulerIsTraveling then return None
|
||||
|
||||
@@ -56,7 +56,7 @@ object AvailableArmTroopsCommandFactory
|
||||
|
||||
Some(
|
||||
ArmTroopsAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
availableBattalions = affordableBattalions.map(_.id),
|
||||
armamentCosts = armamentCosts,
|
||||
maxArmament =
|
||||
|
||||
+21
-27
@@ -28,7 +28,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
pid: ProvinceId,
|
||||
gs: GameState
|
||||
): Vector[MovingArmy] =
|
||||
gs.provinces(pid.value)
|
||||
gs.provinces(pid)
|
||||
.hostileArmies
|
||||
.flatMap(_.armies)
|
||||
.sortBy(ma => (ma.getArmy.factionId, ma.getArmy.units.head.heroId))
|
||||
@@ -39,9 +39,9 @@ object AvailableAttackDecisionCommandFactory
|
||||
fid: FactionId,
|
||||
gs: GameState
|
||||
): Option[HostileArmyGroup] =
|
||||
gs.provinces(pid.value)
|
||||
gs.provinces(pid)
|
||||
.hostileArmies
|
||||
.find(ha => FactionId(ha.factionId) == fid)
|
||||
.find(_.factionId == fid)
|
||||
.filter(_.status.asMessage.sealedValue.isAwaitingDecision)
|
||||
|
||||
private def defendingArmyStats(
|
||||
@@ -49,7 +49,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
pid: ProvinceId,
|
||||
gs: GameState
|
||||
): Option[ArmyStats] = {
|
||||
val province = gs.provinces(pid.value)
|
||||
val province = gs.provinces(pid)
|
||||
|
||||
val heroCount = province.rulingFactionHeroIds.size + province.defendingArmy
|
||||
.map(_.units.size)
|
||||
@@ -72,9 +72,9 @@ object AvailableAttackDecisionCommandFactory
|
||||
factionId = defenderFid,
|
||||
heroCount = heroCount,
|
||||
troopCount = troopCount,
|
||||
hostility = LegacyFactionUtils
|
||||
.hostilityStatus(FactionId(defenderFid), attackerFid, gs),
|
||||
originProvinceId = pid.value
|
||||
hostility =
|
||||
LegacyFactionUtils.hostilityStatus(defenderFid, attackerFid, gs),
|
||||
originProvinceId = pid
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -85,8 +85,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
gs: GameState
|
||||
): Vector[ArmyStats] =
|
||||
relevantArmies(pid, gs).map(ia =>
|
||||
IncomingArmyUtils
|
||||
.stats(toFid, ia.getArmy, gs, ProvinceId(ia.originProvince))
|
||||
IncomingArmyUtils.stats(toFid, ia.getArmy, gs, ia.originProvince)
|
||||
) ++ defendingArmyStats(
|
||||
toFid,
|
||||
pid,
|
||||
@@ -113,9 +112,9 @@ object AvailableAttackDecisionCommandFactory
|
||||
fid: FactionId
|
||||
): Option[AttackDecisionType] =
|
||||
Option.when(
|
||||
gs.provinces(pid.value).rulingFactionId.isEmpty ||
|
||||
gs.provinces(pid).rulingFactionId.isEmpty ||
|
||||
IncomingArmyUtils.isHostileProvince(
|
||||
gs.provinces(pid.value),
|
||||
gs.provinces(pid),
|
||||
fid,
|
||||
gs
|
||||
)
|
||||
@@ -127,9 +126,9 @@ object AvailableAttackDecisionCommandFactory
|
||||
fid: FactionId
|
||||
): Option[AttackDecisionType] =
|
||||
Option.when(
|
||||
hasResourcesToDemand(gs.provinces(pid.value))
|
||||
hasResourcesToDemand(gs.provinces(pid))
|
||||
&& IncomingArmyUtils.isHostileProvince(
|
||||
gs.provinces(pid.value),
|
||||
gs.provinces(pid),
|
||||
fid,
|
||||
gs
|
||||
) && allArmiesCanFlee(gs, pid, fid)
|
||||
@@ -137,8 +136,8 @@ object AvailableAttackDecisionCommandFactory
|
||||
DemandTributeDecision(
|
||||
Some(
|
||||
TributeAmount(
|
||||
food = gs.provinces(pid.value).food,
|
||||
gold = gs.provinces(pid.value).gold
|
||||
food = gs.provinces(pid).food,
|
||||
gold = gs.provinces(pid).gold
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -161,7 +160,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
MoreOption.flatWhen(
|
||||
!allArmiesCanFlee(gs, pid, fid) &&
|
||||
!IncomingArmyUtils.isHostileProvince(
|
||||
gs.provinces(pid.value),
|
||||
gs.provinces(pid),
|
||||
fid,
|
||||
gs
|
||||
)
|
||||
@@ -175,19 +174,14 @@ object AvailableAttackDecisionCommandFactory
|
||||
.map(_.id)
|
||||
.toVector match {
|
||||
case items if items.isEmpty => None
|
||||
case emptyProvinceIds =>
|
||||
case emptyProvinces =>
|
||||
ProvinceDistances
|
||||
.closestProvinceOption(
|
||||
pid,
|
||||
emptyProvinceIds.map(ProvinceId(_)),
|
||||
p =>
|
||||
gs.provinces(p.value)
|
||||
.neighbors
|
||||
.map(_.provinceId)
|
||||
.map(ProvinceId(_))
|
||||
.toVector
|
||||
emptyProvinces,
|
||||
p => gs.provinces(p).neighbors.map(_.provinceId).toVector
|
||||
)
|
||||
.map(pwd => gs.provinces(pwd.provinceId.value))
|
||||
.map(pwd => gs.provinces(pwd.provinceId))
|
||||
}
|
||||
}
|
||||
.map { returnProvince =>
|
||||
@@ -219,7 +213,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
): Option[AttackDecisionAvailableCommand] = {
|
||||
internalRequire(
|
||||
IncomingArmyUtils.incomingArmiesAreMutuallyAllied(
|
||||
gameState.provinces(provinceId.value),
|
||||
gameState.provinces(provinceId),
|
||||
gameState
|
||||
),
|
||||
s"Incoming armies in attack decision phase are not mutually allied in province $provinceId"
|
||||
@@ -232,7 +226,7 @@ object AvailableAttackDecisionCommandFactory
|
||||
case nonemptyDecisionOptions =>
|
||||
Some(
|
||||
AttackDecisionAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
armies = armyStats(factionId, provinceId, gameState),
|
||||
actingUnits = hostileArmyGroup.armies
|
||||
.flatMap(_.getArmy.units)
|
||||
|
||||
+5
-4
@@ -60,8 +60,9 @@ object AvailableControlWeatherCommandsFactory
|
||||
gameState: GameState,
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ControlWeatherAvailableCommand] = makeControlWeatherCommand(
|
||||
gameState,
|
||||
gameState.provinces(provinceId.value)
|
||||
)
|
||||
): Option[ControlWeatherAvailableCommand] =
|
||||
makeControlWeatherCommand(
|
||||
gameState,
|
||||
gameState.provinces(provinceId)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ object AvailableDeclineQuestCommandsFactory
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[DeclineQuestAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
MoreOption.flatWhen(
|
||||
province.rulerIsTraveling
|
||||
@@ -26,7 +26,7 @@ object AvailableDeclineQuestCommandsFactory
|
||||
|
||||
Option.when(withQuests.nonEmpty) {
|
||||
DeclineQuestAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
declinableHeroes = withQuests.map(uh =>
|
||||
expandedUnaffiliatedHero(gs = gameState, uh = uh)
|
||||
)
|
||||
|
||||
+6
-9
@@ -24,7 +24,7 @@ object AvailableDefendCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
): Vector[ProvinceId] =
|
||||
if LegacyFactionUtils
|
||||
.provinces(
|
||||
factionId = FactionId(from.rulingFactionId.get),
|
||||
factionId = from.rulingFactionId.get,
|
||||
gameState = gs
|
||||
)
|
||||
.map(_.id)
|
||||
@@ -43,7 +43,6 @@ object AvailableDefendCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
)
|
||||
.toVector
|
||||
.map(_.id)
|
||||
.map(ProvinceId(_))
|
||||
|
||||
private def makeDefendCommand(
|
||||
gameState: GameState,
|
||||
@@ -94,17 +93,15 @@ object AvailableDefendCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
.toVector
|
||||
.map(_.id),
|
||||
actingProvinceId = province.id,
|
||||
suitableBattalionsForHeroes = BattalionSuitability
|
||||
.suitableBattalionsForHeroes(
|
||||
suitableBattalionsForHeroes =
|
||||
BattalionSuitability.suitableBattalionsForHeroes(
|
||||
hs = availableHeroes.toVector,
|
||||
bs = availableBattalions.toVector,
|
||||
bts = gameState.battalionTypes.toVector
|
||||
)
|
||||
.map { case (hid, suitability) => (hid.value, suitability) },
|
||||
),
|
||||
availableBattalions = availableBattalionsWithCosts,
|
||||
availableFleeProvinceIds =
|
||||
sortedFleeProvinces(from = province, gs = gameState)
|
||||
.map(_.value),
|
||||
sortedFleeProvinces(from = province, gs = gameState),
|
||||
recommendedUnits = recommendedUnits,
|
||||
hostileFactionIds = hostileArmies.toVector.map(_.factionId).distinct,
|
||||
hostileHeroCount = hostileUnits.size,
|
||||
@@ -126,6 +123,6 @@ object AvailableDefendCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
): Option[DefendAvailableCommand] =
|
||||
makeDefendCommand(
|
||||
gameState,
|
||||
gameState.provinces(provinceId.value)
|
||||
gameState.provinces(provinceId)
|
||||
)
|
||||
}
|
||||
|
||||
+35
-42
@@ -35,19 +35,15 @@ object AvailableDiplomacyCommandsFactory
|
||||
extends AvailableCommandsFactoryForType {
|
||||
|
||||
def availableHeroIds(gs: GameState, pid: ProvinceId): Vector[HeroId] =
|
||||
gs.provinces(pid.value)
|
||||
gs.provinces(pid)
|
||||
.rulingFactionHeroIds
|
||||
.filter(hid => gs.heroes(hid).vigor >= MinVigorForDiplomacy.doubleValue)
|
||||
.map(HeroId(_))
|
||||
.toVector
|
||||
|
||||
def recommendedHeroId(gs: GameState, availableHids: Seq[HeroId]): HeroId =
|
||||
availableHids
|
||||
.sortBy(hid =>
|
||||
(
|
||||
LegacyHeroUtils.fatigue(gs.heroes(hid.value)),
|
||||
-gs.heroes(hid.value).vigor
|
||||
)
|
||||
(LegacyHeroUtils.fatigue(gs.heroes(hid)), -gs.heroes(hid).vigor)
|
||||
) match {
|
||||
case sortedHeroes =>
|
||||
sortedHeroes
|
||||
@@ -65,19 +61,19 @@ object AvailableDiplomacyCommandsFactory
|
||||
targetFid: FactionId
|
||||
): Option[DiplomacyOption] =
|
||||
Option.when(
|
||||
gs.provinces(pid.value).gold >= TruceGoldCost.intValue
|
||||
gs.provinces(pid).gold >= TruceGoldCost.intValue
|
||||
&& LegacyProvinceUtils.ruledByFactionLeader(
|
||||
province = gs.provinces(pid.value),
|
||||
province = gs.provinces(pid),
|
||||
gameState = gs
|
||||
)
|
||||
&& !LegacyFactionUtils.hasAlliance(
|
||||
fid1 = FactionId(gs.provinces(pid.value).rulingFactionId.get),
|
||||
fid1 = gs.provinces(pid).rulingFactionId.get,
|
||||
fid2 = targetFid,
|
||||
gs = gs
|
||||
)
|
||||
)(
|
||||
TruceOption(
|
||||
targetFactionId = targetFid.value,
|
||||
targetFactionId = targetFid,
|
||||
goldCost = TruceGoldCost.intValue
|
||||
)
|
||||
)
|
||||
@@ -89,15 +85,15 @@ object AvailableDiplomacyCommandsFactory
|
||||
targetFid: FactionId
|
||||
): Option[DiplomacyOption] =
|
||||
Option.when(
|
||||
gs.provinces(pid.value).gold >= AllianceGoldCost.intValue
|
||||
gs.provinces(pid).gold >= AllianceGoldCost.intValue
|
||||
&& LegacyProvinceUtils.ruledByFactionLeader(
|
||||
province = gs.provinces(pid.value),
|
||||
province = gs.provinces(pid),
|
||||
gameState = gs
|
||||
) && !LegacyFactionUtils
|
||||
.hasAlliance(fid1 = actingFid, fid2 = targetFid, gs = gs)
|
||||
)(
|
||||
AllianceOption(
|
||||
targetFactionId = targetFid.value,
|
||||
targetFactionId = targetFid,
|
||||
goldCost = AllianceGoldCost.intValue
|
||||
)
|
||||
)
|
||||
@@ -109,15 +105,15 @@ object AvailableDiplomacyCommandsFactory
|
||||
targetFid: FactionId
|
||||
): Option[DiplomacyOption] =
|
||||
Option.when(
|
||||
gs.provinces(pid.value).gold >= BreakAllianceGoldCost.intValue
|
||||
gs.provinces(pid).gold >= BreakAllianceGoldCost.intValue
|
||||
&& LegacyProvinceUtils.ruledByFactionLeader(
|
||||
province = gs.provinces(pid.value),
|
||||
province = gs.provinces(pid),
|
||||
gameState = gs
|
||||
) && LegacyFactionUtils
|
||||
.hasAlliance(fid1 = actingFid, fid2 = targetFid, gs = gs)
|
||||
)(
|
||||
BreakAllianceOption(
|
||||
targetFactionId = targetFid.value,
|
||||
targetFactionId = targetFid,
|
||||
goldCost = BreakAllianceGoldCost.intValue
|
||||
)
|
||||
)
|
||||
@@ -132,7 +128,7 @@ object AvailableDiplomacyCommandsFactory
|
||||
targetProvince =>
|
||||
val eligibleNeighbors: ProvinceId => Vector[ProvinceId] =
|
||||
p =>
|
||||
gs.provinces(p.value)
|
||||
gs.provinces(p)
|
||||
.neighbors
|
||||
.map(_.provinceId)
|
||||
.map(gs.provinces)
|
||||
@@ -146,17 +142,16 @@ object AvailableDiplomacyCommandsFactory
|
||||
// inviting across your ally's province
|
||||
LegacyFactionUtils
|
||||
.hasAlliance(
|
||||
FactionId(neighborProvince.rulingFactionId.get),
|
||||
neighborProvince.rulingFactionId.get,
|
||||
actingFid,
|
||||
gs
|
||||
)
|
||||
)
|
||||
.map(_.id)
|
||||
.map(ProvinceId(_))
|
||||
.toVector
|
||||
|
||||
ProvinceDistances
|
||||
.distance(pid, ProvinceId(targetProvince.id), eligibleNeighbors)
|
||||
.distance(pid, targetProvince.id, eligibleNeighbors)
|
||||
.isDefined
|
||||
}
|
||||
}
|
||||
@@ -168,10 +163,8 @@ object AvailableDiplomacyCommandsFactory
|
||||
targetFid: FactionId
|
||||
): Option[DiplomacyOption] =
|
||||
Option.when(
|
||||
gs.currentRoundId >= gs
|
||||
.factions(actingFid.value)
|
||||
.earliestRoundForInvitation &&
|
||||
gs.provinces(pid.value).gold >= InviteGoldCost.intValue
|
||||
gs.currentRoundId >= gs.factions(actingFid).earliestRoundForInvitation &&
|
||||
gs.provinces(pid).gold >= InviteGoldCost.intValue
|
||||
&& LegacyFactionUtils
|
||||
.provinceCount(
|
||||
targetFid,
|
||||
@@ -180,13 +173,13 @@ object AvailableDiplomacyCommandsFactory
|
||||
&& LegacyFactionUtils.provinceCount(actingFid, gs) > LegacyFactionUtils
|
||||
.provinceCount(targetFid, gs)
|
||||
&& LegacyProvinceUtils.ruledByFactionLeader(
|
||||
province = gs.provinces(pid.value),
|
||||
province = gs.provinces(pid),
|
||||
gameState = gs
|
||||
)
|
||||
&& hasClearPath(gs, pid, actingFid, targetFid)
|
||||
)(
|
||||
InvitationOption(
|
||||
targetFactionId = targetFid.value,
|
||||
targetFactionId = targetFid,
|
||||
goldCost = InviteGoldCost.intValue
|
||||
)
|
||||
)
|
||||
@@ -197,9 +190,9 @@ object AvailableDiplomacyCommandsFactory
|
||||
actingFid: FactionId,
|
||||
targetFid: FactionId
|
||||
): Vector[DiplomacyOption] = {
|
||||
val prisonersAvailableToOffer = availablePrisoners(gs.provinces(pid.value))
|
||||
val prisonersAvailableToOffer = availablePrisoners(gs.provinces(pid))
|
||||
val hostagesAvailableToOffer = availableHostages(gs, pid)
|
||||
val goldAvailableToOffer = gs.provinces(pid.value).gold
|
||||
val goldAvailableToOffer = gs.provinces(pid).gold
|
||||
|
||||
if prisonersAvailableToOffer.nonEmpty || hostagesAvailableToOffer.nonEmpty || goldAvailableToOffer > 0
|
||||
then
|
||||
@@ -210,7 +203,7 @@ object AvailableDiplomacyCommandsFactory
|
||||
)
|
||||
.map { prisonerToBeRansomed =>
|
||||
RansomOfferOption(
|
||||
targetFactionId = targetFid.value,
|
||||
targetFactionId = targetFid,
|
||||
ransomOffer = Some(
|
||||
RansomOfferDetails(
|
||||
prisonerToBeRansomed = Some(prisonerToBeRansomed),
|
||||
@@ -263,9 +256,9 @@ object AvailableDiplomacyCommandsFactory
|
||||
gameState: GameState
|
||||
): Boolean =
|
||||
gameState
|
||||
.factions(toFid.value)
|
||||
.factions(toFid)
|
||||
.incomingDiplomacyOffers
|
||||
.exists(dof => FactionId(dof.originatingFactionId) == fromFid)
|
||||
.exists(_.originatingFactionId == fromFid)
|
||||
|
||||
override def availableCommand(
|
||||
gameState: GameState,
|
||||
@@ -273,14 +266,14 @@ object AvailableDiplomacyCommandsFactory
|
||||
provinceId: ProvinceId
|
||||
): Option[DiplomacyAvailableCommand] = {
|
||||
if availableHeroIds(gameState, provinceId).isEmpty then None
|
||||
else if gameState.provinces(provinceId.value).rulingFactionHeroIds.size < 2
|
||||
then None
|
||||
else if gameState.provinces(provinceId).rulingFactionHeroIds.size < 2 then
|
||||
None
|
||||
else {
|
||||
gameState.factions.keys
|
||||
.filterNot(fid => FactionId(fid) == factionId)
|
||||
.filterNot(_ == factionId)
|
||||
.filterNot(fid =>
|
||||
hasIncomingDiplomacyOffer(
|
||||
toFid = FactionId(fid),
|
||||
toFid = fid,
|
||||
fromFid = factionId,
|
||||
gameState = gameState
|
||||
)
|
||||
@@ -290,7 +283,7 @@ object AvailableDiplomacyCommandsFactory
|
||||
gs = gameState,
|
||||
pid = provinceId,
|
||||
actingFid = factionId,
|
||||
targetFid = FactionId(targetFid)
|
||||
targetFid = targetFid
|
||||
)
|
||||
)
|
||||
.toVector
|
||||
@@ -327,10 +320,10 @@ object AvailableDiplomacyCommandsFactory
|
||||
|
||||
Some(
|
||||
DiplomacyAvailableCommand(
|
||||
availableHeroIds = heroIds.map(_.value),
|
||||
availableHeroIds = heroIds,
|
||||
options = options,
|
||||
actingProvinceId = provinceId.value,
|
||||
recommendedHeroId = recommendedHeroId(gameState, heroIds).value
|
||||
actingProvinceId = provinceId,
|
||||
recommendedHeroId = recommendedHeroId(gameState, heroIds)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -356,14 +349,14 @@ object AvailableDiplomacyCommandsFactory
|
||||
provinceId: ProvinceId
|
||||
): Vector[HostageOfferedInExchange] =
|
||||
gameState
|
||||
.provinces(provinceId.value)
|
||||
.provinces(provinceId)
|
||||
.rulingFactionHeroIds
|
||||
.map(heroId => gameState.heroes(heroId))
|
||||
.filter(_.vigor >= MinVigorForDiplomacy.doubleValue)
|
||||
.map(hero =>
|
||||
HostageOfferedInExchange(
|
||||
heroId = hero.id,
|
||||
provinceIdWithHero = provinceId.value
|
||||
provinceIdWithHero = provinceId
|
||||
)
|
||||
)
|
||||
.toVector
|
||||
@@ -381,7 +374,7 @@ object AvailableDiplomacyCommandsFactory
|
||||
_.`type` == UNAFFILIATED_HERO_PRISONER
|
||||
)
|
||||
if prisoner.lastFaction.contains(factionId)
|
||||
if LegacyFactionUtils.isFactionLeader(HeroId(prisoner.heroId), gameState)
|
||||
if LegacyFactionUtils.isFactionLeader(prisoner.heroId, gameState)
|
||||
} yield PrisonerToBeRansomed(
|
||||
prisonerHeroId = prisoner.heroId,
|
||||
provinceIdForPrisoner = province.id
|
||||
|
||||
+3
-3
@@ -17,7 +17,7 @@ object AvailableFeastCommandFactory extends AvailableCommandsFactoryForType {
|
||||
.map(gameState.heroes)
|
||||
.exists(h =>
|
||||
h.vigor < h.constitution || LegacyHeroUtils
|
||||
.effectiveLoyalty(HeroId(h.id), gameState) < 100.0
|
||||
.effectiveLoyalty(h.id, gameState) < 100.0
|
||||
)
|
||||
|
||||
def feastGoldCost(province: Province): Int =
|
||||
@@ -28,7 +28,7 @@ object AvailableFeastCommandFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[FeastAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
val goldCost = feastGoldCost(province)
|
||||
|
||||
Option.when(
|
||||
@@ -36,7 +36,7 @@ object AvailableFeastCommandFactory extends AvailableCommandsFactoryForType {
|
||||
) {
|
||||
FeastAvailableCommand(
|
||||
goldCost = goldCost,
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ object AvailableHandleRiotGiveCommandFactory
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[HandleRiotGiveAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
val food = Math.min(province.food, RiotMaxFood.intValue)
|
||||
val gold = Math.min(province.gold, RiotMaxGold.intValue)
|
||||
@@ -26,7 +26,7 @@ object AvailableHandleRiotGiveCommandFactory
|
||||
) && !province.hasActed && (food > 0 || gold > 0)
|
||||
) {
|
||||
HandleRiotGiveAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
foodAvailable = food,
|
||||
goldAvailable = gold
|
||||
)
|
||||
|
||||
+3
-5
@@ -8,7 +8,7 @@ import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.province.Province
|
||||
import net.eagle0.eagle.library.settings.MaxGiftGold
|
||||
import net.eagle0.eagle.library.util.faction_utils.LegacyFactionUtils
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
|
||||
object AvailableHeroGiftCommandFactory extends AvailableCommandsFactoryForType {
|
||||
import net.eagle0.eagle.library.util.hero.LegacyHeroUtils.*
|
||||
@@ -18,9 +18,7 @@ object AvailableHeroGiftCommandFactory extends AvailableCommandsFactoryForType {
|
||||
gameState: GameState
|
||||
): Seq[EligibleGift] =
|
||||
province.rulingFactionHeroIds
|
||||
.filterNot(hid =>
|
||||
LegacyFactionUtils.isFactionLeader(HeroId(hid), gameState)
|
||||
)
|
||||
.filterNot(hid => LegacyFactionUtils.isFactionLeader(hid, gameState))
|
||||
.map(hid =>
|
||||
EligibleGift(
|
||||
recipientHeroId = hid,
|
||||
@@ -42,7 +40,7 @@ object AvailableHeroGiftCommandFactory extends AvailableCommandsFactoryForType {
|
||||
Some(
|
||||
HeroGiftAvailableCommand(
|
||||
eligibleGifts = eg,
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ object AvailableImproveCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ImproveAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
internalRequire(
|
||||
province.rulingFactionId.contains(factionId),
|
||||
@@ -55,7 +55,7 @@ object AvailableImproveCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
ImproveAvailableCommand(
|
||||
availableHeroIds = availableHeroes.map(_.id),
|
||||
availableTypes = availableTypes.toVector,
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
recommendedHeroId = availableHeroes.maxBy(heroSorting).id,
|
||||
lockedType = province.lockedImprovementType
|
||||
)
|
||||
|
||||
+4
-4
@@ -17,15 +17,15 @@ object AvailableIssueOrdersCommandFactory
|
||||
): Option[IssueOrdersAvailableCommand] =
|
||||
Option.when(
|
||||
gameState
|
||||
.provinces(provinceId.value)
|
||||
.provinces(provinceId)
|
||||
.rulingHeroId
|
||||
.exists(gameState.factions(factionId.value).leaders.contains) &&
|
||||
.exists(gameState.factions(factionId).leaders.contains) &&
|
||||
LegacyFactionUtils.provinceCount(factionId, gameState) > 1
|
||||
) {
|
||||
IssueOrdersAvailableCommand(
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
currentOrders = gameState.provinces.values
|
||||
.filter(_.rulingFactionId.contains(factionId.value))
|
||||
.filter(_.rulingFactionId.contains(factionId))
|
||||
.toVector
|
||||
.sortBy(_.name)
|
||||
.map(p =>
|
||||
|
||||
+9
-11
@@ -3,7 +3,7 @@ package net.eagle0.eagle.library.actions.availability
|
||||
import net.eagle0.eagle.api.available_command.ReconAvailableCommand
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.settings.MinVigorForRecon
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
|
||||
object AvailableReconCommandFactory extends AvailableCommandsFactoryForType {
|
||||
override def availableCommand(
|
||||
@@ -11,7 +11,7 @@ object AvailableReconCommandFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ReconAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
if province.rulingFactionHeroIds.size < 2 then None
|
||||
else {
|
||||
@@ -19,25 +19,23 @@ object AvailableReconCommandFactory extends AvailableCommandsFactoryForType {
|
||||
.map(heroId => gameState.heroes(heroId))
|
||||
.filter(_.profession.isRanger)
|
||||
.filter(_.vigor >= MinVigorForRecon.doubleValue)
|
||||
.map(h => HeroId(h.id))
|
||||
.map(_.id)
|
||||
|
||||
val availableTargets = gameState.provinces.values
|
||||
.filterNot(_.rulingFactionId.contains(factionId.value))
|
||||
.filterNot(_.rulingFactionId.contains(factionId))
|
||||
.filterNot(
|
||||
_.incomingEndTurnActions
|
||||
.exists(eta =>
|
||||
eta.action.isRecon && eta.fromFactionId == factionId.value
|
||||
)
|
||||
.exists(eta => eta.action.isRecon && eta.fromFactionId == factionId)
|
||||
)
|
||||
.toVector
|
||||
.sortBy(_.name)
|
||||
.map(p => ProvinceId(p.id))
|
||||
.map(_.id)
|
||||
|
||||
Option.when(availableHeroes.nonEmpty && availableTargets.nonEmpty) {
|
||||
ReconAvailableCommand(
|
||||
availableHeroIds = availableHeroes.map(_.value),
|
||||
availableTargetProvinces = availableTargets.map(_.value),
|
||||
actingProvinceId = provinceId.value
|
||||
availableHeroIds = availableHeroes,
|
||||
availableTargetProvinces = availableTargets,
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ object AvailableResolveAllianceOfferCommandFactory {
|
||||
factionId: FactionId
|
||||
): Vector[DiplomacyOffer] =
|
||||
gameState
|
||||
.factions(factionId.value)
|
||||
.factions(factionId)
|
||||
.incomingDiplomacyOffers
|
||||
.filter(_.status == DIPLOMACY_OFFER_STATUS_UNRESOLVED)
|
||||
.collect { diploOffer =>
|
||||
@@ -47,7 +47,7 @@ object AvailableResolveAllianceOfferCommandFactory {
|
||||
) =>
|
||||
DiplomacyOffer(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = factionId.value,
|
||||
targetFactionId = factionId,
|
||||
offerDetails = AllianceOfferDetails(),
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ object AvailableResolveBreakAllianceCommandFactory {
|
||||
factionId: FactionId
|
||||
): Vector[DiplomacyOffer] =
|
||||
gameState
|
||||
.factions(factionId.value)
|
||||
.factions(factionId)
|
||||
.incomingDiplomacyOffers
|
||||
.filter(_.status == DIPLOMACY_OFFER_STATUS_UNRESOLVED)
|
||||
.collect { diploOffer =>
|
||||
@@ -41,8 +41,8 @@ object AvailableResolveBreakAllianceCommandFactory {
|
||||
case DiplomacyOffer(
|
||||
originatingFactionId: FactionId,
|
||||
_ /* targetFactionId */,
|
||||
messengerHeroId: Int,
|
||||
messengerOriginProvinceId: Int,
|
||||
messengerHeroId: FactionId,
|
||||
messengerOriginProvinceId: FactionId,
|
||||
status: DiplomacyOfferStatus,
|
||||
_ /* eligibleStatuses */,
|
||||
offerTextId: String,
|
||||
@@ -51,7 +51,7 @@ object AvailableResolveBreakAllianceCommandFactory {
|
||||
) =>
|
||||
DiplomacyOffer(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = factionId.value,
|
||||
targetFactionId = factionId,
|
||||
offerDetails = details,
|
||||
messengerHeroId = messengerHeroId,
|
||||
messengerOriginProvinceId = messengerOriginProvinceId,
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ object AvailableResolveRansomOfferCommandFactory {
|
||||
factionId: FactionId
|
||||
): Option[ResolveRansomOfferAvailableCommand] =
|
||||
gameState
|
||||
.factions(factionId.value)
|
||||
.factions(factionId)
|
||||
.incomingDiplomacyOffers
|
||||
.collect { diplomacyOffer =>
|
||||
diplomacyOffer.offerDetails match {
|
||||
|
||||
+1
-1
@@ -52,5 +52,5 @@ object AvailableResolveTributeCommandsFactory
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ResolveTributeAvailableCommand] =
|
||||
makeResolveTributeCommand(gameState.provinces(provinceId.value), gameState)
|
||||
makeResolveTributeCommand(gameState.provinces(provinceId), gameState)
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ object AvailableResolveTruceOfferCommandFactory {
|
||||
factionId: FactionId
|
||||
): Vector[DiplomacyOffer] =
|
||||
gameState
|
||||
.factions(factionId.value)
|
||||
.factions(factionId)
|
||||
.incomingDiplomacyOffers
|
||||
.filter(_.status == DIPLOMACY_OFFER_STATUS_UNRESOLVED)
|
||||
.collect { diploOffer =>
|
||||
@@ -50,7 +50,7 @@ object AvailableResolveTruceOfferCommandFactory {
|
||||
) =>
|
||||
DiplomacyOffer(
|
||||
originatingFactionId = originatingFactionId,
|
||||
targetFactionId = factionId.value,
|
||||
targetFactionId = factionId,
|
||||
offerDetails = TruceOfferDetails(
|
||||
endDate = Some(
|
||||
gameState.currentDate.get.addMonths(TruceMonths.intValue)
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ object AvailableRestCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
): Option[RestAvailableCommand] =
|
||||
Some(
|
||||
RestAvailableCommand(
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ object AvailableReturnCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[ReturnAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
require(
|
||||
province.rulingFactionId.contains(factionId),
|
||||
@@ -18,7 +18,7 @@ object AvailableReturnCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
)
|
||||
|
||||
Option.when(province.rulerIsTraveling)(
|
||||
ReturnAvailableCommand(actingProvinceId = provinceId.value)
|
||||
ReturnAvailableCommand(actingProvinceId = provinceId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,6 +53,6 @@ object AvailableStartEpidemicCommandFactory
|
||||
): Option[StartEpidemicAvailableCommand] =
|
||||
makeStartEpidemicCommand(
|
||||
gameState,
|
||||
gameState.provinces(provinceId.value)
|
||||
gameState.provinces(provinceId)
|
||||
)
|
||||
}
|
||||
|
||||
+9
-11
@@ -14,7 +14,7 @@ object AvailableSwearBrotherhoodCommandFactory
|
||||
|
||||
def canHaveMoreLeaders(gameState: GameState, factionId: FactionId): Boolean =
|
||||
gameState
|
||||
.factions(factionId.value)
|
||||
.factions(factionId)
|
||||
.leaders
|
||||
.length < MaximumFactionLeaders.intValue
|
||||
|
||||
@@ -24,9 +24,9 @@ object AvailableSwearBrotherhoodCommandFactory
|
||||
provinceId: ProvinceId
|
||||
): Boolean =
|
||||
gameState
|
||||
.provinces(provinceId.value)
|
||||
.provinces(provinceId)
|
||||
.rulingFactionHeroIds
|
||||
.contains(gameState.factions(factionId.value).factionHeadId)
|
||||
.contains(gameState.factions(factionId).factionHeadId)
|
||||
|
||||
private def eligibleHeroes(
|
||||
gameState: GameState,
|
||||
@@ -34,14 +34,12 @@ object AvailableSwearBrotherhoodCommandFactory
|
||||
provinceId: ProvinceId
|
||||
): Vector[HeroId] =
|
||||
gameState
|
||||
.provinces(provinceId.value)
|
||||
.provinces(provinceId)
|
||||
.rulingFactionHeroIds
|
||||
.map(gameState.heroes)
|
||||
.filter(_.loyalty >= MinimumLoyaltyForSwearBrotherhood.doubleValue)
|
||||
.filterNot(h =>
|
||||
gameState.factions(factionId.value).leaders.contains(h.id)
|
||||
)
|
||||
.map(h => HeroId(h.id))
|
||||
.filterNot(h => gameState.factions(factionId).leaders.contains(h.id))
|
||||
.map(_.id)
|
||||
.toVector
|
||||
|
||||
override def availableCommand(
|
||||
@@ -62,16 +60,16 @@ object AvailableSwearBrotherhoodCommandFactory
|
||||
SwearBrotherhoodAvailableCommand(
|
||||
availableHeroes = hs.map { hid =>
|
||||
HeroAndBackstory(
|
||||
heroId = hid.value,
|
||||
heroId = hid,
|
||||
backstoryTextId = gameState
|
||||
.heroes(hid.value)
|
||||
.heroes(hid)
|
||||
.backstoryVersions
|
||||
.lastOption
|
||||
.map(_.textId)
|
||||
.getOrElse("")
|
||||
)
|
||||
},
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ object AvailableTradeCommandFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[TradeAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
Option.when(
|
||||
province.rulerIsTraveling && (province.gold > 0 || province.food > 0)
|
||||
@@ -22,7 +22,7 @@ object AvailableTradeCommandFactory extends AvailableCommandsFactoryForType {
|
||||
goldAvailable = province.gold,
|
||||
foodSellPrice = BaseFoodSellPrice.doubleValue * province.priceIndex,
|
||||
foodBuyPrice = BaseFoodBuyPrice.doubleValue * province.priceIndex,
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ object AvailableTrainCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[TrainAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
val availableHeroes = province.rulingFactionHeroIds
|
||||
.map(heroId => gameState.heroes(heroId))
|
||||
.filter(_.vigor >= MinVigorForTrain.doubleValue)
|
||||
@@ -35,7 +35,7 @@ object AvailableTrainCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
Option.when(availableHeroes.nonEmpty && hasTrainableBattalion) {
|
||||
TrainAvailableCommand(
|
||||
availableHeroIds = availableHeroes.map(_.id),
|
||||
actingProvinceId = provinceId.value,
|
||||
actingProvinceId = provinceId,
|
||||
recommendedHeroId = availableHeroes.maxBy(heroSorting).id
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ object AvailableTravelCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
factionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
): Option[TravelAvailableCommand] = {
|
||||
val province = gameState.provinces(provinceId.value)
|
||||
val province = gameState.provinces(provinceId)
|
||||
|
||||
require(
|
||||
province.rulingFactionId.contains(factionId),
|
||||
@@ -28,7 +28,7 @@ object AvailableTravelCommandsFactory extends AvailableCommandsFactoryForType {
|
||||
.exists(_ >= MinVigorForTravel.doubleValue)
|
||||
) {
|
||||
TravelAvailableCommand(
|
||||
actingProvinceId = provinceId.value
|
||||
actingProvinceId = provinceId
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -356,8 +356,8 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:end_diplomacy_resolution_phase_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:ransom_invalidated_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:notification_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/hero",
|
||||
@@ -535,6 +535,7 @@ scala_library(
|
||||
"//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/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
@@ -723,7 +724,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/proto_converters:action_result_proto_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/hero",
|
||||
@@ -1310,7 +1311,6 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:command_builder",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:command_factory",
|
||||
"//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",
|
||||
@@ -1326,7 +1326,6 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/common:more_option",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:command_builder",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:command_factory",
|
||||
"//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",
|
||||
@@ -1343,6 +1342,7 @@ scala_library(
|
||||
"//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/proto_converters/game_state",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1372,6 +1372,8 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/command_choice_helpers",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/province:legacy_province_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1478,7 +1480,6 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
],
|
||||
deps = [
|
||||
"//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:protoless_simple_action",
|
||||
@@ -1496,8 +1497,9 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:province_held_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:captured_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/shardok_interface:resolved_eagle_unit",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -461,7 +461,7 @@ case class EndBattleAftermathPhaseAction(
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomStateTSequencer =
|
||||
RandomStateTSequencer(
|
||||
initialState = initialState,
|
||||
initialStateProto = initialState,
|
||||
actionResultApplier = actionResultApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+2
-4
@@ -24,10 +24,8 @@ import net.eagle0.eagle.model.action_result.types.{
|
||||
RansomInvalidatedResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.{ActionResultT, NotificationT}
|
||||
import net.eagle0.eagle.model.proto_converters.{
|
||||
BattalionConverter,
|
||||
NotificationConverter
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.NotificationConverter
|
||||
import net.eagle0.eagle.model.proto_converters.battalion.BattalionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.date.DateConverter
|
||||
import net.eagle0.eagle.model.proto_converters.faction.FactionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.hero.HeroConverter
|
||||
|
||||
+5
-4
@@ -21,6 +21,7 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
import net.eagle0.eagle.library.util.command_choice_helpers.CommandChoiceHelpers
|
||||
import net.eagle0.eagle.library.util.province.LegacyProvinceUtils
|
||||
import net.eagle0.eagle.model.proto_converters.province.ProvinceConverter
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
|
||||
case class EndHandleRiotsPhaseAction(
|
||||
gameState: GameState,
|
||||
@@ -30,7 +31,7 @@ case class EndHandleRiotsPhaseAction(
|
||||
def vassalCommandResults(
|
||||
ars: RandomStateProtoSequencer
|
||||
): RandomStateProtoSequencer =
|
||||
ars.lastState.provinces.values
|
||||
ars.lastStateProto.provinces.values
|
||||
.filter(LegacyProvinceUtils.hasImminentRiot)
|
||||
.filterNot(_.hasActed)
|
||||
.foldLeft(ars) { case (sequencer, p) =>
|
||||
@@ -48,7 +49,7 @@ case class EndHandleRiotsPhaseAction(
|
||||
commandFactory
|
||||
.makeCommand(
|
||||
actingFactionId = p.getRulingFactionId,
|
||||
gameState = gs,
|
||||
gameState = GameStateConverter.fromProto(gs),
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
)
|
||||
@@ -61,7 +62,7 @@ case class EndHandleRiotsPhaseAction(
|
||||
private def riotOccurredResults(
|
||||
ars: RandomStateProtoSequencer
|
||||
): RandomStateProtoSequencer =
|
||||
ars.lastState.provinces.values
|
||||
ars.lastStateProto.provinces.values
|
||||
.filter(LegacyProvinceUtils.hasImminentRiot)
|
||||
.foldLeft(ars) { case (ars, p) =>
|
||||
ars.withActionResult(_ =>
|
||||
@@ -94,7 +95,7 @@ case class EndHandleRiotsPhaseAction(
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): RandomState[Vector[ActionResult]] =
|
||||
RandomStateProtoSequencer(
|
||||
initialState = gameState,
|
||||
initialStateProto = gameState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+3
-3
@@ -295,7 +295,7 @@ case class EndPlayerCommandsPhaseAction(
|
||||
pid: ProvinceId,
|
||||
arsRS: RandomStateTSequencer
|
||||
): RandomStateTSequencer =
|
||||
arsRS.lastState.provinces(pid).deferredChanges.foldLeft(arsRS) {
|
||||
arsRS.lastStateProto.provinces(pid).deferredChanges.foldLeft(arsRS) {
|
||||
case (acc, dc) =>
|
||||
acc.withRandomActionResult { case (gs, fr) =>
|
||||
oneDeferredProvinceChange(pid, dc, gs, fr)
|
||||
@@ -305,7 +305,7 @@ case class EndPlayerCommandsPhaseAction(
|
||||
private def deferredProvinceChangesResults(
|
||||
ars: RandomStateTSequencer
|
||||
): RandomStateTSequencer =
|
||||
ars.lastState.provinces.keys
|
||||
ars.lastStateProto.provinces.keys
|
||||
.foldLeft(ars) { case (newArs, pid) =>
|
||||
deferredProvinceChangesResultsForProvince(pid, newArs)
|
||||
}
|
||||
@@ -321,7 +321,7 @@ case class EndPlayerCommandsPhaseAction(
|
||||
}
|
||||
|
||||
RandomStateTSequencer(
|
||||
initialState = gameState,
|
||||
initialStateProto = gameState,
|
||||
actionResultApplier = applier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+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)
|
||||
)
|
||||
|
||||
+3
-5
@@ -13,10 +13,8 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
}
|
||||
import net.eagle0.eagle.library.util.EagleRequire.internalRequire
|
||||
import net.eagle0.eagle.model.proto_converters.date.DateConverter
|
||||
import net.eagle0.eagle.model.proto_converters.{
|
||||
ActionResultProtoConverter,
|
||||
BattalionConverter
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.ActionResultProtoConverter
|
||||
import net.eagle0.eagle.model.proto_converters.battalion.BattalionConverter
|
||||
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.ProvinceConverter
|
||||
@@ -35,7 +33,7 @@ case class EndVassalCommandsPhaseAction(gameState: GameState)
|
||||
}
|
||||
|
||||
RandomStateProtoSequencer(
|
||||
initialState = gameState,
|
||||
initialStateProto = gameState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ case class PerformReconResolutionAction(
|
||||
startingGameState.provinces.values
|
||||
.foldLeft(
|
||||
RandomStateProtoSequencer(
|
||||
initialState = startingGameState,
|
||||
initialStateProto = startingGameState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): RandomState[Vector[ActionResult]] =
|
||||
RandomStateProtoSequencer(
|
||||
initialState = gameState,
|
||||
initialStateProto = gameState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
@@ -106,7 +106,7 @@ case class PerformUnaffiliatedHeroesAction(
|
||||
.toMap
|
||||
|
||||
val qcpsOpt = questChangedProvinces(
|
||||
pwrf = randomSequencer.lastState.provinces.values.toVector,
|
||||
pwrf = randomSequencer.lastStateProto.provinces.values.toVector,
|
||||
newHeroesMap = newHeroesMap,
|
||||
functionalRandom = randomSequencer.results.nextRandom
|
||||
).map { qcps =>
|
||||
|
||||
+3
-2
@@ -19,6 +19,7 @@ import net.eagle0.eagle.library.util.command_choice_helpers.CommandChooser
|
||||
import net.eagle0.eagle.library.util.command_choice_helpers.CommandChooserImplicits.*
|
||||
import net.eagle0.eagle.library.util.CommandSelection
|
||||
import net.eagle0.eagle.library.util.province.LegacyProvinceUtils
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
|
||||
case class PerformVassalCommandsPhaseAction(
|
||||
@@ -39,7 +40,7 @@ case class PerformVassalCommandsPhaseAction(
|
||||
.filterNot(_.hasActed)
|
||||
.foldLeft(
|
||||
RandomStateProtoSequencer(
|
||||
initialState = gameState,
|
||||
initialStateProto = gameState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
@@ -51,7 +52,7 @@ case class PerformVassalCommandsPhaseAction(
|
||||
commandFactory
|
||||
.makeCommand(
|
||||
actingFactionId = cs.actingFactionId,
|
||||
gameState = gameState,
|
||||
gameState = GameStateConverter.fromProto(gameState),
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
)
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import net.eagle0.eagle.library.actions.impl.command.CommandFactory
|
||||
import net.eagle0.eagle.library.actions.impl.common.RandomSequentialResultsAction
|
||||
import net.eagle0.eagle.library.util.CommandSelection
|
||||
import net.eagle0.eagle.library.util.province.LegacyProvinceUtils
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
|
||||
case class PerformVassalDefenseDecisionsAction(
|
||||
gameState: GameState,
|
||||
@@ -37,7 +38,7 @@ case class PerformVassalDefenseDecisionsAction(
|
||||
commandFactory
|
||||
.makeCommand(
|
||||
actingFactionId = cs.actingFactionId,
|
||||
gameState = gameState,
|
||||
gameState = GameStateConverter.fromProto(gameState),
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
)
|
||||
|
||||
+7
-29
@@ -7,6 +7,8 @@ import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
RansomOfferDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.RansomOffer
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.Invalidated
|
||||
import net.eagle0.eagle.common.unaffiliated_hero_type.UnaffiliatedHeroType.{
|
||||
UNAFFILIATED_HERO_OUTLAW,
|
||||
UNAFFILIATED_HERO_PRISONER
|
||||
@@ -82,31 +84,11 @@ case class ProvinceConqueredAction(
|
||||
startingState
|
||||
.factions(rfid)
|
||||
.incomingDiplomacyOffers
|
||||
.map(DiplomacyOfferConverter.fromProto)
|
||||
.collect {
|
||||
case doff @ DiplomacyOffer(
|
||||
_: FactionId /* originatingFactionId */,
|
||||
_: FactionId /* targetFactionId */,
|
||||
_: HeroId /* messengerHeroId */,
|
||||
_: ProvinceId /* messengerOriginProvinceId */,
|
||||
_: DiplomacyOfferStatus /* status */,
|
||||
_: Vector[DiplomacyOfferStatus] /* eligibleStatuses */,
|
||||
_: ClientTextId /* offerTextId */,
|
||||
RansomOfferDetails(
|
||||
Some(
|
||||
PrisonerToBeRansomed(
|
||||
_,
|
||||
conqueredProvince.id,
|
||||
_ /* unknownFieldSet */
|
||||
)
|
||||
),
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_ /* unknownFieldSet */
|
||||
),
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
doff
|
||||
case ransomOffer: RansomOffer
|
||||
if ransomOffer.prisonerToBeRansomed.provinceIdForPrisoner == conqueredProvince.id =>
|
||||
ransomOffer
|
||||
}
|
||||
|
||||
if incomingRansomOffers.nonEmpty then {
|
||||
@@ -116,11 +98,7 @@ case class ProvinceConqueredAction(
|
||||
removedIncomingDiplomacyOfferFactionIds =
|
||||
incomingRansomOffers.map(_.originatingFactionId).toVector,
|
||||
newIncomingDiplomacyOffers = incomingRansomOffers
|
||||
.map(doff =>
|
||||
DiplomacyOfferConverter
|
||||
.fromProto(doff)
|
||||
.withStatus(Invalidated)
|
||||
)
|
||||
.map(_.withStatus(Invalidated))
|
||||
.toVector
|
||||
)
|
||||
)
|
||||
|
||||
+14
-19
@@ -1,7 +1,5 @@
|
||||
package net.eagle0.eagle.library.actions.impl.action
|
||||
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.province.Province
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.actions.generated_text_request_generators.captured_hero_helpers.CapturedHeroPleaGenerator
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
@@ -12,21 +10,25 @@ import net.eagle0.eagle.model.action_result.concrete.{
|
||||
import net.eagle0.eagle.model.action_result.types.ProvinceHeldResultType
|
||||
import net.eagle0.eagle.model.action_result.{ActionResultT, NotificationDetails}
|
||||
import net.eagle0.eagle.model.state.CapturedHero
|
||||
import net.eagle0.eagle.shardok_interface.ResolvedEagleUnit
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId}
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, GameId, HeroId, RoundId}
|
||||
|
||||
case class ProvinceHeldAction(
|
||||
startingState: GameState,
|
||||
defendingProvince: Province,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
defendingProvince: ProvinceT,
|
||||
attackingFactionIds: Vector[FactionId],
|
||||
notFledAttackers: Vector[ResolvedEagleUnit]
|
||||
capturedHeroIds: Vector[HeroId],
|
||||
destroyedBattalionIds: Vector[BattalionId],
|
||||
heroFactions: Map[HeroId, FactionId]
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
CapturedHeroPleaGenerator.withPleasForFirstNewCapturedHero(
|
||||
gameId = startingState.gameId,
|
||||
currentRoundId = startingState.currentRoundId,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
capturingHeroId = defendingProvince.rulingHeroId.get,
|
||||
capturingFactionId = defendingProvince.getRulingFactionId,
|
||||
capturingFactionId = defendingProvince.rulingFactionId.get,
|
||||
actionResult = ActionResultC(
|
||||
actionResultType = ProvinceHeldResultType,
|
||||
actingFactionId = defendingProvince.rulingFactionId,
|
||||
@@ -49,20 +51,13 @@ case class ProvinceHeldAction(
|
||||
private def changedDefendingProvince: ChangedProvinceC =
|
||||
ChangedProvinceC(
|
||||
provinceId = defendingProvince.id,
|
||||
newCapturedHeroes = capturedAttackers.map(hid =>
|
||||
newCapturedHeroes = capturedHeroIds.map(hid =>
|
||||
CapturedHero(
|
||||
heroId = hid,
|
||||
recruitmentAttempted = false,
|
||||
previousFactionId = startingState.heroes(hid).factionId.get
|
||||
previousFactionId = heroFactions(hid)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def capturedAttackers: Vector[HeroId] =
|
||||
notFledAttackers.map(_.hero.id)
|
||||
|
||||
private def destroyedBattalionIds: Vector[BattalionId] =
|
||||
notFledAttackers
|
||||
.flatMap(_.optionalBattalionId)
|
||||
.filter(startingState.battalions.contains)
|
||||
}
|
||||
|
||||
+30
-20
@@ -374,27 +374,37 @@ case class ResolveBattleAction(
|
||||
|
||||
val wsp = winningShardokPlayers.head
|
||||
if wsp.isDefender then
|
||||
ProvinceHeldAction(
|
||||
startingState = battleEndedResults.last.gameState,
|
||||
defendingProvince = battleEndedResults.last.gameState
|
||||
.provinces(battle.defenderProvince),
|
||||
attackingFactionIds = losingResolvedPlayers.map(_.eagleFid),
|
||||
notFledAttackers = battleResolution.resolvedPlayers.toVector
|
||||
.filterNot(_.eagleFid == wsp.eagleFid)
|
||||
.flatMap { losingPlayer =>
|
||||
losingPlayer.units
|
||||
.filterNot(u =>
|
||||
unitReturned(
|
||||
hid = u.hero.id,
|
||||
in = battle.players
|
||||
.find(_.eagleFid == losingPlayer.eagleFid)
|
||||
.get,
|
||||
out = losingPlayer,
|
||||
battleType = BATTLE_TYPE_ASSAULT_PROVINCE
|
||||
)
|
||||
val gs = battleEndedResults.last.gameState
|
||||
val defendingProv = gs.provinces(battle.defenderProvince)
|
||||
val capturedUnits = battleResolution.resolvedPlayers.toVector
|
||||
.filterNot(_.eagleFid == wsp.eagleFid)
|
||||
.flatMap { losingPlayer =>
|
||||
losingPlayer.units
|
||||
.filterNot(u =>
|
||||
unitReturned(
|
||||
hid = u.hero.id,
|
||||
in = battle.players
|
||||
.find(_.eagleFid == losingPlayer.eagleFid)
|
||||
.get,
|
||||
out = losingPlayer,
|
||||
battleType = BATTLE_TYPE_ASSAULT_PROVINCE
|
||||
)
|
||||
.filterNot(_.status.isOutlawedUnit)
|
||||
}
|
||||
)
|
||||
.filterNot(_.status.isOutlawedUnit)
|
||||
}
|
||||
|
||||
ProvinceHeldAction(
|
||||
gameId = gs.gameId,
|
||||
currentRoundId = gs.currentRoundId,
|
||||
defendingProvince = ProvinceConverter.fromProto(defendingProv),
|
||||
attackingFactionIds = losingResolvedPlayers.map(_.eagleFid),
|
||||
capturedHeroIds = capturedUnits.map(_.hero.id),
|
||||
destroyedBattalionIds = capturedUnits
|
||||
.flatMap(_.optionalBattalionId)
|
||||
.filter(gs.battalions.contains),
|
||||
heroFactions = capturedUnits
|
||||
.map(u => u.hero.id -> gs.heroes(u.hero.id).factionId.get)
|
||||
.toMap
|
||||
)
|
||||
else
|
||||
ProvinceConqueredAction(
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ case class SafePassageArmiesProceedAction(
|
||||
provinceId = toProvinceId,
|
||||
newIncomingArmies = ha.armies.map(ma =>
|
||||
ma.copy(
|
||||
arrivalRound = currentRoundId.value + 1,
|
||||
arrivalRound = currentRoundId + 1,
|
||||
destinationProvinceId = toProvinceId,
|
||||
originProvinceId = p.id,
|
||||
army = ma.army.copy(
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ case class TruceTurnBackPhaseAction(startingState: GameState)
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): RandomState[Vector[ActionResult]] = {
|
||||
RandomStateProtoSequencer(
|
||||
initialState = startingState,
|
||||
initialStateProto = startingState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
+6
-9
@@ -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
|
||||
@@ -15,7 +13,7 @@ import net.eagle0.eagle.model.state.hero.concrete.HeroC
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.RecruitmentInfo
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Traveler
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.concrete.UnaffiliatedHeroC
|
||||
import net.eagle0.eagle.{ClientTextId, FactionId, GameId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.{FactionId, GameId, ProvinceId, RoundId}
|
||||
|
||||
case class UnaffiliatedHeroAppearedAction(
|
||||
hero: HeroC,
|
||||
@@ -39,7 +37,7 @@ case class UnaffiliatedHeroAppearedAction(
|
||||
if hero.backstoryVersions.isEmpty then
|
||||
Vector(
|
||||
BackstoryVersion(
|
||||
textId = ClientTextId(newBackstoryTextId),
|
||||
textId = newBackstoryTextId,
|
||||
date = currentDate
|
||||
)
|
||||
)
|
||||
@@ -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
-1
@@ -73,7 +73,7 @@ object ApprehendOutlawCommand {
|
||||
changedProvinces = Vector(
|
||||
ChangedProvinceC(
|
||||
provinceId = province.id,
|
||||
removedUnaffiliatedHeroIds = Vector(targetedHeroId.value),
|
||||
removedUnaffiliatedHeroIds = Vector(targetedHeroId),
|
||||
newUnaffiliatedHeroes = Vector(
|
||||
province.unaffiliatedHeroes
|
||||
.find(_.heroId == targetedHeroId)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,49 +21,6 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "command_builder",
|
||||
srcs = ["CommandBuilder.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//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:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "deterministic_single_result_command",
|
||||
srcs = ["DeterministicSingleResultCommand.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_base",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:deterministic_single_result_action",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//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/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:vigor_xp_applier",
|
||||
"//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/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",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "command_factory",
|
||||
srcs = ["CommandFactory.scala"],
|
||||
@@ -73,18 +30,16 @@ scala_library(
|
||||
],
|
||||
exports = [
|
||||
":command_base",
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
":alms_command",
|
||||
":apprehend_outlaw_command",
|
||||
":arm_troops_command",
|
||||
":attack_decision_command",
|
||||
":command_builder",
|
||||
":command_base",
|
||||
":control_weather_command",
|
||||
":decline_quest_command",
|
||||
":defend_command",
|
||||
":deterministic_single_result_command",
|
||||
":diplomacy_command",
|
||||
":divine_command",
|
||||
":exile_vassal_command",
|
||||
@@ -104,7 +59,6 @@ scala_library(
|
||||
":protoless_random_simple_action_wrapper",
|
||||
":protoless_sequential_results_action_wrapper",
|
||||
":protoless_simple_action_wrapper",
|
||||
":random_simple_action_wrapper",
|
||||
":recon_command",
|
||||
":recruit_heroes_command",
|
||||
":resolve_alliance_offer_command",
|
||||
@@ -116,7 +70,6 @@ scala_library(
|
||||
":rest_command",
|
||||
":return_command",
|
||||
":send_supplies_command",
|
||||
":simple_action_wrapper",
|
||||
":start_epidemic_command",
|
||||
":suppress_beasts_command",
|
||||
":swear_brotherhood_command",
|
||||
@@ -127,13 +80,12 @@ scala_library(
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:control_weather_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:province_orders_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:protoless_random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils:legacy_faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
@@ -141,20 +93,30 @@ scala_library(
|
||||
"//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/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/battalion",
|
||||
"//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/diplomacy_option",
|
||||
"//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/diplomacy_option",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
@@ -204,7 +166,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 +182,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 +305,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",
|
||||
],
|
||||
)
|
||||
@@ -363,18 +332,28 @@ 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/api/command/util:diplomacy_option_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/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:action_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:truce_months",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:date_utils",
|
||||
"//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: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/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:alliance_broken_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:alliance_offered_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:faction_invited_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:ransom_started_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types:truce_offered_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/diplomacy_option",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
@@ -492,14 +471,20 @@ 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: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: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:army",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -752,13 +737,9 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
"//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/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
@@ -845,28 +826,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 +856,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",
|
||||
],
|
||||
)
|
||||
@@ -949,7 +936,9 @@ 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/proto_converters:action_result_proto_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -979,6 +968,7 @@ 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/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
],
|
||||
)
|
||||
@@ -990,6 +980,9 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
@@ -1006,7 +999,10 @@ 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/proto_converters:action_result_proto_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1049,61 +1045,6 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "random_simple_action_wrapper",
|
||||
srcs = ["RandomSimpleActionWrapper.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//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/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:random_state_proto_sequencer",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:vigor_xp_applier",
|
||||
"//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/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",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "random_single_result_command",
|
||||
srcs = ["RandomSingleResultCommand.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_base",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//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/common:functional_random",
|
||||
"//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:random_state_proto_sequencer",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:vigor_xp_applier",
|
||||
"//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/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/state/hero:gender",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "recon_command",
|
||||
srcs = ["ReconCommand.scala"],
|
||||
@@ -1111,24 +1052,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 +1113,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 +1142,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 +1169,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 +1198,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 +1228,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 +1258,26 @@ 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",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1384,48 +1344,23 @@ 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: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",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "simple_action_wrapper",
|
||||
srcs = ["SimpleActionWrapper.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":command_base",
|
||||
"//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/library/actions/applier:action_result_proto_applier_impl",
|
||||
"//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/actions/impl/common:vigor_xp_applier",
|
||||
"//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/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 +1371,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 +1443,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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1542,9 +1473,6 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":command_builder",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
@@ -1575,7 +1503,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 +1522,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",
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.FactionId
|
||||
import net.eagle0.eagle.api.available_command.AvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
|
||||
trait CommandBuilder[AC <: AvailableCommand, SC <: SelectedCommand] {
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
gameState: GameState,
|
||||
availableCommand: AC,
|
||||
selectedCommand: SC
|
||||
): Command
|
||||
}
|
||||
+352
-192
@@ -23,24 +23,29 @@ import net.eagle0.eagle.api.command.util.prisoner_management_type.{
|
||||
PrisonerManagementOptionReturn,
|
||||
PrisonerManagementOption as PrisonerManagementOptionProto
|
||||
}
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.library.util.faction_utils.FactionUtils
|
||||
import net.eagle0.eagle.model.proto_converters.CombatUnitConverter
|
||||
import net.eagle0.eagle.library.actions.impl.command.AttackDecisionCommand.{
|
||||
AttackDecision,
|
||||
SafePassage
|
||||
}
|
||||
import net.eagle0.eagle.library.actions.impl.command.FreeForAllDecisionCommand.FreeForAllDecision
|
||||
import net.eagle0.eagle.library.actions.impl.command.ManagePrisonersCommand.PrisonerManagementOption
|
||||
import net.eagle0.eagle.library.actions.impl.command.ManagePrisonersCommand.PrisonerToManage
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ProtolessRandomSimpleAction,
|
||||
ProtolessSequentialResultsAction,
|
||||
ProtolessSimpleAction,
|
||||
RandomSimpleAction,
|
||||
SimpleAction
|
||||
ProtolessSimpleAction
|
||||
}
|
||||
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.state.diplomacy_option.DiplomacyOption
|
||||
import net.eagle0.eagle.api.command.util.diplomacy_option.DiplomacyOption as DiplomacyOptionProto
|
||||
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.{
|
||||
@@ -48,31 +53,60 @@ import net.eagle0.eagle.model.proto_converters.province.{
|
||||
ProvinceOrderTypeConverter
|
||||
}
|
||||
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.proto_converters.battalion.BattalionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.diplomacy_option.DiplomacyOptionConverter
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{
|
||||
AllianceOffer,
|
||||
BreakAlliance,
|
||||
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
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.{ClientTextId, FactionId, HeroId, ProvinceId}
|
||||
|
||||
class CommandFactory {
|
||||
private def allProvinces(gameState: GameState): Vector[ProvinceT] =
|
||||
gameState.provinces.values.map(ProvinceConverter.fromProto).toVector
|
||||
gameState.provinces.values.toVector
|
||||
|
||||
private def allFactions(gameState: GameState): Vector[FactionT] =
|
||||
gameState.factions.values.map(FactionConverter.fromProto).toVector
|
||||
gameState.factions.values.toVector
|
||||
|
||||
private def allBattalions(gameState: GameState): Vector[BattalionT] =
|
||||
gameState.battalions.values.map(BattalionConverter.fromProto).toVector
|
||||
gameState.battalions.values.toVector
|
||||
|
||||
private def allHeroes(gameState: GameState): Vector[HeroT] =
|
||||
gameState.heroes.values.map(HeroConverter.fromProto).toVector
|
||||
gameState.heroes.values.toVector
|
||||
|
||||
private def convertAttackDecisionToFreeForAllDecision(
|
||||
attackDecision: AttackDecisionType
|
||||
): FreeForAllDecision = {
|
||||
attackDecision match {
|
||||
case AdvanceDecision(_) => FreeForAllDecisionCommand.Advance
|
||||
case WithdrawDecision(_) => FreeForAllDecisionCommand.Withdraw
|
||||
case DemandTributeDecision(_, _) =>
|
||||
throw new EagleCommandException(
|
||||
"Demand Tribute not allowed for free-for-all"
|
||||
)
|
||||
case SafePassageDecision(_, _) =>
|
||||
throw new EagleCommandException(
|
||||
"Safe Passage not allowed for free-for-all"
|
||||
)
|
||||
case AttackDecisionType.Empty =>
|
||||
throw new EagleCommandException("Must specify an attack decision type")
|
||||
}
|
||||
}
|
||||
|
||||
private def factionHeroesInProvince(
|
||||
gameState: GameState,
|
||||
@@ -82,17 +116,15 @@ class CommandFactory {
|
||||
.filter(h =>
|
||||
gameState.provinces(provinceId).rulingFactionHeroIds.contains(h.id)
|
||||
)
|
||||
.map(HeroConverter.fromProto)
|
||||
.toVector
|
||||
|
||||
private def questFulfillmentChecker(
|
||||
gameState: GameState
|
||||
): QuestFulfillmentChecker = new QuestFulfillmentChecker(
|
||||
gameId = gameState.gameId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
currentDate = gameState.currentDate.get,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
previousBackstoryTextIdLookup = hid =>
|
||||
gameState.heroes(hid).backstoryVersions.last.textId
|
||||
previousBackstoryTextIdLookup = hid => gameState.heroes(hid).backstoryTextId
|
||||
)
|
||||
|
||||
def makeCommand(
|
||||
@@ -108,9 +140,7 @@ class CommandFactory {
|
||||
) =>
|
||||
ApprehendOutlawCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(aoac.actingProvinceId)
|
||||
),
|
||||
actingProvince = gameState.provinces(aoac.actingProvinceId),
|
||||
availableHeroIds = aoac.availableHeroIds.toVector,
|
||||
outlawHeroIds = aoac.outlaws.map(_.getHero.id).toVector,
|
||||
actingHeroId = aosc.actingHeroId,
|
||||
@@ -126,11 +156,8 @@ class CommandFactory {
|
||||
newArmament = ab.newArmament
|
||||
)
|
||||
}.toVector,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(atac.actingProvinceId)
|
||||
),
|
||||
existingBattalions = gameState.battalions.values.toVector
|
||||
.map(BattalionConverter.fromProto),
|
||||
actingProvince = gameState.provinces(atac.actingProvinceId),
|
||||
existingBattalions = gameState.battalions.values.toVector,
|
||||
battalionTypes = gameState.battalionTypes.toVector,
|
||||
armamentCosts = atac.armamentCosts.map { ac =>
|
||||
ArmTroopsCommand.ArmamentCost(
|
||||
@@ -182,35 +209,38 @@ class CommandFactory {
|
||||
) =>
|
||||
DeclineQuestCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(dqac.actingProvinceId)
|
||||
),
|
||||
province = gameState.provinces(dqac.actingProvinceId),
|
||||
gameId = gameState.gameId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
currentDate = gameState.currentDate.get,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
selectedHeroId = dqsc.heroId,
|
||||
declinableHeroes = dqac.declinableHeroes.map(_.getHero.id).toVector,
|
||||
previousBackstoryTextIdLookup = { (hid: HeroId) =>
|
||||
gameState.heroes(hid).backstoryVersions.last.textId
|
||||
gameState.heroes(hid).backstoryTextId
|
||||
}
|
||||
)
|
||||
case (dfac: DefendAvailableCommand, dfsc: DefendSelectedCommand) =>
|
||||
DefendCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = dfac,
|
||||
selectedCommand = dfsc,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(dfac.actingProvinceId)
|
||||
)
|
||||
defendingUnits =
|
||||
dfsc.defendingUnits.map(CombatUnitConverter.fromProto).toVector,
|
||||
fleeProvinceId = dfsc.fleeProvinceId,
|
||||
availableFleeProvinceIds = dfac.availableFleeProvinceIds.toVector,
|
||||
actingProvince = gameState.provinces(dfac.actingProvinceId)
|
||||
)
|
||||
case (dpac: DiplomacyAvailableCommand, dpsc: DiplomacySelectedCommand) =>
|
||||
val convertedOption =
|
||||
DiplomacyOptionConverter.fromProto(dpsc.selectedOption)
|
||||
|
||||
val availableOptions =
|
||||
dpac.options.map(o => DiplomacyOptionConverter.fromProto(o)).toVector
|
||||
DiplomacyCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = dpac,
|
||||
selectedCommand = dpsc,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(dpac.actingProvinceId)
|
||||
),
|
||||
sentHeroId = dpsc.sentHeroId,
|
||||
availableHeroIds = dpac.availableHeroIds.toVector,
|
||||
selectedOption = convertedOption,
|
||||
availableOptions = availableOptions,
|
||||
actingProvince = gameState.provinces(dpac.actingProvinceId),
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
currentDate = gameState.currentDate.get
|
||||
@@ -234,34 +264,34 @@ class CommandFactory {
|
||||
ExileVassalCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
exilableHeroIds = evac.exilableHeroIds.toVector,
|
||||
exiledHero = HeroConverter.fromProto(
|
||||
gameState.heroes(evsc.exiledHeroId)
|
||||
),
|
||||
exiledHero = gameState.heroes(evsc.exiledHeroId),
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
gameId = gameState.gameId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(evac.actingProvinceId)
|
||||
)
|
||||
currentDate = gameState.currentDate.get,
|
||||
actingProvince = gameState.provinces(evac.actingProvinceId)
|
||||
)
|
||||
case (ac: FeastAvailableCommand, _: FeastSelectedCommand) =>
|
||||
val provinceProto = gameState.provinces(ac.actingProvinceId)
|
||||
val province = gameState.provinces(ac.actingProvinceId)
|
||||
FeastCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
province = ProvinceConverter.fromProto(provinceProto),
|
||||
rulingFactionHeroes = provinceProto.rulingFactionHeroIds
|
||||
.map(gameState.heroes)
|
||||
.map(HeroConverter.fromProto)
|
||||
.toVector,
|
||||
factionLeaderIds =
|
||||
gameState.factions(actingFactionId).leaders.toVector,
|
||||
province = province,
|
||||
rulingFactionHeroes = province.rulingFactionHeroIds
|
||||
.map(gameState.heroes),
|
||||
factionLeaderIds = gameState.factions(actingFactionId).leaderIds,
|
||||
goldCost = ac.goldCost
|
||||
)
|
||||
case (
|
||||
ac: FreeForAllDecisionAvailableCommand,
|
||||
sc: FreeForAllDecisionSelectedCommand
|
||||
) =>
|
||||
FreeForAllDecisionCommand.make(actingFactionId, ac, sc)
|
||||
FreeForAllDecisionCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
provinceId = ac.provinceId,
|
||||
selectedDecision =
|
||||
convertAttackDecisionToFreeForAllDecision(sc.decision),
|
||||
availableDecisions = ac.availableDecisions.toVector
|
||||
.map(convertAttackDecisionToFreeForAllDecision)
|
||||
)
|
||||
case (
|
||||
ac: HandleCapturedHeroAvailableCommand,
|
||||
sc: HandleCapturedHeroSelectedCommand
|
||||
@@ -269,18 +299,12 @@ class CommandFactory {
|
||||
HandleCapturedHeroesCommand.make(
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
actingFaction = FactionConverter.fromProto(
|
||||
gameState.factions(actingFactionId)
|
||||
),
|
||||
actingFactionHead = HeroConverter.fromProto(
|
||||
gameState.heroes(
|
||||
gameState.factions(actingFactionId).leaders.head
|
||||
)
|
||||
),
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
currentDate = gameState.currentDate.get,
|
||||
actingFaction = gameState.factions(actingFactionId),
|
||||
actingFactionHead = gameState.heroes(
|
||||
gameState.factions(actingFactionId).leaderIds.head
|
||||
),
|
||||
province = gameState.provinces(ac.actingProvinceId),
|
||||
availableCapturedHeroesWithOptions = ac.availableHeroes.map { ch =>
|
||||
HandleCapturedHeroesCommand.AvailableCapturedHeroWithOptions(
|
||||
heroId = ch.getHero.id,
|
||||
@@ -288,8 +312,7 @@ class CommandFactory {
|
||||
options = ch.options.map { handleCapturedHeroOption }.toVector
|
||||
)
|
||||
}.toVector,
|
||||
selectedCapturedHero =
|
||||
HeroConverter.fromProto(gameState.heroes(sc.heroId)),
|
||||
selectedCapturedHero = gameState.heroes(sc.heroId),
|
||||
selectedOption = handleCapturedHeroOption(sc.selectedOption),
|
||||
allProvinces = allProvinces(gameState)
|
||||
)
|
||||
@@ -300,13 +323,10 @@ class CommandFactory {
|
||||
val province = gameState.provinces(ac.actingProvinceId)
|
||||
HandleRiotCrackDownCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvince = ProvinceConverter.fromProto(province),
|
||||
rulingHero =
|
||||
HeroConverter.fromProto(gameState.heroes(province.getRulingHeroId)),
|
||||
actingHero = HeroConverter.fromProto(gameState.heroes(sc.heroId)),
|
||||
optionalBattalion = sc.battalionId
|
||||
.map(gameState.battalions)
|
||||
.map(BattalionConverter.fromProto),
|
||||
actingProvince = province,
|
||||
rulingHero = gameState.heroes(province.rulingHeroId.get),
|
||||
actingHero = gameState.heroes(sc.heroId),
|
||||
optionalBattalion = sc.battalionId.map(gameState.battalions),
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
availableBattalionIds = ac.battalionIdsAvailable.toVector
|
||||
)
|
||||
@@ -316,9 +336,7 @@ class CommandFactory {
|
||||
) =>
|
||||
HandleRiotDoNothingCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
)
|
||||
province = gameState.provinces(ac.actingProvinceId)
|
||||
)
|
||||
case (
|
||||
ac: HandleRiotGiveAvailableCommand,
|
||||
@@ -327,12 +345,8 @@ class CommandFactory {
|
||||
val province = gameState.provinces(ac.actingProvinceId)
|
||||
HandleRiotGiveCommand.make(
|
||||
actingFactionId,
|
||||
province = ProvinceConverter.fromProto(province),
|
||||
rulingHero = HeroConverter.fromProto(
|
||||
gameState.heroes(
|
||||
province.getRulingHeroId
|
||||
)
|
||||
),
|
||||
province = province,
|
||||
rulingHero = gameState.heroes(province.rulingHeroId.get),
|
||||
foodGiven = sc.foodAmount,
|
||||
goldGiven = sc.goldAmount,
|
||||
foodAvailable = ac.foodAvailable,
|
||||
@@ -341,19 +355,13 @@ class CommandFactory {
|
||||
case (ac: HeroGiftAvailableCommand, sc: HeroGiftSelectedCommand) =>
|
||||
HeroGiftCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
recipientProvince = ProvinceConverter.fromProto(
|
||||
ac.eligibleGifts
|
||||
.find(_.recipientHeroId == sc.recipientHeroId)
|
||||
.map(_.recipientProvinceId)
|
||||
.map(gameState.provinces)
|
||||
.get
|
||||
),
|
||||
recipientHero = HeroConverter.fromProto(
|
||||
gameState.heroes(sc.recipientHeroId)
|
||||
),
|
||||
actingProvince = gameState.provinces(ac.actingProvinceId),
|
||||
recipientProvince = ac.eligibleGifts
|
||||
.find(_.recipientHeroId == sc.recipientHeroId)
|
||||
.map(_.recipientProvinceId)
|
||||
.map(gameState.provinces)
|
||||
.get,
|
||||
recipientHero = gameState.heroes(sc.recipientHeroId),
|
||||
goldGiven = sc.amount,
|
||||
eligibleGifts = ac.eligibleGifts.map {
|
||||
case EligibleGift(
|
||||
@@ -367,21 +375,14 @@ class CommandFactory {
|
||||
goldAvailable = goldAvailable
|
||||
)
|
||||
}.toVector,
|
||||
factionProvinces = LegacyFactionUtils
|
||||
.provinces(
|
||||
actingFactionId,
|
||||
gameState
|
||||
)
|
||||
.map(ProvinceConverter.fromProto)
|
||||
factionProvinces = gameState.provinces.values.toVector
|
||||
.filter(_.rulingFactionId.contains(actingFactionId))
|
||||
)
|
||||
case (ac: ImproveAvailableCommand, sc: ImproveSelectedCommand) =>
|
||||
ImproveCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingHero =
|
||||
HeroConverter.fromProto(gameState.heroes(sc.actingHeroId)),
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
actingHero = gameState.heroes(sc.actingHeroId),
|
||||
actingProvince = gameState.provinces(ac.actingProvinceId),
|
||||
improvementType =
|
||||
ImprovementTypeConverter.fromProto(sc.improvementType).get,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
@@ -394,14 +395,10 @@ class CommandFactory {
|
||||
)
|
||||
case (ac: IssueOrdersAvailableCommand, sc: IssueOrdersSelectedCommand) =>
|
||||
IssueOrdersCommand.make(
|
||||
actingFaction =
|
||||
FactionConverter.fromProto(gameState.factions(actingFactionId)),
|
||||
actingFaction = gameState.factions(actingFactionId),
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
factionProvinceIds = LegacyFactionUtils
|
||||
.provinces(
|
||||
factionId = actingFactionId,
|
||||
gameState = gameState
|
||||
)
|
||||
factionProvinceIds = gameState.provinces.values.toVector
|
||||
.filter(_.rulingFactionId.contains(actingFactionId))
|
||||
.map(_.id),
|
||||
newOrders = sc.newOrders.map { (po: ProvinceOrdersProto) =>
|
||||
IssueOrdersCommand.ProvinceOrders(
|
||||
@@ -419,19 +416,38 @@ class CommandFactory {
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = ac.actingProvinceId,
|
||||
availablePrisoners = ac.prisoners.map(prisonerToManage).toVector,
|
||||
prisonerUnaffiliatedHero = UnaffiliatedHeroConverter.fromProto(
|
||||
gameState
|
||||
.provinces(ac.actingProvinceId)
|
||||
.unaffiliatedHeroes
|
||||
.find(_.heroId == sc.prisonerHeroId)
|
||||
.get
|
||||
),
|
||||
prisonerUnaffiliatedHero = gameState
|
||||
.provinces(ac.actingProvinceId)
|
||||
.unaffiliatedHeroes
|
||||
.find(_.heroId == sc.prisonerHeroId)
|
||||
.get,
|
||||
chosenOption = prisonerManagementOption(sc.chosenOption),
|
||||
allProvinces = allProvinces(gameState),
|
||||
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
|
||||
@@ -445,15 +461,14 @@ class CommandFactory {
|
||||
)
|
||||
OrganizeTroopsCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
province = gameState.provinces(ac.actingProvinceId),
|
||||
existingBattalions = gameState.battalions.values.toVector,
|
||||
constructibleBattalionTypeIds = ac.availableBattalionTypes
|
||||
.filter(
|
||||
_.meetsRequirements
|
||||
)
|
||||
.map(_.typeId)
|
||||
.map(BattalionTypeIdConverter.fromProto)
|
||||
.toVector,
|
||||
allBattalionTypes = gameState.battalionTypes.toVector,
|
||||
changedBattalions = sc.changedBattalions
|
||||
@@ -470,7 +485,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 +494,7 @@ class CommandFactory {
|
||||
.toVector,
|
||||
troopCosts = ac.troopCosts.map { tc =>
|
||||
OrganizeTroopsCommand.TroopCost(
|
||||
battalionTypeId = tc.`type`,
|
||||
battalionTypeId = BattalionTypeIdConverter.fromProto(tc.`type`),
|
||||
cost = tc.costPerTroop
|
||||
)
|
||||
}.toVector
|
||||
@@ -499,14 +514,12 @@ class CommandFactory {
|
||||
.toVector,
|
||||
selectedHeroId = sc.heroId,
|
||||
accept = sc.accept,
|
||||
province =
|
||||
ProvinceConverter.fromProto(gameState.provinces(sc.provinceId)),
|
||||
province = gameState.provinces(sc.provinceId),
|
||||
allProvinces = allProvinces(gameState),
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
currentDate = gameState.currentDate.get,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
previousBackstoryTextId =
|
||||
gameState.heroes(sc.heroId).backstoryVersions.last.textId,
|
||||
previousBackstoryTextId = gameState.heroes(sc.heroId).backstoryTextId,
|
||||
questFulfillmentChecker = questFulfillmentChecker(gameState)
|
||||
)
|
||||
|
||||
@@ -516,31 +529,32 @@ class CommandFactory {
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
foodAvailable = ac.foodAvailable,
|
||||
selectedFoodAmount = sc.amount,
|
||||
actingHero =
|
||||
HeroConverter.fromProto(gameState.heroes(sc.actingHeroId)),
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
factionProvinces = LegacyFactionUtils
|
||||
actingHero = gameState.heroes(sc.actingHeroId),
|
||||
actingProvince = gameState.provinces(ac.actingProvinceId),
|
||||
factionProvinces = FactionUtils
|
||||
.provinces(
|
||||
actingFactionId,
|
||||
gameState
|
||||
gameState.provinces.values.toVector
|
||||
)
|
||||
.map(ProvinceConverter.fromProto)
|
||||
)
|
||||
|
||||
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
|
||||
) =>
|
||||
RecruitHeroesCommand.make(
|
||||
actingFactionId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
currentDate = gameState.currentDate.get,
|
||||
province = gameState.provinces(ac.actingProvinceId),
|
||||
availableHeroIds = ac.availableHeroes.map(_.getHero.id).toVector,
|
||||
selectedHeroIds = sc.heroIds.toVector,
|
||||
allProvinces = allProvinces(gameState),
|
||||
@@ -551,21 +565,85 @@ class CommandFactory {
|
||||
ac: ResolveInvitationAvailableCommand,
|
||||
sc: ResolveInvitationSelectedCommand
|
||||
) =>
|
||||
ResolveInvitationCommand.make(actingFactionId, gameState, ac, sc)
|
||||
// Find the selected invitation to get its eligible statuses
|
||||
val selectedOffer = ac.invitations
|
||||
.find(_.originatingFactionId == sc.originatingFactionId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"Could not find invitation from faction ${sc.originatingFactionId}"
|
||||
)
|
||||
)
|
||||
|
||||
ResolveInvitationCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = sc.originatingFactionId,
|
||||
resolution = StatusConverter.fromProto(sc.resolution),
|
||||
allFactions = allFactions(gameState).map(f => f.id -> f).toMap,
|
||||
availableResolutions = selectedOffer.eligibleStatuses
|
||||
.map(StatusConverter.fromProto)
|
||||
.toVector,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
case (
|
||||
ac: ResolveRansomOfferAvailableCommand,
|
||||
sc: ResolveRansomOfferSelectedCommand
|
||||
) =>
|
||||
ResolveRansomOfferCommand.make(actingFactionId, gameState, ac, sc)
|
||||
// Find the selected offer to get its eligible statuses
|
||||
val selectedOffer = ac.offers
|
||||
.find(_.originatingFactionId == sc.offeringFactionId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"Could not find ransom offer from faction ${sc.offeringFactionId}"
|
||||
)
|
||||
)
|
||||
|
||||
ResolveRansomOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
originatingFactionId = sc.offeringFactionId,
|
||||
resolution = StatusConverter.fromProto(sc.resolution),
|
||||
allFactions = allFactions(gameState).map(f => f.id -> f).toMap,
|
||||
availableResolutions = selectedOffer.eligibleStatuses
|
||||
.map(StatusConverter.fromProto)
|
||||
.toVector,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
case (
|
||||
ac: ResolveTruceOfferAvailableCommand,
|
||||
sc: ResolveTruceOfferSelectedCommand
|
||||
) =>
|
||||
// TODO: after the Availability is migrated off protobuf, move these checks into the "make" method
|
||||
// Find the selected offer
|
||||
val selectedOffer = ac.offers
|
||||
.find(_.originatingFactionId == sc.originatingFactionId)
|
||||
.getOrElse(
|
||||
throw new EagleInternalException(
|
||||
s"Could not find truce 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
|
||||
)
|
||||
@@ -574,10 +652,34 @@ class CommandFactory {
|
||||
ac: ResolveAllianceOfferAvailableCommand,
|
||||
sc: ResolveAllianceOfferSelectedCommand
|
||||
) =>
|
||||
// TODO: after the Availability is migrated off protobuf, move these checks into the "make" method
|
||||
val originatingFid = sc.originatingFactionId
|
||||
val selectedOffer = ac.offers
|
||||
.find(_.originatingFactionId == originatingFid)
|
||||
.getOrElse(
|
||||
throw new EagleCommandException(
|
||||
s"Selected faction ID $originatingFid was not among options ${ac.offers.map(_.originatingFactionId)}"
|
||||
)
|
||||
)
|
||||
|
||||
val allianceOffer =
|
||||
DiplomacyOfferConverter.fromProto(selectedOffer) match {
|
||||
case alliance: AllianceOffer => alliance
|
||||
case other =>
|
||||
throw new EagleInternalException(
|
||||
s"Expected AllianceOffer, got $other"
|
||||
)
|
||||
}
|
||||
|
||||
val resolution = StatusConverter.fromProto(sc.resolution)
|
||||
|
||||
ResolveAllianceOfferCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc,
|
||||
allianceOffer = allianceOffer,
|
||||
resolution = resolution,
|
||||
availableResolutions = selectedOffer.eligibleStatuses
|
||||
.map(StatusConverter.fromProto)
|
||||
.toVector,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
@@ -586,10 +688,34 @@ class CommandFactory {
|
||||
ac: ResolveBreakAllianceAvailableCommand,
|
||||
sc: ResolveBreakAllianceSelectedCommand
|
||||
) =>
|
||||
// TODO: after the Availability is migrated off protobuf, move these checks into the "make" method
|
||||
val originatingFid = sc.originatingFactionId
|
||||
val selectedOffer = ac.offers
|
||||
.find(_.originatingFactionId == originatingFid)
|
||||
.getOrElse(
|
||||
throw new EagleCommandException(
|
||||
s"Selected faction ID $originatingFid was not among options ${ac.offers.map(_.originatingFactionId)}"
|
||||
)
|
||||
)
|
||||
|
||||
val breakAllianceOffer =
|
||||
DiplomacyOfferConverter.fromProto(selectedOffer) match {
|
||||
case breakAlliance: BreakAlliance => breakAlliance
|
||||
case other =>
|
||||
throw new EagleInternalException(
|
||||
s"Expected BreakAlliance offer, got $other"
|
||||
)
|
||||
}
|
||||
|
||||
val resolution = StatusConverter.fromProto(sc.resolution)
|
||||
|
||||
ResolveBreakAllianceCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableCommand = ac,
|
||||
selectedCommand = sc,
|
||||
breakAllianceOffer = breakAllianceOffer,
|
||||
resolution = resolution,
|
||||
availableResolutions = selectedOffer.eligibleStatuses
|
||||
.map(StatusConverter.fromProto)
|
||||
.toVector,
|
||||
gameId = gameState.gameId,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
@@ -598,7 +724,35 @@ class CommandFactory {
|
||||
ac: ResolveTributeAvailableCommand,
|
||||
sc: ResolveTributeSelectedCommand
|
||||
) =>
|
||||
ResolveTributeCommand.make(actingFactionId, gameState, ac, sc)
|
||||
import net.eagle0.eagle.model.proto_converters.TributeAmountConverter
|
||||
|
||||
// TODO: after the Availability is migrated off protobuf, move these checks into the "make" method
|
||||
val demandingFid = sc.demandingFactionId
|
||||
val selectedDemand = ac.demands
|
||||
.find(_.demandingFactionId == demandingFid)
|
||||
.getOrElse(
|
||||
throw new EagleCommandException(
|
||||
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,
|
||||
currentDate = gameState.currentDate.get,
|
||||
allProvinces = allProvinces(gameState)
|
||||
)
|
||||
|
||||
case (ac: RestAvailableCommand, sc: RestSelectedCommand) =>
|
||||
RestCommand.make(
|
||||
@@ -618,12 +772,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,
|
||||
@@ -633,15 +808,12 @@ class CommandFactory {
|
||||
actingFactionId = actingFactionId,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
availableBattalionIds = ac.availableBattalionIds.toVector,
|
||||
province = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
selectedHero = HeroConverter.fromProto(gameState.heroes(sc.heroId)),
|
||||
province = gameState.provinces(ac.actingProvinceId),
|
||||
selectedHero = gameState.heroes(sc.heroId),
|
||||
selectedBattalion = sc.battalionId
|
||||
.flatMap(gameState.battalions.get)
|
||||
.map(BattalionConverter.fromProto),
|
||||
.flatMap(gameState.battalions.get),
|
||||
gameId = gameState.gameId,
|
||||
currentDate = DateConverter.fromProto(gameState.currentDate),
|
||||
currentDate = gameState.currentDate.get,
|
||||
currentRoundId = gameState.currentRoundId
|
||||
)
|
||||
|
||||
@@ -649,14 +821,21 @@ 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 = gameState.currentDate.get,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
gameId = gameState.gameId
|
||||
)
|
||||
|
||||
case (ac: TradeAvailableCommand, sc: TradeSelectedCommand) =>
|
||||
TradeCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvince = ProvinceConverter.fromProto(
|
||||
gameState.provinces(ac.actingProvinceId)
|
||||
),
|
||||
actingProvince = gameState.provinces(ac.actingProvinceId),
|
||||
tradeType = sc.tradeType match {
|
||||
case TradeType.UNKNOWN => TradeCommandType.Unknown
|
||||
case TradeType.BUY_FOOD => TradeCommandType.BuyFood
|
||||
@@ -667,31 +846,24 @@ class CommandFactory {
|
||||
amount = sc.amount
|
||||
)
|
||||
case (ac: TrainAvailableCommand, sc: TrainSelectedCommand) =>
|
||||
val province =
|
||||
ProvinceConverter.fromProto(gameState.provinces(ac.actingProvinceId))
|
||||
val province = gameState.provinces(ac.actingProvinceId)
|
||||
TrainCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
availableHeroIds = ac.availableHeroIds.toVector,
|
||||
actingProvince = province,
|
||||
actingHero =
|
||||
HeroConverter.fromProto(gameState.heroes(sc.actingHeroId)),
|
||||
actingHero = gameState.heroes(sc.actingHeroId),
|
||||
provinceBattalions = province.battalionIds
|
||||
.map(gameState.battalions)
|
||||
.map(BattalionConverter.fromProto),
|
||||
.map(gameState.battalions),
|
||||
battalionTypes = gameState.battalionTypes.toVector
|
||||
)
|
||||
case (ac: TravelAvailableCommand, _: TravelSelectedCommand) =>
|
||||
val province =
|
||||
ProvinceConverter.fromProto(gameState.provinces(ac.actingProvinceId))
|
||||
val province = gameState.provinces(ac.actingProvinceId)
|
||||
TravelCommand.make(
|
||||
province = province,
|
||||
rulingHero = HeroConverter.fromProto(
|
||||
gameState.heroes(province.rulingHeroId.get)
|
||||
),
|
||||
rulingHero = gameState.heroes(province.rulingHeroId.get),
|
||||
unaffiliatedHeroes = province.unaffiliatedHeroes
|
||||
.map(_.heroId)
|
||||
.map(gameState.heroes)
|
||||
.map(HeroConverter.fromProto)
|
||||
)
|
||||
|
||||
case x =>
|
||||
@@ -699,18 +871,6 @@ class CommandFactory {
|
||||
s"$x failed to match AvailableCommand / SelectedCommand pair: $availableCommand / $selectedCommand"
|
||||
)
|
||||
}) match {
|
||||
case simpleAction: SimpleAction =>
|
||||
new SimpleActionWrapper(
|
||||
startingState = gameState,
|
||||
simpleAction = simpleAction,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
case randomSimpleAction: RandomSimpleAction =>
|
||||
new RandomSimpleActionWrapper(
|
||||
startingState = gameState,
|
||||
randomSimpleAction = randomSimpleAction,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
case protolessSimpleAction: ProtolessSimpleAction =>
|
||||
new ProtolessSimpleActionWrapper(
|
||||
startingState = gameState,
|
||||
@@ -723,10 +883,10 @@ class CommandFactory {
|
||||
protolessRandomSimpleAction = protolessRandomSimpleAction,
|
||||
selectedCommand = selectedCommand
|
||||
)
|
||||
case protolessSequentialResutlsAction: ProtolessSequentialResultsAction =>
|
||||
case protolessSequentialResultsAction: ProtolessSequentialResultsAction =>
|
||||
new ProtolessSequentialResultsActionWrapper(
|
||||
startingState = gameState,
|
||||
protolessSequentialResultsAction = protolessSequentialResutlsAction
|
||||
protolessSequentialResultsAction = protolessSequentialResultsAction
|
||||
)
|
||||
|
||||
case c: Command => c
|
||||
|
||||
@@ -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.map(ProvinceId(_))
|
||||
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.value),
|
||||
province = Some(province.id.value),
|
||||
provinceActed = Some(province.id.value),
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplier
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ActionWithResultingState,
|
||||
DeterministicSingleResultAction,
|
||||
VigorXPApplier
|
||||
}
|
||||
|
||||
abstract class DeterministicSingleResultCommand(
|
||||
startingState: GameState,
|
||||
val selectedCommand: SelectedCommand
|
||||
) extends DeterministicSingleResultAction(startingState)
|
||||
with Command {
|
||||
override def execute(
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): Vector[ActionWithResultingState] =
|
||||
VigorXPApplier.withVigorXp(immediateExecute) match {
|
||||
case result =>
|
||||
Vector(
|
||||
actionResultProtoApplier.applyActionResult(
|
||||
startingState = startingState,
|
||||
result = Command.resultWithLastCommand(
|
||||
result = result,
|
||||
selectedCommand = selectedCommand,
|
||||
factionId = result.province
|
||||
.map(startingState.provinces)
|
||||
.flatMap(_.rulingFactionId)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+285
-348
@@ -1,278 +1,208 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.DiplomacyAvailableCommand
|
||||
import net.eagle0.eagle.api.command.util.diplomacy_option.{
|
||||
AllianceOption,
|
||||
BreakAllianceOption,
|
||||
DiplomacyOption,
|
||||
InvitationOption,
|
||||
RansomOfferOption,
|
||||
TruceOption
|
||||
}
|
||||
import net.eagle0.eagle.api.selected_command.DiplomacySelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.{
|
||||
ALLIANCE_BROKEN,
|
||||
ALLIANCE_OFFERED,
|
||||
FACTION_INVITED,
|
||||
RANSOM_STARTED,
|
||||
TRUCE_OFFERED
|
||||
}
|
||||
import net.eagle0.eagle.common.date.Date
|
||||
import net.eagle0.eagle.common.diplomacy_offer.{
|
||||
AllianceOfferDetails,
|
||||
BreakAllianceDetails,
|
||||
DiplomacyOffer,
|
||||
InvitationDetails,
|
||||
RansomOfferDetails,
|
||||
TruceOfferDetails
|
||||
}
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus.DIPLOMACY_OFFER_STATUS_UNRESOLVED
|
||||
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.changed_hero.ChangedHero.Vigor.VigorDelta
|
||||
import net.eagle0.eagle.internal.changed_province.ChangedProvince
|
||||
import net.eagle0.eagle.internal.generated_text_request.{
|
||||
AllianceOfferMessage,
|
||||
BreakAllianceMessage,
|
||||
InvitationMessage,
|
||||
GeneratedTextRequest,
|
||||
RansomOfferMessage,
|
||||
TruceOfferMessage
|
||||
}
|
||||
import net.eagle0.eagle.library.actions.impl.common.SimpleAction
|
||||
import net.eagle0.eagle.library.settings.{ActionVigorCost, TruceMonths}
|
||||
import net.eagle0.eagle.library.util.DateProtoUtils._Date
|
||||
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.model.state.diplomacy_option.DiplomacyOption
|
||||
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,
|
||||
ChangedHeroC,
|
||||
StatDelta
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.concrete.ChangedFactionC.{
|
||||
OutgoingAllianceOfferFactionId,
|
||||
OutgoingInvitationFactionId,
|
||||
OutgoingRansomOfferFactionId,
|
||||
OutgoingTruceOfferFactionId
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.LlmRequestT
|
||||
import net.eagle0.eagle.model.action_result.types.{
|
||||
AllianceBrokenResultType,
|
||||
AllianceOfferedResultType,
|
||||
FactionInvitedResultType,
|
||||
RansomStartedResultType,
|
||||
TruceOfferedResultType
|
||||
}
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.{
|
||||
AllianceOffer,
|
||||
BreakAlliance,
|
||||
Invitation,
|
||||
RansomOffer,
|
||||
RansomOfferDetails,
|
||||
TruceOffer
|
||||
}
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.Unresolved
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.library.settings.{ActionVigorCost, TruceMonths}
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
|
||||
object DiplomacyCommand {
|
||||
|
||||
private def optionTargetFid(
|
||||
option: DiplomacyOption.NonEmpty
|
||||
): FactionId =
|
||||
private def optionTargetFid(option: DiplomacyOption): FactionId =
|
||||
option match {
|
||||
case TruceOption(tfid, _, _ /* unknownFieldSet */ ) => FactionId(tfid)
|
||||
case InvitationOption(tfid, _, _ /* unknownFieldSet */ ) =>
|
||||
FactionId(tfid)
|
||||
case RansomOfferOption(tfid, _, _ /* unknownFieldSet */ ) =>
|
||||
FactionId(tfid)
|
||||
case AllianceOption(tfid, _, _ /* unknownFieldSet */ ) => FactionId(tfid)
|
||||
case BreakAllianceOption(tfid, _, _ /* unknownFieldSet */ ) =>
|
||||
FactionId(tfid)
|
||||
case DiplomacyOption.TruceOption(tfid, _) => tfid
|
||||
case DiplomacyOption.InvitationOption(tfid, _) => tfid
|
||||
case DiplomacyOption.RansomOfferOption(tfid, _, _, _, _) => tfid
|
||||
case DiplomacyOption.AllianceOption(tfid, _) => tfid
|
||||
case DiplomacyOption.BreakAllianceOption(tfid, _) => tfid
|
||||
}
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: DiplomacyAvailableCommand,
|
||||
selectedCommand: DiplomacySelectedCommand,
|
||||
sentHeroId: HeroId,
|
||||
availableHeroIds: Vector[HeroId],
|
||||
selectedOption: DiplomacyOption,
|
||||
availableOptions: Vector[DiplomacyOption],
|
||||
actingProvince: ProvinceT,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
): SimpleAction = {
|
||||
val targetFid = selectedCommand.targetFactionId
|
||||
val selectedOption = selectedCommand.selectedOption
|
||||
): ProtolessSimpleAction = {
|
||||
val targetFactionId = optionTargetFid(selectedOption)
|
||||
|
||||
val actingHeroId = sentHeroId
|
||||
|
||||
commandRequire(
|
||||
!selectedOption.isEmpty,
|
||||
s"Selected an empty diplomacy option"
|
||||
availableHeroIds.contains(actingHeroId),
|
||||
s"Sent hero $sentHeroId was not in available options $availableHeroIds"
|
||||
)
|
||||
|
||||
val nonEmptySelectedOption = selectedOption.asNonEmpty.get
|
||||
|
||||
commandRequire(
|
||||
optionTargetFid(nonEmptySelectedOption) == targetFid,
|
||||
s"Target fid $targetFid did not match selected option $selectedOption"
|
||||
)
|
||||
|
||||
val actingHeroId = selectedCommand.sentHeroId
|
||||
|
||||
nonEmptySelectedOption match {
|
||||
case InvitationOption(_, goldCost, _ /* unknownFieldSet */ ) =>
|
||||
selectedOption match {
|
||||
case DiplomacyOption.InvitationOption(_, goldCost) =>
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds
|
||||
.contains(actingHeroId),
|
||||
s"Sent hero ${selectedCommand.sentHeroId} was not in available options ${availableCommand.availableHeroIds}"
|
||||
availableOptions.contains(selectedOption),
|
||||
s"Selected option $selectedOption was not in available options $availableOptions"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableCommand.options.contains(nonEmptySelectedOption),
|
||||
s"There was no available option $nonEmptySelectedOption for target faction $targetFid"
|
||||
)
|
||||
|
||||
InviteCommand(
|
||||
sc = selectedCommand,
|
||||
actingProvince = actingProvince,
|
||||
fid = actingFactionId,
|
||||
targetFid = FactionId(targetFid),
|
||||
actingHero = HeroId(actingHeroId),
|
||||
targetFid = targetFactionId,
|
||||
actingHero = actingHeroId,
|
||||
goldCost = goldCost,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
|
||||
case TruceOption(_, goldCost, _ /* unknownFieldSet */ ) =>
|
||||
case DiplomacyOption.TruceOption(_, goldCost) =>
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds
|
||||
.contains(actingHeroId),
|
||||
s"Sent hero ${selectedCommand.sentHeroId} was not in available options ${availableCommand.availableHeroIds}"
|
||||
availableOptions.contains(selectedOption),
|
||||
s"Selected option $selectedOption was not in available options $availableOptions"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableCommand.options.contains(nonEmptySelectedOption),
|
||||
s"There was no available option $nonEmptySelectedOption for target faction $targetFid"
|
||||
)
|
||||
|
||||
TruceCommand(
|
||||
sc = selectedCommand,
|
||||
actingProvince = actingProvince,
|
||||
fid = actingFactionId,
|
||||
targetFid = FactionId(targetFid),
|
||||
actingHero = HeroId(actingHeroId),
|
||||
targetFid = targetFactionId,
|
||||
actingHero = actingHeroId,
|
||||
goldCost = goldCost,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
case RansomOfferOption(
|
||||
case DiplomacyOption.RansomOfferOption(
|
||||
_,
|
||||
ransomOfferOption: Option[RansomOfferDetails],
|
||||
_ /* unknownFieldSet */
|
||||
prisonerToBeRansomed,
|
||||
prisonersOffered,
|
||||
hostagesOffered,
|
||||
goldOffered
|
||||
) =>
|
||||
commandRequire(
|
||||
ransomOfferOption.nonEmpty,
|
||||
"Must specify a ransom offer"
|
||||
)
|
||||
|
||||
val ransomOffer = ransomOfferOption.get
|
||||
commandRequire(
|
||||
ransomOffer.goldOffered > 0 || ransomOffer.hostagesOffered.nonEmpty || ransomOffer.prisonersOffered.nonEmpty,
|
||||
goldOffered > 0 || hostagesOffered.nonEmpty || prisonersOffered.nonEmpty,
|
||||
"Must select gold, hostages, or prisoners"
|
||||
)
|
||||
|
||||
val availableOptionOpt = availableCommand.options.collectFirst {
|
||||
case x @ RansomOfferOption(
|
||||
tfid,
|
||||
availableOffer,
|
||||
_ /* unknownFieldSet */
|
||||
)
|
||||
if tfid == targetFid
|
||||
&& availableOffer.get.prisonerToBeRansomed == ransomOffer.prisonerToBeRansomed =>
|
||||
x
|
||||
// Validation logic for ransom offers
|
||||
val prisonerHeroId = prisonerToBeRansomed.prisonerHeroId
|
||||
val prisonerProvinceId = prisonerToBeRansomed.provinceIdForPrisoner
|
||||
|
||||
// Basic validation that required fields are present
|
||||
commandRequire(
|
||||
prisonerHeroId > 0,
|
||||
s"Invalid prisoner hero ID: $prisonerHeroId"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
prisonerProvinceId > 0,
|
||||
s"Invalid prisoner province ID: $prisonerProvinceId"
|
||||
)
|
||||
|
||||
// Validate that we have prisoners and/or hostages if offering them
|
||||
if prisonersOffered.nonEmpty then {
|
||||
prisonersOffered.foreach { prisoner =>
|
||||
commandRequire(
|
||||
prisoner.heroId > 0,
|
||||
s"Invalid offered prisoner hero ID: ${prisoner.heroId}"
|
||||
)
|
||||
commandRequire(
|
||||
prisoner.provinceIdWithHero > 0,
|
||||
s"Invalid offered prisoner province ID: ${prisoner.provinceIdWithHero}"
|
||||
)
|
||||
}
|
||||
}
|
||||
commandRequire(
|
||||
availableOptionOpt.isDefined,
|
||||
s"No ransom command available for target fid $targetFid"
|
||||
)
|
||||
val availableOption = availableOptionOpt.get.ransomOffer.get
|
||||
|
||||
commandRequire(
|
||||
ransomOffer.hostagesOffered.forall(
|
||||
availableOption.hostagesOffered.contains
|
||||
),
|
||||
s"Offered hostages ${ransomOffer.hostagesOffered.map(_.heroId)} are not all among available ${availableOption.hostagesOffered
|
||||
.map(_.heroId)}"
|
||||
)
|
||||
if hostagesOffered.nonEmpty then {
|
||||
hostagesOffered.foreach { hostage =>
|
||||
commandRequire(
|
||||
hostage.heroId > 0,
|
||||
s"Invalid offered hostage hero ID: ${hostage.heroId}"
|
||||
)
|
||||
commandRequire(
|
||||
hostage.provinceIdWithHero > 0,
|
||||
s"Invalid offered hostage province ID: ${hostage.provinceIdWithHero}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
commandRequire(
|
||||
ransomOffer.prisonersOffered.forall(
|
||||
availableOption.prisonersOffered.contains
|
||||
),
|
||||
s"Offered prisoners ${ransomOffer.prisonersOffered.map(_.heroId)} are not all among available ${availableOption.prisonersOffered
|
||||
.map(_.heroId)}"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
ransomOffer.prisonerToBeRansomed.isDefined,
|
||||
"Must select a prisoner to ransom"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableOption.prisonerToBeRansomed.contains(
|
||||
ransomOffer.getPrisonerToBeRansomed
|
||||
),
|
||||
s"Selected prisoner to ransom ${ransomOffer.getPrisonerToBeRansomed} is not among available ${availableOption.prisonerToBeRansomed}"
|
||||
)
|
||||
|
||||
val selectedGold = ransomOffer.goldOffered
|
||||
commandRequire(
|
||||
selectedGold <= availableOption.goldOffered,
|
||||
s"Tried to send $selectedGold gold but only ${availableOption.goldOffered} available"
|
||||
)
|
||||
commandRequire(
|
||||
selectedGold >= 0,
|
||||
"Can't send negative gold"
|
||||
)
|
||||
// Validate gold offering
|
||||
if goldOffered > 0 then {
|
||||
commandRequire(
|
||||
actingProvince.gold >= goldOffered,
|
||||
s"Not enough gold to offer $goldOffered (have ${actingProvince.gold})"
|
||||
)
|
||||
}
|
||||
|
||||
RansomCommand(
|
||||
sc = selectedCommand,
|
||||
ransomOffer = ransomOffer,
|
||||
pid = availableCommand.actingProvinceId,
|
||||
prisonerToBeRansomed = prisonerToBeRansomed,
|
||||
prisonersOffered = prisonersOffered,
|
||||
hostagesOffered = hostagesOffered,
|
||||
goldOffered = goldOffered,
|
||||
pid = actingProvince.id,
|
||||
fid = actingFactionId,
|
||||
targetFid = targetFid,
|
||||
offeringHeroId = selectedCommand.sentHeroId,
|
||||
hidToBeRansomed = ransomOffer.getPrisonerToBeRansomed.prisonerHeroId,
|
||||
goldOffered = selectedGold,
|
||||
hostageHidsOffered =
|
||||
ransomOffer.hostagesOffered.toVector.map(_.heroId),
|
||||
prisonerHidsOffered =
|
||||
ransomOffer.prisonersOffered.toVector.map(_.heroId),
|
||||
targetFid = targetFactionId,
|
||||
offeringHeroId = sentHeroId,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
|
||||
case AllianceOption(
|
||||
targetFactionId,
|
||||
goldCost,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
case DiplomacyOption.AllianceOption(_, goldCost) =>
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds
|
||||
.contains(actingHeroId),
|
||||
s"Sent hero ${selectedCommand.sentHeroId} was not in available options ${availableCommand.availableHeroIds}"
|
||||
availableOptions.contains(selectedOption),
|
||||
s"Selected option $selectedOption was not in available options $availableOptions"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableCommand.options.contains(nonEmptySelectedOption),
|
||||
s"There was no available option $nonEmptySelectedOption for target faction $targetFid"
|
||||
)
|
||||
|
||||
AllianceCommand(
|
||||
sc = selectedCommand,
|
||||
actingProvince = actingProvince,
|
||||
fid = actingFactionId,
|
||||
targetFid = targetFactionId,
|
||||
actingHero = selectedCommand.sentHeroId,
|
||||
actingHero = sentHeroId,
|
||||
goldCost = goldCost,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
currentDate = currentDate
|
||||
)
|
||||
|
||||
case BreakAllianceOption(
|
||||
targetFactionId,
|
||||
goldCost,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
case DiplomacyOption.BreakAllianceOption(_, goldCost) =>
|
||||
commandRequire(
|
||||
availableCommand.availableHeroIds
|
||||
.contains(actingHeroId),
|
||||
s"Sent hero ${selectedCommand.sentHeroId} was not in available options ${availableCommand.availableHeroIds}"
|
||||
availableOptions.contains(selectedOption),
|
||||
s"Selected option $selectedOption was not in available options $availableOptions"
|
||||
)
|
||||
|
||||
commandRequire(
|
||||
availableCommand.options.contains(nonEmptySelectedOption),
|
||||
s"There was no available option $nonEmptySelectedOption for target faction $targetFid"
|
||||
)
|
||||
|
||||
BreakAllianceCommand(
|
||||
sc = selectedCommand,
|
||||
actingProvince = actingProvince,
|
||||
fid = actingFactionId,
|
||||
targetFid = targetFactionId,
|
||||
actingHero = selectedCommand.sentHeroId,
|
||||
actingHero = sentHeroId,
|
||||
goldCost = goldCost,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId,
|
||||
@@ -285,28 +215,29 @@ object DiplomacyCommand {
|
||||
actingProvince: ProvinceT,
|
||||
actingHero: HeroId,
|
||||
goldCost: Int
|
||||
): ActionResult =
|
||||
ActionResult(
|
||||
province = Some(actingProvince.id),
|
||||
player = actingProvince.rulingFactionId,
|
||||
provinceActed = Some(actingProvince.id),
|
||||
changedHeroes = Vector(
|
||||
ChangedHero(
|
||||
id = actingHero,
|
||||
vigor = VigorDelta(-ActionVigorCost.intValue)
|
||||
)
|
||||
),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = actingProvince.id,
|
||||
goldDelta = Some(-goldCost),
|
||||
removedRulingPlayerHeroIds = Vector(actingHero)
|
||||
)
|
||||
)
|
||||
): ActionResultC = {
|
||||
val heroChange = ChangedHeroC(
|
||||
heroId = actingHero,
|
||||
vigorChange = StatDelta(-ActionVigorCost.intValue)
|
||||
)
|
||||
|
||||
val provinceChange = ChangedProvinceC(
|
||||
provinceId = actingProvince.id,
|
||||
goldDelta = Some(-goldCost),
|
||||
removedRulingFactionHeroIds = Vector(actingHero)
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
actionResultType = TruceOfferedResultType, // Will be overridden
|
||||
provinceId = Some(actingProvince.id),
|
||||
actingFactionId = actingProvince.rulingFactionId,
|
||||
provinceIdActed = Some(actingProvince.id),
|
||||
changedHeroes = Vector(heroChange),
|
||||
changedProvinces = Vector(provinceChange)
|
||||
)
|
||||
}
|
||||
|
||||
private case class TruceCommand(
|
||||
sc: DiplomacySelectedCommand,
|
||||
actingProvince: ProvinceT,
|
||||
fid: FactionId,
|
||||
targetFid: FactionId,
|
||||
@@ -315,54 +246,54 @@ object DiplomacyCommand {
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
) extends SimpleAction {
|
||||
) extends ProtolessSimpleAction {
|
||||
private val textId =
|
||||
s"round $currentRoundId truce offer / province ${actingProvince.id} / faction $fid / targetFaction $targetFid"
|
||||
|
||||
private val truceOffer = DiplomacyOffer(
|
||||
private val truceOffer = TruceOffer(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero,
|
||||
messengerOriginProvinceId = actingProvince.id,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
status = Unresolved,
|
||||
offerTextId = textId,
|
||||
offerDetails = TruceOfferDetails(endDate =
|
||||
Some(currentDate.addMonths(TruceMonths.intValue))
|
||||
)
|
||||
endDate = currentDate.addMonths(TruceMonths.intValue)
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
override def immediateExecute: ActionResultT = {
|
||||
genericDiplomacyResult(
|
||||
actingProvince = actingProvince,
|
||||
actingHero = actingHero,
|
||||
goldCost = goldCost
|
||||
).update(
|
||||
_.`type` := TRUCE_OFFERED,
|
||||
_.changedFactions := Vector(
|
||||
ChangedFaction(
|
||||
id = targetFid.value,
|
||||
addedIncomingDiplomacyOffers = Vector(truceOffer)
|
||||
).copy(
|
||||
actionResultType = TruceOfferedResultType,
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = targetFid,
|
||||
newIncomingDiplomacyOffers = Vector(truceOffer)
|
||||
),
|
||||
ChangedFaction(
|
||||
id = fid.value,
|
||||
addedOutgoingTruceOfferPartners = Vector(targetFid.value)
|
||||
ChangedFactionC(
|
||||
factionId = fid,
|
||||
newOutgoingTruceOfferFactionIds =
|
||||
Vector(OutgoingTruceOfferFactionId(targetFid))
|
||||
)
|
||||
),
|
||||
_.newGeneratedTextRequests :+= GeneratedTextRequest(
|
||||
id = textId,
|
||||
eagleGameId = gameId,
|
||||
details = TruceOfferMessage(
|
||||
newGeneratedTextRequests = Vector(
|
||||
LlmRequestT.TruceOfferMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(targetFid),
|
||||
alwaysGenerate = false,
|
||||
offeringFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero
|
||||
),
|
||||
recipientFactionIds = Vector(targetFid)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class AllianceCommand(
|
||||
sc: DiplomacySelectedCommand,
|
||||
actingProvince: ProvinceT,
|
||||
fid: FactionId,
|
||||
targetFid: FactionId,
|
||||
@@ -371,52 +302,53 @@ object DiplomacyCommand {
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
) extends SimpleAction {
|
||||
) extends ProtolessSimpleAction {
|
||||
private val textId =
|
||||
s"round $currentRoundId alliance offer / province ${actingProvince.id} / faction $fid / targetFaction $targetFid"
|
||||
|
||||
private val allianceOffer = DiplomacyOffer(
|
||||
private val allianceOffer = AllianceOffer(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero,
|
||||
messengerOriginProvinceId = actingProvince.id,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
offerTextId = textId,
|
||||
offerDetails = AllianceOfferDetails()
|
||||
status = Unresolved,
|
||||
offerTextId = textId
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
override def immediateExecute: ActionResultT = {
|
||||
genericDiplomacyResult(
|
||||
actingProvince = actingProvince,
|
||||
actingHero = actingHero,
|
||||
goldCost = goldCost
|
||||
).update(
|
||||
_.`type` := ALLIANCE_OFFERED,
|
||||
_.changedFactions := Vector(
|
||||
ChangedFaction(
|
||||
id = targetFid.value,
|
||||
addedIncomingDiplomacyOffers = Vector(allianceOffer)
|
||||
).copy(
|
||||
actionResultType = AllianceOfferedResultType,
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = targetFid,
|
||||
newIncomingDiplomacyOffers = Vector(allianceOffer)
|
||||
),
|
||||
ChangedFaction(
|
||||
id = fid.value,
|
||||
addedOutgoingAllianceOfferPartners = Vector(targetFid.value)
|
||||
ChangedFactionC(
|
||||
factionId = fid,
|
||||
newOutgoingAllianceOfferFactionIds =
|
||||
Vector(OutgoingAllianceOfferFactionId(targetFid))
|
||||
)
|
||||
),
|
||||
_.newGeneratedTextRequests :+= GeneratedTextRequest(
|
||||
id = textId,
|
||||
eagleGameId = gameId,
|
||||
details = AllianceOfferMessage(
|
||||
newGeneratedTextRequests = Vector(
|
||||
LlmRequestT.AllianceOfferMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(targetFid),
|
||||
alwaysGenerate = false,
|
||||
offeringFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero
|
||||
),
|
||||
recipientFactionIds = Vector(targetFid)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class BreakAllianceCommand(
|
||||
sc: DiplomacySelectedCommand,
|
||||
actingProvince: ProvinceT,
|
||||
fid: FactionId,
|
||||
targetFid: FactionId,
|
||||
@@ -425,48 +357,48 @@ object DiplomacyCommand {
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId,
|
||||
currentDate: Date
|
||||
) extends SimpleAction {
|
||||
) extends ProtolessSimpleAction {
|
||||
val textId =
|
||||
s"round $currentRoundId break alliance offer / province ${actingProvince.id} / faction $fid / targetFaction $targetFid"
|
||||
|
||||
private val breakAllianceOffer = DiplomacyOffer(
|
||||
private val breakAllianceOffer = BreakAlliance(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero,
|
||||
messengerOriginProvinceId = actingProvince.id,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
offerTextId = textId,
|
||||
offerDetails = BreakAllianceDetails()
|
||||
status = Unresolved,
|
||||
offerTextId = textId
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
override def immediateExecute: ActionResultT = {
|
||||
genericDiplomacyResult(
|
||||
actingProvince = actingProvince,
|
||||
actingHero = actingHero,
|
||||
goldCost = goldCost
|
||||
).update(
|
||||
_.`type` := ALLIANCE_BROKEN,
|
||||
_.changedFactions := Vector(
|
||||
ChangedFaction(
|
||||
id = targetFid.value,
|
||||
addedIncomingDiplomacyOffers = Vector(breakAllianceOffer)
|
||||
).copy(
|
||||
actionResultType = AllianceBrokenResultType,
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = targetFid,
|
||||
newIncomingDiplomacyOffers = Vector(breakAllianceOffer)
|
||||
)
|
||||
),
|
||||
_.newGeneratedTextRequests :+= GeneratedTextRequest(
|
||||
id = textId,
|
||||
eagleGameId = gameId,
|
||||
details = BreakAllianceMessage(
|
||||
newGeneratedTextRequests = Vector(
|
||||
LlmRequestT.BreakAllianceMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(targetFid),
|
||||
alwaysGenerate = false,
|
||||
breakingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero
|
||||
),
|
||||
recipientFactionIds = Vector(targetFid)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class InviteCommand(
|
||||
sc: DiplomacySelectedCommand,
|
||||
actingProvince: ProvinceT,
|
||||
fid: FactionId,
|
||||
targetFid: FactionId,
|
||||
@@ -474,109 +406,114 @@ object DiplomacyCommand {
|
||||
goldCost: Int,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
) extends ProtolessSimpleAction {
|
||||
private val textId =
|
||||
s"round $currentRoundId invitation / province ${actingProvince.id} / faction $fid / targetFaction $targetFid"
|
||||
|
||||
private val invitation = DiplomacyOffer(
|
||||
private val invitation = Invitation(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero,
|
||||
messengerOriginProvinceId = actingProvince.id,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
offerTextId = textId,
|
||||
offerDetails = InvitationDetails()
|
||||
status = Unresolved,
|
||||
offerTextId = textId
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
override def immediateExecute: ActionResultT = {
|
||||
genericDiplomacyResult(
|
||||
actingProvince = actingProvince,
|
||||
actingHero = actingHero,
|
||||
goldCost = goldCost
|
||||
).update(
|
||||
_.`type` := FACTION_INVITED,
|
||||
_.changedFactions := Vector(
|
||||
ChangedFaction(
|
||||
id = targetFid.value,
|
||||
addedIncomingDiplomacyOffers = Vector(invitation)
|
||||
).copy(
|
||||
actionResultType = FactionInvitedResultType,
|
||||
changedFactions = Vector(
|
||||
ChangedFactionC(
|
||||
factionId = targetFid,
|
||||
newIncomingDiplomacyOffers = Vector(invitation)
|
||||
),
|
||||
ChangedFaction(
|
||||
id = fid.value,
|
||||
addedOutgoingInvitationPartners = Vector(targetFid.value)
|
||||
ChangedFactionC(
|
||||
factionId = fid,
|
||||
newOutgoingInvitationFactionIds =
|
||||
Vector(OutgoingInvitationFactionId(targetFid))
|
||||
)
|
||||
),
|
||||
_.newGeneratedTextRequests :+= GeneratedTextRequest(
|
||||
id = textId,
|
||||
eagleGameId = gameId.value,
|
||||
details = InvitationMessage(
|
||||
offeringFactionId = fid.value,
|
||||
targetFactionId = targetFid.value,
|
||||
messengerHeroId = actingHero.value
|
||||
),
|
||||
recipientFactionIds = Vector(targetFid.value)
|
||||
newGeneratedTextRequests = Vector(
|
||||
LlmRequestT.InvitationMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
recipientFactionIds = Vector(targetFid),
|
||||
alwaysGenerate = false,
|
||||
invitingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = actingHero
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private case class RansomCommand(
|
||||
sc: DiplomacySelectedCommand,
|
||||
ransomOffer: RansomOfferDetails,
|
||||
prisonerToBeRansomed: RansomOfferDetails.PrisonerToBeRansomed,
|
||||
prisonersOffered: Vector[RansomOfferDetails.PrisonerOfferedInExchange],
|
||||
hostagesOffered: Vector[RansomOfferDetails.HostageOfferedInExchange],
|
||||
goldOffered: Int,
|
||||
pid: ProvinceId,
|
||||
fid: FactionId,
|
||||
targetFid: FactionId,
|
||||
offeringHeroId: HeroId,
|
||||
hidToBeRansomed: HeroId,
|
||||
goldOffered: Int,
|
||||
hostageHidsOffered: Vector[HeroId],
|
||||
prisonerHidsOffered: Vector[HeroId],
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
) extends ProtolessSimpleAction {
|
||||
private val textId =
|
||||
s"round $currentRoundId ransom offer / province $pid / faction $fid / targetFaction $targetFid"
|
||||
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = RANSOM_STARTED,
|
||||
province = Some(pid.value),
|
||||
player = Some(fid.value),
|
||||
provinceActed = Some(pid.value),
|
||||
private val ransomOffer = RansomOffer(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = offeringHeroId,
|
||||
messengerOriginProvinceId = pid,
|
||||
status = Unresolved,
|
||||
offerTextId = textId,
|
||||
prisonerToBeRansomed = prisonerToBeRansomed,
|
||||
prisonersOffered = prisonersOffered,
|
||||
hostagesOffered = hostagesOffered,
|
||||
goldOffered = goldOffered
|
||||
)
|
||||
|
||||
override def immediateExecute: ActionResultT = {
|
||||
ActionResultC(
|
||||
actionResultType = RansomStartedResultType,
|
||||
provinceId = Some(pid),
|
||||
actingFactionId = Some(fid),
|
||||
provinceIdActed = Some(pid),
|
||||
changedFactions = Vector(
|
||||
ChangedFaction(
|
||||
id = targetFid.value,
|
||||
addedIncomingDiplomacyOffers = Vector(
|
||||
DiplomacyOffer(
|
||||
originatingFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
messengerHeroId = offeringHeroId,
|
||||
messengerOriginProvinceId = pid,
|
||||
status = DIPLOMACY_OFFER_STATUS_UNRESOLVED,
|
||||
offerTextId = textId,
|
||||
offerDetails = ransomOffer
|
||||
)
|
||||
)
|
||||
ChangedFactionC(
|
||||
factionId = targetFid,
|
||||
newIncomingDiplomacyOffers = Vector(ransomOffer)
|
||||
),
|
||||
ChangedFaction(
|
||||
id = fid.value,
|
||||
addedOutgoingRansomOfferPartners = Vector(targetFid.value)
|
||||
ChangedFactionC(
|
||||
factionId = fid,
|
||||
newOutgoingRansomOfferFactionIds =
|
||||
Vector(OutgoingRansomOfferFactionId(targetFid))
|
||||
)
|
||||
),
|
||||
newGeneratedTextRequests = Vector(
|
||||
GeneratedTextRequest(
|
||||
id = textId,
|
||||
LlmRequestT.RansomOfferMessage(
|
||||
requestId = textId,
|
||||
eagleGameId = gameId,
|
||||
details = RansomOfferMessage(
|
||||
offeringFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
offeringHeroId = offeringHeroId,
|
||||
ransomedHeroId = hidToBeRansomed,
|
||||
goldOffered = goldOffered,
|
||||
hostageHeroIdsOffered = hostageHidsOffered,
|
||||
prisonerHeroIdsOffered = prisonerHidsOffered
|
||||
),
|
||||
recipientFactionIds = Vector(targetFid)
|
||||
recipientFactionIds = Vector(targetFid),
|
||||
alwaysGenerate = false,
|
||||
offeringFactionId = fid,
|
||||
targetFactionId = targetFid,
|
||||
offeringHeroId = offeringHeroId,
|
||||
ransomedHeroId = prisonerToBeRansomed.prisonerHeroId,
|
||||
goldOffered = goldOffered,
|
||||
hostageHeroIdsOffered = hostagesOffered.map(_.heroId).toVector,
|
||||
prisonerHeroIdsOffered = prisonersOffered.map(_.heroId).toVector
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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,
|
||||
|
||||
+48
-67
@@ -1,46 +1,43 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.FreeForAllDecisionAvailableCommand
|
||||
import net.eagle0.eagle.api.command.util.attack_decision_type.{
|
||||
AdvanceDecision,
|
||||
AttackDecisionType,
|
||||
DemandTributeDecision,
|
||||
SafePassageDecision,
|
||||
WithdrawDecision
|
||||
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.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.model.state.HostileArmyGroupStatus.{
|
||||
AwaitingFreeForAll,
|
||||
Withdrawing
|
||||
}
|
||||
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.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
|
||||
object FreeForAllDecisionCommand {
|
||||
sealed trait FreeForAllDecision
|
||||
case object Advance extends FreeForAllDecision
|
||||
case object Withdraw extends FreeForAllDecision
|
||||
|
||||
private case class FreeForAllAttackCommand(
|
||||
sc: FreeForAllDecisionSelectedCommand,
|
||||
attackingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = ARMY_ADVANCED_TO_FREE_FOR_ALL,
|
||||
player = Some(attackingFactionId.value),
|
||||
province = Some(provinceId.value),
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = ArmyAdvancedToFreeForAllResultType,
|
||||
actingFactionId = Some(attackingFactionId),
|
||||
provinceId = Some(provinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = provinceId.value,
|
||||
ChangedProvinceC(
|
||||
provinceId = provinceId,
|
||||
// set the new status on the hostile army
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = attackingFactionId.value,
|
||||
newStatus = AwaitingFreeForAll()
|
||||
HostileArmyStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = AwaitingFreeForAll
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -49,23 +46,22 @@ object FreeForAllDecisionCommand {
|
||||
}
|
||||
|
||||
private case class FreeForAllWithdrawCommand(
|
||||
sc: FreeForAllDecisionSelectedCommand,
|
||||
attackingFactionId: FactionId,
|
||||
provinceId: ProvinceId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult =
|
||||
ActionResult(
|
||||
`type` = ARMY_WITHDREW_FROM_FREE_FOR_ALL,
|
||||
player = Some(attackingFactionId.value),
|
||||
province = Some(provinceId.value),
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
ActionResultC(
|
||||
actionResultType = ArmyWithdrewFromFreeForAllResultType,
|
||||
actingFactionId = Some(attackingFactionId),
|
||||
provinceId = Some(provinceId),
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = provinceId.value,
|
||||
ChangedProvinceC(
|
||||
provinceId = provinceId,
|
||||
// set the new status on the hostile army
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyGroupStatusChange(
|
||||
factionId = attackingFactionId.value,
|
||||
newStatus = Withdrawing()
|
||||
HostileArmyStatusChange(
|
||||
factionId = attackingFactionId,
|
||||
newStatus = Withdrawing
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -75,40 +71,25 @@ object FreeForAllDecisionCommand {
|
||||
|
||||
def make(
|
||||
actingFactionId: FactionId,
|
||||
availableCommand: FreeForAllDecisionAvailableCommand,
|
||||
selectedCommand: FreeForAllDecisionSelectedCommand
|
||||
): SimpleAction = {
|
||||
val selectedType = selectedCommand.decision
|
||||
|
||||
provinceId: ProvinceId,
|
||||
selectedDecision: FreeForAllDecision,
|
||||
availableDecisions: Vector[FreeForAllDecision]
|
||||
): ProtolessSimpleAction = {
|
||||
commandRequire(
|
||||
availableCommand.availableDecisions
|
||||
.contains(selectedType),
|
||||
s"Selected $selectedType was not in ${availableCommand.availableDecisions}"
|
||||
availableDecisions.contains(selectedDecision),
|
||||
s"Selected $selectedDecision was not in $availableDecisions"
|
||||
)
|
||||
|
||||
selectedCommand.decision match {
|
||||
case AttackDecisionType.Empty =>
|
||||
throw new EagleCommandException(s"Must specify an attack decision type")
|
||||
|
||||
case AdvanceDecision(_ /* unknownFieldSet */ ) =>
|
||||
selectedDecision match {
|
||||
case Advance =>
|
||||
FreeForAllAttackCommand(
|
||||
sc = selectedCommand,
|
||||
attackingFactionId = actingFactionId,
|
||||
provinceId = ProvinceId(availableCommand.provinceId)
|
||||
provinceId = provinceId
|
||||
)
|
||||
case WithdrawDecision(_ /* unknownFieldSet */ ) =>
|
||||
case Withdraw =>
|
||||
FreeForAllWithdrawCommand(
|
||||
sc = selectedCommand,
|
||||
attackingFactionId = actingFactionId,
|
||||
provinceId = ProvinceId(availableCommand.provinceId)
|
||||
)
|
||||
case DemandTributeDecision(_, _ /* unknownFieldSet */ ) =>
|
||||
throw new EagleCommandException(
|
||||
s"Demand Tribute not allowed for free-for-all"
|
||||
)
|
||||
case SafePassageDecision(_, _ /* unknownFieldSet */ ) =>
|
||||
throw new EagleCommandException(
|
||||
s"Safe Passage not allowed for free-for-all"
|
||||
provinceId = provinceId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+87
-64
@@ -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
|
||||
),
|
||||
@@ -325,14 +345,14 @@ object OrganizeTroopsCommand {
|
||||
|
||||
// Merge in moved troops to existing battalions
|
||||
val afterChangingBattalions =
|
||||
(afterAddingBattalions ++ changedBattalions
|
||||
afterAddingBattalions ++ changedBattalions
|
||||
.map { cb =>
|
||||
mergeInMultiple(
|
||||
afterAddingBattalions(cb.id),
|
||||
cb.troopsFromOtherBattalion
|
||||
)
|
||||
}
|
||||
.map(b => b.id -> b)).toMap
|
||||
.map(b => b.id -> b)
|
||||
|
||||
// Add new troops to new battalions
|
||||
val afterAddingForNew =
|
||||
@@ -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.value),
|
||||
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.value).toVector,
|
||||
changedBatt.filter(_.size == 0).map(_.id).toVector,
|
||||
changedProvinces = Vector(
|
||||
ChangedProvince(
|
||||
id = province.id.value,
|
||||
ChangedProvinceC(
|
||||
provinceId = province.id,
|
||||
goldDelta = Some(-afterAddingForChanged.cost),
|
||||
newPriceIndex = PriceIndexUtils.maybeNewPriceIndexFromGoldSpend(
|
||||
province.priceIndex,
|
||||
@@ -371,8 +394,8 @@ object OrganizeTroopsCommand {
|
||||
)
|
||||
)
|
||||
),
|
||||
provinceActed = Some(province.id.value),
|
||||
province = Some(province.id.value)
|
||||
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,
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@ import net.eagle0.common.{RandomState, SeededRandom}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.NEW_RANDOM_SEED
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplier
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ActionWithResultingState,
|
||||
@@ -13,6 +13,7 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
VigorXPApplier
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.ActionResultProtoConverter
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
|
||||
class ProtolessRandomSimpleActionWrapper(
|
||||
startingState: GameState,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.SeededRandom
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.library.actions.applier.{
|
||||
ActionResultProtoApplier,
|
||||
|
||||
+4
-2
@@ -1,7 +1,8 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplier
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ActionWithResultingState,
|
||||
@@ -9,6 +10,7 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
VigorXPApplier
|
||||
}
|
||||
import net.eagle0.eagle.model.proto_converters.ActionResultProtoConverter
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
|
||||
class ProtolessSimpleActionWrapper(
|
||||
startingState: GameState,
|
||||
@@ -24,7 +26,7 @@ class ProtolessSimpleActionWrapper(
|
||||
case result =>
|
||||
Vector(
|
||||
actionResultProtoApplier.applyActionResult(
|
||||
startingState = startingState,
|
||||
startingState = GameStateConverter.toProto(startingState),
|
||||
result = Command.resultWithLastCommand(
|
||||
result = result,
|
||||
selectedCommand = selectedCommand,
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.common.{RandomState, SeededRandom}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType.NEW_RANDOM_SEED
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplier
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ActionWithResultingState,
|
||||
RandomSimpleAction,
|
||||
RandomStateProtoSequencer,
|
||||
VigorXPApplier
|
||||
}
|
||||
|
||||
class RandomSimpleActionWrapper(
|
||||
startingState: GameState,
|
||||
randomSimpleAction: RandomSimpleAction,
|
||||
selectedCommand: SelectedCommand
|
||||
) extends Command {
|
||||
override def execute(
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): Vector[ActionWithResultingState] =
|
||||
RandomStateProtoSequencer(
|
||||
initialState = startingState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = SeededRandom(startingState.randomSeed)
|
||||
)
|
||||
.withRandomActionResult { case (gs, fr) =>
|
||||
randomSimpleAction
|
||||
.immediateExecute(fr)
|
||||
.map(VigorXPApplier.withVigorXp)
|
||||
.map { resultWithVigorXp =>
|
||||
Command.resultWithLastCommand(
|
||||
result = resultWithVigorXp,
|
||||
selectedCommand = selectedCommand,
|
||||
factionId = resultWithVigorXp.province
|
||||
.map(startingState.provinces)
|
||||
.flatMap(_.rulingFactionId)
|
||||
)
|
||||
}
|
||||
}
|
||||
.withRandomActionResult { case (gs, fr) =>
|
||||
RandomState(
|
||||
ActionResult(
|
||||
`type` = NEW_RANDOM_SEED,
|
||||
newRandomSeed = Some(fr.seed)
|
||||
),
|
||||
fr
|
||||
)
|
||||
}
|
||||
.results
|
||||
.newValue
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ abstract class RandomSingleResultCommand(
|
||||
actionResultProtoApplier: ActionResultProtoApplier
|
||||
): Vector[ActionWithResultingState] =
|
||||
RandomStateProtoSequencer(
|
||||
initialState = startingState,
|
||||
initialStateProto = startingState,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = SeededRandom(startingState.randomSeed)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
+163
-117
@@ -1,135 +1,181 @@
|
||||
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,
|
||||
allianceOffer: AllianceOffer,
|
||||
resolution: Status,
|
||||
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 - use availableResolutions from AvailableCommand instead of allianceOffer.eligibleStatuses
|
||||
commandRequire(
|
||||
selectedOffer.nonEmpty,
|
||||
s"Selected faction ID $offeringFid was not among options ${offers.map(_.originatingFactionId)}"
|
||||
)
|
||||
|
||||
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,
|
||||
allianceOffer = allianceOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
}
|
||||
|
||||
private case class ResolveAllianceOfferCommand(
|
||||
actingFactionId: FactionId,
|
||||
allianceOffer: AllianceOffer,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"${currentRoundId} resolve alliance offer ${allianceOffer.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(allianceOffer.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(allianceOffer.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(allianceOffer.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 = allianceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case Rejected =>
|
||||
NotificationDetails.AllianceRejected(
|
||||
offeringFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case Imprisoned =>
|
||||
NotificationDetails.AllianceAmbassadorImprisoned(
|
||||
offeringFactionId = allianceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
ambassadorHeroId = allianceOffer.messengerHeroId
|
||||
)
|
||||
|
||||
case _ =>
|
||||
throw new EagleCommandException(s"Unexpected status: $status")
|
||||
},
|
||||
affectedProvinceIds = Vector(),
|
||||
affectedHeroIds = Vector(allianceOffer.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 = allianceOffer.originatingFactionId,
|
||||
targetFactionId = actingFactionId,
|
||||
messengerHeroId = allianceOffer.messengerHeroId,
|
||||
resolution = status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+125
-104
@@ -1,133 +1,154 @@
|
||||
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, HeroId, 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,
|
||||
breakAllianceOffer: BreakAlliance,
|
||||
resolution: Status,
|
||||
gameId: GameId,
|
||||
currentRoundId: RoundId
|
||||
) extends SimpleAction {
|
||||
override def immediateExecute: ActionResult = {
|
||||
val llmRequest =
|
||||
DiplomacyResolutionLlmRequestGenerator.breakAllianceResolutionRequest(
|
||||
gameId = gameId.value,
|
||||
currentRoundId = currentRoundId.value,
|
||||
originatingFactionId =
|
||||
FactionId(breakAllianceOffer.originatingFactionId),
|
||||
targetFactionId = FactionId(breakAllianceOffer.targetFactionId),
|
||||
messengerHeroId = HeroId(breakAllianceOffer.messengerHeroId),
|
||||
resolution = resolution
|
||||
)
|
||||
) extends ProtolessSimpleAction {
|
||||
private val originatingFactionId = breakAllianceOffer.originatingFactionId
|
||||
private val messengerHeroId = breakAllianceOffer.messengerHeroId
|
||||
private val messengerOriginProvinceId =
|
||||
breakAllianceOffer.messengerOriginProvinceId
|
||||
|
||||
ActionResult(
|
||||
`type` = ActionResultType.OFFER_RESOLVED,
|
||||
player = Some(breakAllianceOffer.targetFactionId),
|
||||
override def immediateExecute: ActionResultT = {
|
||||
val llmRequestId =
|
||||
s"$currentRoundId resolve break alliance $messengerHeroId"
|
||||
|
||||
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 =
|
||||
FactionId(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 =
|
||||
FactionId(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,
|
||||
breakAllianceOffer: BreakAlliance,
|
||||
resolution: Status,
|
||||
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)}"
|
||||
)
|
||||
|
||||
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,
|
||||
breakAllianceOffer = breakAllianceOffer,
|
||||
resolution = resolution,
|
||||
gameId = gameId,
|
||||
currentRoundId = currentRoundId
|
||||
)
|
||||
|
||||
+221
-204
@@ -1,238 +1,255 @@
|
||||
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
|
||||
availableResolutions: Vector[Status],
|
||||
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 available resolutions from the AvailableCommand
|
||||
commandRequire(
|
||||
availableResolutions.contains(resolution),
|
||||
s"Selected invitation resolution $resolution was not among options $availableResolutions"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+160
-165
@@ -1,184 +1,179 @@
|
||||
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
|
||||
availableResolutions: Vector[Status],
|
||||
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 available resolutions from the AvailableCommand
|
||||
commandRequire(
|
||||
availableResolutions.contains(resolution),
|
||||
s"Selected ransom offer resolution $resolution was not among options $availableResolutions"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+168
-180
@@ -1,195 +1,183 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
import net.eagle0.eagle.api.available_command.{
|
||||
ResolveTributeAvailableCommand,
|
||||
TributeAndFaction
|
||||
}
|
||||
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.{
|
||||
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.actions.impl.common.ProtolessSimpleAction
|
||||
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.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
ActionResultC,
|
||||
ChangedFactionC
|
||||
}
|
||||
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,
|
||||
TributePaid,
|
||||
TributeDemanded
|
||||
}
|
||||
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.model.state.province.ProvinceT
|
||||
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,
|
||||
allProvinces: Vector[ProvinceT]
|
||||
): 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,
|
||||
allProvinces = allProvinces
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
allProvinces: Vector[ProvinceT]
|
||||
) 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)
|
||||
|
||||
// Find other provinces ruled by this faction that have ANY hostile armies from the demanding faction
|
||||
val otherProvinceChanges = allProvinces
|
||||
.filter(province =>
|
||||
province.rulingFactionId.contains(actingFactionId) &&
|
||||
province.id != actingProvinceId
|
||||
)
|
||||
.filter(province =>
|
||||
province.hostileArmies
|
||||
.exists(army => army.factionId == demandingFactionId)
|
||||
)
|
||||
.map { province =>
|
||||
ChangedProvinceC(
|
||||
provinceId = province.id,
|
||||
hostileArmyStatusChanges = Vector(
|
||||
HostileArmyStatusChange(
|
||||
factionId = demandingFactionId,
|
||||
newStatus = TributePaid(TributeAmount(gold = 0, food = 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
)
|
||||
)
|
||||
) ++ otherProvinceChanges,
|
||||
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, FactionId, HeroId}
|
||||
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 = FactionId(truceOffer.originatingFactionId),
|
||||
targetFactionId = FactionId(truceOffer.targetFactionId),
|
||||
messengerHeroId = HeroId(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
|
||||
@@ -180,22 +180,6 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "random_simple_action",
|
||||
srcs = ["RandomSimpleAction.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "random_state_proto_sequencer",
|
||||
srcs = ["RandomStateProtoSequencer.scala"],
|
||||
@@ -205,6 +189,7 @@ scala_library(
|
||||
],
|
||||
exports = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
deps = [
|
||||
":action",
|
||||
@@ -225,6 +210,8 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types/base:action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:action_result_proto_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -237,6 +224,7 @@ scala_library(
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
deps = [
|
||||
":action_with_resulting_state",
|
||||
@@ -256,18 +244,8 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types/base:action_result_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:action_result_proto_converter",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "simple_action",
|
||||
srcs = ["SimpleAction.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.eagle0.eagle.library.actions.impl.common
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
|
||||
trait RandomSimpleAction {
|
||||
def immediateExecute(
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[ActionResult]
|
||||
}
|
||||
+69
-55
@@ -1,79 +1,81 @@
|
||||
package net.eagle0.eagle.library.actions.impl.common
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult as ActionResultProto
|
||||
import net.eagle0.eagle.internal.game_state.GameState as GameStateProto
|
||||
import net.eagle0.eagle.library.actions.applier.ActionResultProtoApplier
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.proto_converters.ActionResultProtoConverter
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
|
||||
trait RandomStateProtoSequencer {
|
||||
def lastState: GameState
|
||||
def lastStateProto: GameStateProto
|
||||
|
||||
def results: RandomState[Vector[ActionWithResultingState]]
|
||||
def actionResults: RandomState[Vector[ActionResult]]
|
||||
def actionResults: RandomState[Vector[ActionResultProto]]
|
||||
|
||||
def withRandomActionResult(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResult]
|
||||
) => RandomState[ActionResultProto]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withRandomActionResults(
|
||||
actionResultsGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResult]]
|
||||
) => RandomState[Vector[ActionResultProto]]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withRandomAction(
|
||||
actionGen: (GameState, FunctionalRandom) => RandomState[Action]
|
||||
actionGen: (GameStateProto, FunctionalRandom) => RandomState[Action]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
// ActionResultSequencer passthroughs
|
||||
def withAction(action: GameState => Action): RandomStateProtoSequencer
|
||||
def withAction(action: GameStateProto => Action): RandomStateProtoSequencer
|
||||
|
||||
def withProtolessSimpleAction(
|
||||
action: GameState => ProtolessSimpleAction
|
||||
action: GameStateProto => ProtolessSimpleAction
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withProtolessSequentialResultsAction(
|
||||
action: GameState => ProtolessSequentialResultsAction
|
||||
action: GameStateProto => ProtolessSequentialResultsAction
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withRandomActionResultT(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResultT]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withRandomActionResultTs(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResultT]]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withActionResult(
|
||||
actionResultGen: GameState => ActionResult
|
||||
actionResultGen: GameStateProto => ActionResultProto
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withActionResultT(
|
||||
actionResultGen: GameState => ActionResultT
|
||||
actionResultGen: GameStateProto => ActionResultT
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withActionResultTs(
|
||||
actionResultGen: GameState => Iterable[ActionResultT]
|
||||
actionResultGen: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withActionResults(
|
||||
actionResultsGen: GameState => Iterable[ActionResult]
|
||||
actionResultsGen: GameStateProto => Iterable[ActionResultProto]
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withActionWithResultingState(
|
||||
awrsGen: GameState => ActionWithResultingState
|
||||
awrsGen: GameStateProto => ActionWithResultingState
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def withContinuance(
|
||||
@@ -85,7 +87,7 @@ trait RandomStateProtoSequencer {
|
||||
): RandomStateProtoSequencer
|
||||
|
||||
def foldIn[T](ts: Iterable[T])(
|
||||
f: (T, GameState, FunctionalRandom) => RandomState[ActionResult]
|
||||
f: (T, GameStateProto, FunctionalRandom) => RandomState[ActionResultProto]
|
||||
): RandomStateProtoSequencer
|
||||
}
|
||||
|
||||
@@ -94,9 +96,20 @@ object RandomStateProtoSequencer {
|
||||
initialState: GameState,
|
||||
actionResultProtoApplier: ActionResultProtoApplier,
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomStateProtoSequencer =
|
||||
apply(
|
||||
initialStateProto = GameStateConverter.toProto(initialState),
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
def apply(
|
||||
initialStateProto: GameStateProto,
|
||||
actionResultProtoApplier: ActionResultProtoApplier,
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomStateProtoSequencer =
|
||||
RandomStateProtoSequencerImpl(
|
||||
initialState = initialState,
|
||||
initialStateProto = initialStateProto,
|
||||
actionResultProtoApplier = actionResultProtoApplier,
|
||||
results = RandomState(
|
||||
Vector(),
|
||||
@@ -106,38 +119,39 @@ object RandomStateProtoSequencer {
|
||||
}
|
||||
|
||||
private case class RandomStateProtoSequencerImpl(
|
||||
initialState: GameState,
|
||||
initialStateProto: GameStateProto,
|
||||
actionResultProtoApplier: ActionResultProtoApplier,
|
||||
results: RandomState[Vector[ActionWithResultingState]]
|
||||
) extends RandomStateProtoSequencer {
|
||||
override def actionResults: RandomState[Vector[ActionResult]] =
|
||||
override def actionResults: RandomState[Vector[ActionResultProto]] =
|
||||
results.map(_.map(_.actionResult))
|
||||
|
||||
override val lastState: GameState =
|
||||
results.newValue.lastOption.map(_.gameState).getOrElse(initialState)
|
||||
override val lastStateProto: GameStateProto =
|
||||
results.newValue.lastOption.map(_.gameState).getOrElse(initialStateProto)
|
||||
|
||||
override def withAction(
|
||||
action: GameState => Action
|
||||
action: GameStateProto => Action
|
||||
): RandomStateProtoSequencer =
|
||||
copy(
|
||||
results =
|
||||
results.map(_ ++ action(lastState).execute(actionResultProtoApplier))
|
||||
results = results.map(
|
||||
_ ++ action(lastStateProto).execute(actionResultProtoApplier)
|
||||
)
|
||||
)
|
||||
|
||||
override def withProtolessSimpleAction(
|
||||
action: GameState => ProtolessSimpleAction
|
||||
action: GameStateProto => ProtolessSimpleAction
|
||||
): RandomStateProtoSequencer =
|
||||
withActionResultT(gs => action(gs).immediateExecute)
|
||||
|
||||
override def withProtolessSequentialResultsAction(
|
||||
action: GameState => ProtolessSequentialResultsAction
|
||||
action: GameStateProto => ProtolessSequentialResultsAction
|
||||
): RandomStateProtoSequencer =
|
||||
withActionResults(gs =>
|
||||
action(gs).results.map(ActionResultProtoConverter.toProto)
|
||||
)
|
||||
|
||||
override def withActionResultT(
|
||||
action: GameState => ActionResultT
|
||||
action: GameStateProto => ActionResultT
|
||||
): RandomStateProtoSequencer =
|
||||
withActionResult(gs =>
|
||||
ActionResultProtoConverter.toProto(
|
||||
@@ -146,41 +160,41 @@ private case class RandomStateProtoSequencerImpl(
|
||||
)
|
||||
|
||||
override def withActionResultTs(
|
||||
action: GameState => Iterable[ActionResultT]
|
||||
action: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateProtoSequencer =
|
||||
withActionResults(gs => action(gs).map(ActionResultProtoConverter.toProto))
|
||||
|
||||
override def withActionResult(
|
||||
actionResultGen: GameState => ActionResult
|
||||
actionResultGen: GameStateProto => ActionResultProto
|
||||
): RandomStateProtoSequencer =
|
||||
copy(
|
||||
results = results.map(
|
||||
_ :+ actionResultProtoApplier
|
||||
.applyActionResult(lastState, actionResultGen(lastState))
|
||||
.applyActionResult(lastStateProto, actionResultGen(lastStateProto))
|
||||
)
|
||||
)
|
||||
|
||||
override def withActionResults(
|
||||
actionResultsGen: GameState => Iterable[ActionResult]
|
||||
actionResultsGen: GameStateProto => Iterable[ActionResultProto]
|
||||
): RandomStateProtoSequencer =
|
||||
copy(
|
||||
results = results.map(
|
||||
_ ++ actionResultProtoApplier
|
||||
.applyActionResults(lastState, actionResultsGen(lastState))
|
||||
.applyActionResults(lastStateProto, actionResultsGen(lastStateProto))
|
||||
)
|
||||
)
|
||||
|
||||
override def foldIn[T](ts: Iterable[T])(
|
||||
f: (T, GameState, FunctionalRandom) => RandomState[ActionResult]
|
||||
f: (T, GameStateProto, FunctionalRandom) => RandomState[ActionResultProto]
|
||||
): RandomStateProtoSequencer =
|
||||
ts.foldLeft(this) { case (sequencer, t) =>
|
||||
sequencer.withRandomActionResult { case (gs, fr) => f(t, gs, fr) }
|
||||
}
|
||||
|
||||
override def withActionWithResultingState(
|
||||
awrsGen: GameState => ActionWithResultingState
|
||||
awrsGen: GameStateProto => ActionWithResultingState
|
||||
): RandomStateProtoSequencer = copy(
|
||||
results = results.map(_ :+ awrsGen(lastState))
|
||||
results = results.map(_ :+ awrsGen(lastStateProto))
|
||||
)
|
||||
|
||||
override def withContinuance(
|
||||
@@ -189,33 +203,33 @@ private case class RandomStateProtoSequencerImpl(
|
||||
|
||||
override def withRandomActionResult(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResult]
|
||||
) => RandomState[ActionResultProto]
|
||||
): RandomStateProtoSequencerImpl =
|
||||
results match {
|
||||
case RandomState(ars, fr) =>
|
||||
copy(
|
||||
results = actionResultGen(lastState, fr).map { ar =>
|
||||
results = actionResultGen(lastStateProto, fr).map { ar =>
|
||||
ars :+ actionResultProtoApplier
|
||||
.applyActionResult(lastState, ar)
|
||||
.applyActionResult(lastStateProto, ar)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override def withRandomActionResultT(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResultT]
|
||||
): RandomStateProtoSequencerImpl =
|
||||
results match {
|
||||
case RandomState(ars, fr) =>
|
||||
copy(
|
||||
results = actionResultGen(lastState, fr).map { ar =>
|
||||
results = actionResultGen(lastStateProto, fr).map { ar =>
|
||||
ars :+ actionResultProtoApplier
|
||||
.applyActionResult(
|
||||
lastState,
|
||||
lastStateProto,
|
||||
ActionResultProtoConverter.toProto(ar)
|
||||
)
|
||||
}
|
||||
@@ -224,15 +238,15 @@ private case class RandomStateProtoSequencerImpl(
|
||||
|
||||
override def withRandomActionResults(
|
||||
actionResultsGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResult]]
|
||||
) => RandomState[Vector[ActionResultProto]]
|
||||
): RandomStateProtoSequencer =
|
||||
results match {
|
||||
case RandomState(ars, fr) =>
|
||||
copy(results = actionResultsGen(lastState, fr).map { newArs =>
|
||||
copy(results = actionResultsGen(lastStateProto, fr).map { newArs =>
|
||||
ars ++ actionResultProtoApplier.applyActionResults(
|
||||
lastState,
|
||||
lastStateProto,
|
||||
newArs
|
||||
)
|
||||
})
|
||||
@@ -240,17 +254,17 @@ private case class RandomStateProtoSequencerImpl(
|
||||
|
||||
override def withRandomActionResultTs(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResultT]]
|
||||
): RandomStateProtoSequencerImpl =
|
||||
results match {
|
||||
case RandomState(ars, fr) =>
|
||||
copy(
|
||||
results = actionResultGen(lastState, fr).map { newArs =>
|
||||
results = actionResultGen(lastStateProto, fr).map { newArs =>
|
||||
ars ++ actionResultProtoApplier
|
||||
.applyActionResults(
|
||||
lastState,
|
||||
lastStateProto,
|
||||
newArs.map(ActionResultProtoConverter.toProto)
|
||||
)
|
||||
}
|
||||
@@ -258,11 +272,11 @@ private case class RandomStateProtoSequencerImpl(
|
||||
}
|
||||
|
||||
override def withRandomAction(
|
||||
actionGen: (GameState, FunctionalRandom) => RandomState[Action]
|
||||
actionGen: (GameStateProto, FunctionalRandom) => RandomState[Action]
|
||||
): RandomStateProtoSequencer =
|
||||
results match {
|
||||
case RandomState(ars, fr) =>
|
||||
copy(results = actionGen(lastState, fr).map { action =>
|
||||
copy(results = actionGen(lastStateProto, fr).map { action =>
|
||||
ars ++ action.execute(actionResultProtoApplier)
|
||||
})
|
||||
}
|
||||
|
||||
+45
-32
@@ -1,16 +1,18 @@
|
||||
package net.eagle0.eagle.library.actions.impl.common
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.internal.game_state.GameState
|
||||
import net.eagle0.eagle.internal.game_state.GameState as GameStateProto
|
||||
import net.eagle0.eagle.library.actions.applier.{
|
||||
ActionResultTApplier,
|
||||
ActionResultTWithResultingState
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.proto_converters.ActionResultProtoConverter
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
|
||||
trait RandomStateTSequencer {
|
||||
def lastState: GameState
|
||||
def lastStateProto: GameStateProto
|
||||
|
||||
def actionResults: RandomState[Vector[ActionResultT]]
|
||||
|
||||
@@ -28,7 +30,7 @@ trait RandomStateTSequencer {
|
||||
|
||||
def withRandomActionResult(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResultT]
|
||||
): RandomStateTSequencer
|
||||
@@ -40,33 +42,33 @@ trait RandomStateTSequencer {
|
||||
|
||||
def withRandomActionResults(
|
||||
actionResultsGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResultT]]
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withProtolessSimpleAction(
|
||||
action: GameState => ProtolessSimpleAction
|
||||
action: GameStateProto => ProtolessSimpleAction
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withProtolessSequentialResultsAction(
|
||||
action: GameState => ProtolessSequentialResultsAction
|
||||
action: GameStateProto => ProtolessSequentialResultsAction
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withActionResult(
|
||||
actionResultGen: GameState => ActionResultT
|
||||
actionResultGen: GameStateProto => ActionResultT
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withActionResultT(
|
||||
actionResultGen: GameState => ActionResultT
|
||||
actionResultGen: GameStateProto => ActionResultT
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withActionResultTs(
|
||||
actionResultGen: GameState => Iterable[ActionResultT]
|
||||
actionResultGen: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withActionResults(
|
||||
actionResultsGen: GameState => Iterable[ActionResultT]
|
||||
actionResultsGen: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateTSequencer
|
||||
|
||||
def withContinuance(
|
||||
@@ -78,7 +80,7 @@ trait RandomStateTSequencer {
|
||||
): RandomStateTSequencer
|
||||
|
||||
def foldIn[T](ts: Iterable[T])(
|
||||
f: (T, GameState, FunctionalRandom) => RandomState[ActionResultT]
|
||||
f: (T, GameStateProto, FunctionalRandom) => RandomState[ActionResultT]
|
||||
): RandomStateTSequencer
|
||||
}
|
||||
|
||||
@@ -87,9 +89,20 @@ object RandomStateTSequencer {
|
||||
initialState: GameState,
|
||||
actionResultApplier: ActionResultTApplier,
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomStateTSequencer =
|
||||
apply(
|
||||
initialStateProto = GameStateConverter.toProto(initialState),
|
||||
actionResultApplier = actionResultApplier,
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
def apply(
|
||||
initialStateProto: GameStateProto,
|
||||
actionResultApplier: ActionResultTApplier,
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomStateTSequencer =
|
||||
RandomStateTSequencerImpl(
|
||||
initialState = initialState,
|
||||
initialStateProto = initialStateProto,
|
||||
actionResultApplier = actionResultApplier,
|
||||
actionResultTsWithResultingStates = RandomState(
|
||||
Vector(),
|
||||
@@ -99,7 +112,7 @@ object RandomStateTSequencer {
|
||||
}
|
||||
|
||||
private case class RandomStateTSequencerImpl(
|
||||
initialState: GameState,
|
||||
initialStateProto: GameStateProto,
|
||||
actionResultApplier: ActionResultTApplier,
|
||||
actionResultTsWithResultingStates: RandomState[
|
||||
Vector[ActionResultTWithResultingState]
|
||||
@@ -108,52 +121,52 @@ private case class RandomStateTSequencerImpl(
|
||||
override def actionResults: RandomState[Vector[ActionResultT]] =
|
||||
actionResultTsWithResultingStates.map(_.map(_.actionResult))
|
||||
|
||||
override def lastState: GameState =
|
||||
override def lastStateProto: GameStateProto =
|
||||
actionResultTsWithResultingStates.newValue.lastOption
|
||||
.map(_.resultingState)
|
||||
.getOrElse(initialState)
|
||||
.getOrElse(initialStateProto)
|
||||
|
||||
override def withProtolessSimpleAction(
|
||||
action: GameState => ProtolessSimpleAction
|
||||
action: GameStateProto => ProtolessSimpleAction
|
||||
): RandomStateTSequencer =
|
||||
withActionResultT(gs => action(gs).immediateExecute)
|
||||
|
||||
override def withProtolessSequentialResultsAction(
|
||||
action: GameState => ProtolessSequentialResultsAction
|
||||
action: GameStateProto => ProtolessSequentialResultsAction
|
||||
): RandomStateTSequencer =
|
||||
withActionResults(gs => action(gs).results)
|
||||
|
||||
override def withActionResultT(
|
||||
action: GameState => ActionResultT
|
||||
action: GameStateProto => ActionResultT
|
||||
): RandomStateTSequencer =
|
||||
withActionResult(gs => action(gs))
|
||||
|
||||
override def withActionResultTs(
|
||||
action: GameState => Iterable[ActionResultT]
|
||||
action: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateTSequencer =
|
||||
withActionResults(gs => action(gs))
|
||||
|
||||
override def withActionResult(
|
||||
actionResultGen: GameState => ActionResultT
|
||||
): RandomStateTSequencer = actionResultGen(lastState) match {
|
||||
actionResultGen: GameStateProto => ActionResultT
|
||||
): RandomStateTSequencer = actionResultGen(lastStateProto) match {
|
||||
case art =>
|
||||
copy(
|
||||
actionResultTsWithResultingStates =
|
||||
actionResultTsWithResultingStates.map(
|
||||
_ :+ ActionResultTWithResultingState(art, lastState)
|
||||
_ :+ ActionResultTWithResultingState(art, lastStateProto)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override def withActionResults(
|
||||
actionResultsGen: GameState => Iterable[ActionResultT]
|
||||
): RandomStateTSequencer = actionResultsGen(lastState).foldLeft(this) {
|
||||
actionResultsGen: GameStateProto => Iterable[ActionResultT]
|
||||
): RandomStateTSequencer = actionResultsGen(lastStateProto).foldLeft(this) {
|
||||
case (sequencer, ar) =>
|
||||
sequencer.copy(actionResultTsWithResultingStates =
|
||||
sequencer.actionResultTsWithResultingStates.map(
|
||||
_ :+ actionResultApplier
|
||||
.applyActionResult(
|
||||
sequencer.lastState,
|
||||
sequencer.lastStateProto,
|
||||
ar
|
||||
)
|
||||
)
|
||||
@@ -161,7 +174,7 @@ private case class RandomStateTSequencerImpl(
|
||||
}
|
||||
|
||||
override def foldIn[T](ts: Iterable[T])(
|
||||
f: (T, GameState, FunctionalRandom) => RandomState[ActionResultT]
|
||||
f: (T, GameStateProto, FunctionalRandom) => RandomState[ActionResultT]
|
||||
): RandomStateTSequencer =
|
||||
ts.foldLeft(this) { case (sequencer, t) =>
|
||||
sequencer.withRandomActionResult { case (gs, fr) => f(t, gs, fr) }
|
||||
@@ -173,19 +186,19 @@ private case class RandomStateTSequencerImpl(
|
||||
|
||||
override def withRandomActionResult(
|
||||
actionResultGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[ActionResultT]
|
||||
): RandomStateTSequencerImpl =
|
||||
actionResultTsWithResultingStates match {
|
||||
case RandomState(awrs, fr) =>
|
||||
actionResultGen(lastState, fr) match {
|
||||
actionResultGen(lastStateProto, fr) match {
|
||||
case RandomState(art, newFr) =>
|
||||
copy(actionResultTsWithResultingStates =
|
||||
RandomState(
|
||||
awrs :+ actionResultApplier
|
||||
.applyActionResult(
|
||||
lastState,
|
||||
lastStateProto,
|
||||
art
|
||||
),
|
||||
newFr
|
||||
@@ -196,13 +209,13 @@ private case class RandomStateTSequencerImpl(
|
||||
|
||||
override def withRandomActionResults(
|
||||
actionResultsGen: (
|
||||
GameState,
|
||||
GameStateProto,
|
||||
FunctionalRandom
|
||||
) => RandomState[Vector[ActionResultT]]
|
||||
): RandomStateTSequencer =
|
||||
actionResultTsWithResultingStates match {
|
||||
case RandomState(awrs, fr) =>
|
||||
actionResultsGen(lastState, fr) match {
|
||||
actionResultsGen(lastStateProto, fr) match {
|
||||
case RandomState(Vector(), newFr) =>
|
||||
copy(
|
||||
actionResultTsWithResultingStates = RandomState(awrs, newFr)
|
||||
@@ -212,7 +225,7 @@ private case class RandomStateTSequencerImpl(
|
||||
actionResultTsWithResultingStates = RandomState(
|
||||
awrs ++ actionResultApplier
|
||||
.applyActionResults(
|
||||
lastState,
|
||||
lastStateProto,
|
||||
arts
|
||||
),
|
||||
newFr
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.eagle0.eagle.library.actions.impl.common
|
||||
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult
|
||||
|
||||
trait SimpleAction {
|
||||
def immediateExecute: ActionResult
|
||||
}
|
||||
+2
-2
@@ -10,7 +10,7 @@ object FactionInfoUtilities {
|
||||
gameState: GameState
|
||||
): Faction =
|
||||
gameState.factions.getOrElse(
|
||||
factionId.value,
|
||||
gameState.destroyedFactions(factionId.value)
|
||||
factionId,
|
||||
gameState.destroyedFactions(factionId)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
package net.eagle0.eagle.library.actions.llm_prompt_generators
|
||||
|
||||
import net.eagle0.eagle.ClientTextId
|
||||
import net.eagle0.eagle.client_text.{
|
||||
ClientTextStore,
|
||||
TextGenerationDependencyInProgress,
|
||||
@@ -51,12 +50,12 @@ object GeneratorUtilities {
|
||||
|
||||
val academyName = "The Academy of Arcane and Occult Arts"
|
||||
|
||||
private def factionHeadNameIds(gameState: GameState): Vector[ClientTextId] =
|
||||
private def factionHeadNameIds(gameState: GameState): Vector[String] =
|
||||
gameState.factions.values.toVector
|
||||
.sortBy(_.id)
|
||||
.map(_.factionHeadId)
|
||||
.map(hid => gameState.heroes.getOrElse(hid, gameState.killedHeroes(hid)))
|
||||
.map(hero => ClientTextId(hero.nameTextId))
|
||||
.map(_.nameTextId)
|
||||
|
||||
private def factionHeadsNamesResult(
|
||||
gameState: GameState,
|
||||
|
||||
+1
-4
@@ -6,8 +6,5 @@ import net.eagle0.eagle.internal.hero.Hero
|
||||
|
||||
object HeroInfoUtilities {
|
||||
def getHero(heroId: HeroId, gameState: GameState): Hero =
|
||||
gameState.heroes.getOrElse(
|
||||
heroId.value,
|
||||
gameState.killedHeroes(heroId.value)
|
||||
)
|
||||
gameState.heroes.getOrElse(heroId, gameState.killedHeroes(heroId))
|
||||
}
|
||||
|
||||
+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(
|
||||
|
||||
+20
-20
@@ -23,11 +23,11 @@ object DiplomacyResolutionLlmRequestGenerator {
|
||||
GeneratedTextRequest(
|
||||
id =
|
||||
s"$currentRoundId truce offer $originatingFactionId $targetFactionId resolution $resolution",
|
||||
eagleGameId = gameId.value,
|
||||
eagleGameId = gameId,
|
||||
details = TruceResolutionMessage(
|
||||
offeringFactionId = originatingFactionId.value,
|
||||
targetFactionId = targetFactionId.value,
|
||||
messengerHeroId = messengerHeroId.value,
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = targetFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolutionStatus = resolution
|
||||
)
|
||||
)
|
||||
@@ -43,11 +43,11 @@ object DiplomacyResolutionLlmRequestGenerator {
|
||||
GeneratedTextRequest(
|
||||
id =
|
||||
s"$currentRoundId alliance offer $originatingFactionId $targetFactionId resolution $resolution",
|
||||
eagleGameId = gameId.value,
|
||||
eagleGameId = gameId,
|
||||
details = AllianceOfferResolutionMessage(
|
||||
offeringFactionId = originatingFactionId.value,
|
||||
targetFactionId = targetFactionId.value,
|
||||
messengerHeroId = messengerHeroId.value,
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = targetFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolutionStatus = resolution
|
||||
)
|
||||
)
|
||||
@@ -63,11 +63,11 @@ object DiplomacyResolutionLlmRequestGenerator {
|
||||
GeneratedTextRequest(
|
||||
id =
|
||||
s"$currentRoundId break alliance $originatingFactionId $targetFactionId resolution $resolution",
|
||||
eagleGameId = gameId.value,
|
||||
eagleGameId = gameId,
|
||||
details = BreakAllianceResolutionMessage(
|
||||
breakingFactionId = originatingFactionId.value,
|
||||
targetFactionId = targetFactionId.value,
|
||||
messengerHeroId = messengerHeroId.value,
|
||||
breakingFactionId = originatingFactionId,
|
||||
targetFactionId = targetFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolutionStatus = resolution
|
||||
)
|
||||
)
|
||||
@@ -83,11 +83,11 @@ object DiplomacyResolutionLlmRequestGenerator {
|
||||
GeneratedTextRequest(
|
||||
id =
|
||||
s"$currentRoundId invitation resolution $originatingFactionId $invitedFactionId resolution $resolution",
|
||||
eagleGameId = gameId.value,
|
||||
eagleGameId = gameId,
|
||||
details = InvitationResolutionMessage(
|
||||
offeringFactionId = originatingFactionId.value,
|
||||
targetFactionId = invitedFactionId.value,
|
||||
messengerHeroId = messengerHeroId.value,
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = invitedFactionId,
|
||||
messengerHeroId = messengerHeroId,
|
||||
resolutionStatus = resolution
|
||||
)
|
||||
)
|
||||
@@ -103,11 +103,11 @@ object DiplomacyResolutionLlmRequestGenerator {
|
||||
GeneratedTextRequest(
|
||||
id =
|
||||
s"$currentRoundId ransom resolution $originatingFactionId $targetFactionId resolution $resolution",
|
||||
eagleGameId = gameId.value,
|
||||
eagleGameId = gameId,
|
||||
details = RansomResolutionMessage(
|
||||
offeringFactionId = originatingFactionId.value,
|
||||
targetFactionId = targetFactionId.value,
|
||||
ransomedHeroId = ransomedHeroId.value,
|
||||
offeringFactionId = originatingFactionId,
|
||||
targetFactionId = targetFactionId,
|
||||
ransomedHeroId = ransomedHeroId,
|
||||
resolutionStatus = resolution
|
||||
)
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user