* Enable battalion diversity quest generation (PR 3/3)
Adds quest creation logic for BattalionDiversityQuest to QuestCreationUtils.
Quest availability:
- Only if province currently has 1-2 battalion types
- This encourages players to diversify their army composition
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Clarify PR dependency structure in quest docs
PR 2 (client) and PR 3 (generation) both depend on PR 1 (types),
but are independent of each other. They can be developed in parallel
and merged in either order after PR 1.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The existing cleanup only removed dangling images. Now also removes
images older than 24h to prevent disk space exhaustion while keeping
recent images available for rollback.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The S3 API requires credentials with bucket access, but the file is
publicly accessible at assets.eagle0.net. Use HTTP GET for reading
(no credentials needed) and keep S3 API only for writing.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add long-press support for right-click on touch devices
On iPad and other touch devices, right-click is not available. This adds
long-press detection to GeneralClickDetector (used by the strategic map)
to trigger right-click behavior after holding for 0.5 seconds.
- Tracks pointer down time and position
- Triggers right-click after 0.5s if finger hasn't moved >10 pixels
- Suppresses normal left-click if long-press was triggered
- Cancels long-press detection if finger moves too far
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Only enable long-press for touch input, not mouse
Mouse users can right-click, so long-press should only trigger for
touch devices. Check pointerId >= 0 to distinguish touch (0+) from
mouse (-1, -2, -3 for left, right, middle buttons).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Restore support for ACCESS_KEY_ID/SECRET_KEY env vars (used by CI)
while also supporting DO_SPACES_* env vars (used by docker-compose).
Priority order:
1. ~/.s3cfg file
2. DO_SPACES_* env vars
3. ACCESS_KEY_ID/SECRET_KEY env vars
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Adds BattalionDiversityQuest - a quest where unaffiliated heroes want
to see three different types of battalion at near-full strength (80%
capacity) in the current province.
This PR adds:
- Proto message definition
- Scala case object
- Proto converter
- Fulfillment check (near UpgradeBattalionQuest)
- LLM prompt generators
Does NOT generate the quest yet - that will be in PR 3 after client
handling is added in PR 2.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Replace duel_challenged sound with licensed asset
Replace duel_challenged.mp3 (unknown license) with Weapon Draw Metal 1.wav
from the purchased Medieval Combat Sounds Unity Asset Store pack.
The dramatic sword unsheathing sound fits well for a duel challenge.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Wire up Weapon Draw Metal 5 as duel_challenged sound
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add S3 credentials to admin server container
The admin server needs DO_SPACES_* environment variables to access
S3/Spaces for What's New data storage. Without these, the What's New
Management page fails with "static credentials are empty".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix S3 credentials: use DO_SPACES_* env vars
The aws package was looking for ACCESS_KEY_ID/SECRET_KEY env vars,
but docker-compose passes DO_SPACES_ACCESS_KEY/DO_SPACES_SECRET_KEY.
Updated ReadAwsConfig() to use the correct env var names and also
respect DO_SPACES_ENDPOINT.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add stale PR refs cleanup to iOS CI workflows
Self-hosted runners persist .git between runs. When a PR is updated,
old local refs may point to commits that were never fetched, causing
"Could not scan for Git LFS files" errors.
Applied to:
- ios_addressables_build.yml
- ios_testflight.yml
(Same fix already present in mac_build.yml and unity_build.yml)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fetch LFS after checkout to avoid stale ref issues
Move LFS fetching out of actions/checkout and into a separate step.
This ensures our stale PR refs cleanup runs before any LFS operations,
avoiding "Could not scan for Git LFS files" errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix LFS fetch order in mac_build and unity_build workflows
Apply the same fix as ios_* workflows: set lfs: false in checkout
and fetch LFS files manually afterward to avoid stale ref issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The admin server needs DO_SPACES_* environment variables to access
S3/Spaces for What's New data storage. Without these, the What's New
Management page fails with "static credentials are empty".
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add quest creation logic for DevelopProvincesQuest and MobilizeProvincesQuest
to QuestCreationUtils.
Quest parameters:
- Availability: Only if faction has >= 3 provinces
- Target province count: Random 3-5, capped at current province count
- Target months: Random 3-6
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add ADDING_NEW_QUESTS.md documentation explaining the three-PR
strategy and listing all files that need modification for new quests
- Add DevelopProvincesQuest and MobilizeProvincesQuest cases to
DisplayNames.QuestTypeString()
- Add quest description strings to UnaffiliatedHeroRowController
showing progress (e.g., "3/5 months")
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add click-to-dismiss on modal blockers as safety net
If a modal panel somehow becomes invisible while its blocker remains
active, users can now tap the dimmed area to dismiss it. This prevents
getting stuck with an unresponsive UI.
Applied to all three controllers that share the modal blocker:
- WhatsNewPanelController
- BugReportPanelController
- SettingsPanelController
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Give each modal panel its own dedicated modal blocker
Previously Settings, Bug Report, and What's New panels shared a single
modal blocker, which could cause state conflicts if one panel's blocker
state affected another.
Now each panel has its own dedicated blocker:
- Settings Panel Modal Blocker
- Bug Report Modal Blocker
- What's New Modal Blocker
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The fetchWhatsNewData function was silently swallowing ALL errors and
returning empty data, not just "file not found" errors. This masked
real issues like permission errors.
Now:
- Only returns empty data for actual "NoSuchKey" (file not found) errors
- Logs and returns other errors so they appear on the page
- Logs successful fetches with entry count for debugging
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The htmx form was receiving both an HX-Redirect header and HTML body content.
This caused htmx to swap the content before processing the redirect, making
the button appear to do nothing.
Fix: Return only the HX-Redirect header without body content on success.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add Province Order Quests (Develop/Mobilize)
Add two new quest types where unaffiliated heroes want the faction to
maintain a certain number of provinces in specific order states
(Develop or Mobilize) for a cumulative number of months.
Quest mechanics:
- Availability: Only if faction has >= 3 provinces
- Target province count: Random 3-5, capped at current province count
- Target months: Random 3-6 (componentCount)
- Progress: Each round, if faction has >= X provinces with the required
order type, componentsFulfilled increments by 1
- Completion: When componentsFulfilled >= componentCount
- Failure: If faction falls below X total provinces
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove ProvinceOrderQuestProgress action result type
Fold the province order quest progress changes into the EndVassalCommandsPhase
action result instead of creating a separate action result type.
Also improve LLM prompt descriptions to explain what Develop and Mobilize
orders mean (Develop = improve agriculture/economy/infrastructure,
Mobilize = organize/train/arm troops for war).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove quest generation for province order quests
Keep the proto definitions, Scala types, converters, and handling code
(fulfillment, failure, progress tracking, LLM prompts) but remove the
actual quest creation logic from QuestCreationUtils.
This allows the client to be updated to understand these quest types
before the server starts generating them.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Change costLabel to only show the numeric cost value
- Add separate costWarningLabel for "(only X available)" warning
- Warning label only shown when insufficient gold available
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Update hero and battalion backstory prompt generators to explicitly
request flowing narrative prose rather than dated lists. The LLM
should weave events into a cohesive story that reads as a biography
or unit history, not a timeline.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add underProvinceNameText/underProvinceOwnerText to MapController
- Update SetUpCenterText to populate both regular and under text fields
- Add clickedProvincePanel/underClickedProvincePanel refs to EagleGameController
- Switch panel visibility based on screen width in ArrangeLayout
- Organize EagleGameController Inspector fields with Header attributes
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Notify connected clients when a new version is available after CI deploy.
Flow:
1. CI deploys new build and waits 60s for CDN cache
2. CI calls admin server HTTP endpoint with shared secret
3. Admin server calls Eagle via gRPC
4. Eagle broadcasts to all connected lobby users
Components:
- Proto: ClientUpdateAvailable message, NotifyClientUpdate RPC
- Eagle: notifyClientUpdate() broadcasts to lobby users
- Admin server: /notify-update HTTP endpoint with secret auth
- CI: Notify steps in mac_build.yml and unity_build.yml
- Docker: NOTIFY_SECRET env var passed to admin container
Client-side handling will be added in a follow-up PR.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add battalion backstory to LLM prompt generators
Add descriptionWithBackstory methods to BattalionDescriptions that include
the battalion's backstory text alongside the basic description (name, type,
size). This gives LLM prompts richer context about the units involved.
Updated prompt generators:
- SuppressBeastsPromptGenerator (Failed and Succeeded): Include battalion
backstory when describing beast hunting attempts
- HeroBackstoryUpdatePromptGenerator: Include battalion backstory in
FoughtInBattle, SuppressedBeasts, and SuppressedRiot events
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix battalion backstory usage in prompts
Use basic description inline in sentences and include backstory as
separate context block, matching how hero backstories are handled.
- In SuppressBeastsPromptGenerator: use basic description in
"$heroName took [battalion]" and add fullDescription as context
- In HeroBackstoryUpdatePromptGenerator: use basic description only
in event text (hero's story doesn't need battalion backstory detail)
- Renamed methods in BattalionDescriptions for clarity:
- backstoryText: just the backstory
- fullDescription: "Name is a battalion... $backstory"
- optionalFullDescription: for optional battalions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix duplicate code blocks from rebase
The rebase introduced duplicate code blocks in FoughtInBattle,
SuppressedBeasts, and SuppressedRiot cases that caused syntax errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove unused BattalionView methods from BattalionDescriptions
Since EventForHeroBackstory now uses BattalionId instead of BattalionView,
we no longer need the BattalionView overloads in BattalionDescriptions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The FoughtInBattle, SuppressedBeasts, and SuppressedRiot events now store
Option[BattalionId] instead of Option[BattalionView]. This allows looking
up the battalion from GameState at prompt generation time, providing access
to the battalion's current backstory text rather than a snapshot.
Changes:
- Proto: Changed battalion field from BattalionView to optional int32
- EventForHeroBackstoryT.scala: Changed battalion type to Option[BattalionId]
- EventForHeroBackstoryConverter: Updated toProto/fromProto conversion
- ResolveBattleAction, SuppressBeastsCommand, HandleRiotCrackDownCommand:
Now pass battalion.map(_.id) when creating events
- HeroBackstoryUpdatePromptGenerator: Looks up battalion from GameState
using gameState.battalions.getOrElse(id, gameState.destroyedBattalions(id))
- Updated tests and removed unused BattalionViewFilter deps
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Update Notification Panel layout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Additional Notification Panel layout tweaks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update button text styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Fix empty.tail crash in BattalionBackstoryUpdatePromptGenerator
When a battalion had no previous backstory versions, calling .last on
an empty vector caused a NoSuchElementException. Use lastOption with
a match to safely handle the empty case by returning an empty string.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Generate initial backstory for newly raised battalions
When a player raises a new battalion via OrganizeTroopsCommand, now
generates a BattalionInitialBackstoryRequest so the battalion gets
its first backstory. Previously only battalions created at game start
(in NewGameCreation) received initial backstories.
This ensures all battalions have backstories from their creation,
complementing the empty.tail fix which handles the transitional case.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Update Suppress Beasts command panel layout in Unity
- Only show "(only X available)" when insufficient gold, with newline
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add references for battalion name (GeneratedTextUpdater) and type icon
(RawImage) to the battalion popup panel header. Populate them when
hovering over a battalion row.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When creating backstory events for changed battalions, the code assumed
every battalion in changedBatt would also be in changedBattalions. This
is not true when a battalion is modified indirectly - for example, when
troops are transferred OUT of it to another battalion.
The fix uses find() and handles the None case with default values (0 for
hired, dismissed, and transferred in counts).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add git corruption detection to Unity CI workflows
Self-hosted runners can accumulate corrupted git state over time.
Add a pre-checkout step that runs git fsck and nukes the repo if
corruption is detected, allowing a fresh clone.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix CI git corruption: check target ref objects instead of full fsck
Self-hosted runners can have stale refs (e.g., refs/remotes/pull/*/merge)
pointing to commits whose objects weren't fetched when the PR was updated.
Running git fsck is too broad and slow. Instead, check if the specific
target ref's objects are complete before checkout.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix CI: prune stale PR refs instead of checking all objects
Self-hosted runners persist .git between runs. When a PR is updated,
actions/checkout doesn't prune old local refs like refs/remotes/pull/*/merge.
These stale refs may point to commits whose objects were never fetched,
causing "missing object" errors during checkout.
Fix by explicitly removing PR refs before checkout. This is faster and
more targeted than validating object completeness.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add four new battalion backstory event types:
- SuppressedRiot: Records when a battalion helps suppress a riot, including
the riot size, casualties, and whether the suppression succeeded
- Trained: Records training sessions by a hero, with training improvement
- Armed: Records equipment upgrades with armament improvement and cost
- SurvivedStarvation: Records when battalions suffer casualties due to
food shortage, with loss proportion and whether on march or in garrison
The LLM prompt generator includes guidance to not over-emphasize routine
training and arming events in favor of more dramatic events like battles
and riots.
Also includes per-battalion cost tracking in ArmTroopsCommand to properly
attribute gold spending for each battalion's backstory event.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add What's New feature to Unity client
- Add WhatsNewManager singleton for fetching and tracking changelog
- Add WhatsNewPanelController for modal display with category styling
- Integrate CheckAndShow() call in ConnectionHandler after OAuth login
The manager fetches entries from assets.eagle0.net/whats-new.json,
tracks last seen date in PlayerPrefs, and shows new entries on login.
UI prefab setup required in Unity Editor.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Wire up What's New UI in Unity
- Move WhatsNewEntryUI to separate file for Unity component discovery
- Add What's New Entry prefab
- Wire up WhatsNewManager and WhatsNewPanelController in Gameplay scene
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add battalion backstory infrastructure
Adds support for battalions to have backstory events similar to heroes:
- New proto message EventForBattalionBackstory with event types:
- OrganizedTroops: tracks size changes, hiring, dismissals, transfers
- SuppressedBeasts: records beast suppression operations
- ApprehendedOutlaws: records outlaw apprehension (for future use)
- FoughtInBattle: records battle participation and casualties
- New Scala enum EventForBattalionBackstoryT matching the proto
- Updated BattalionT trait and BattalionC with:
- backstoryVersions: Vector[BackstoryVersion] for LLM-generated text
- backstoryEvents: Vector[EventForBattalionBackstoryT] for events
- Helper methods: withBackstoryVersions, withBackstoryEvents, addBackstoryEvent
- New converters:
- BackstoryVersionConverter (extracted for reuse)
- EventForBattalionBackstoryConverter
- Updated BattalionConverter to handle backstory fields
- Wired up backstory events in:
- SuppressBeastsCommand: adds SuppressedBeasts event to battalion
- ResolveBattleAction: adds FoughtInBattle event to battalions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add LLM-driven battalion backstory updates
This commit adds the system to actually use battalion backstory events
to trigger LLM-generated backstory updates, similar to the hero backstory
update system.
New components:
- BattalionBackstoryUpdateAction: finds battalions with events, generates
LLM requests, adds new backstory versions, and clears events
- BattalionBackstoryUpdateActionGenerator: creates action from game state
- BattalionBackstoryUpdatePromptGenerator: generates prompts describing
events for LLM to update backstory
- BattalionBackstoryUpdateRequest proto message and converter
The system is wired into:
- EndPlayerCommandsPhaseAction
- EndVassalCommandsPhaseAction
- EndBattleAftermathPhaseAction
- EngineImpl (command execution)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Track previousSize/newSize for battalion events, add heroId to OrganizedTroops
Changes:
- SuppressedBeasts event: replaced 'casualties' with 'previousSize' and 'newSize'
- ApprehendedOutlaws event: added 'previousSize' and 'newSize' fields
- OrganizedTroops event: added 'heroId' for the province ruler who ordered the reorganization
- OrganizeTroopsCommand now creates battalion backstory events when troops are organized
- Updated prompt generator to include hero names and size information
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a game is deleted (via admin console or last player dropping),
cancel any pending Shardok battles to:
- Stop processing battles for non-existent games
- Prevent reconnection attempts for deleted games
- Clean up resources
The implementation removes matching entries from pendingBattles map,
which prevents scheduleReconnect from re-establishing streams and
handleStreamingResponse from processing further updates.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add CRUD handlers for managing what's-new entries stored in S3
- Add whats_new.html template with add/edit/delete forms
- Add navigation link to layout.html
- Add player-friendly summary generation to generate_changelog.sh
- Add seed JSON file for initial data
The admin console at /whats-new allows managing changelog entries
that will be displayed to players in the Unity client. The script
integration generates summaries and opens the admin console with
pre-populated content after sending weekly changelogs.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add battalion backstory popup on hover
Add support for displaying battalion backstories when hovering over
battalions in the Battalions panel, similar to hero backstories:
- Added battalionPopupPanel and battalionPopupPanelBackstory fields
- Added BattalionLongHoverRowChanged method to handle hover events
- Uses GeneratedTextUpdater for auto-scrolling text display
To wire up in Unity:
1. Create a popup panel similar to hero popup
2. Add GeneratedTextUpdater component for backstory text
3. Assign references in HeroesAndBattalionsPanelController
4. Wire battalionsTable.LongHoverRowChangedHandler to BattalionLongHoverRowChanged
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Eagle0 > Build Protos menu item for editor proto rebuilds
Provides a convenient way to rebuild protocol buffer files from within
Unity Editor (Cmd+Shift+P on Mac). This helps when proto files change
and the generated C# code needs to be updated.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Wire up battalion backstory popup panel in Unity
- Add TableRowHoverDetector to Battalion Row Prefab for hover events
- Configure battalion popup panel in Gameplay scene
- Wire LongHoverRowChangedHandler to BattalionLongHoverRowChanged
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Position popup column spacer via EagleGameController layout system
Set the popup column spacer width in ArrangeLayout() alongside the
heroes and battalions panel width, ensuring they stay synchronized
when resolution changes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Propagate battalion backstories to clients by adding backstory_text_id
field to BattalionView proto and Scala view classes.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1. Command Interaction Guidance (onboarding step 7):
- Explains clicking provinces for acting vs right-click for target
- Describes using left side panels for heroes/battalions selection
- Reminds that Commit finalizes the command
2. Hero Stat Gain Tutorial:
- Triggered first time a player's hero gains a stat point
- Uses HeroStatGained action result type for reliable detection
- Explains experience, stat growth, and professions
Also updated info button tutorial to mention the '?' keyboard shortcut.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Completed:
- Bug report form in Unity client
- Feedback channel (Discord server)
- Support plan (Discord + bug reporting + email)
- Art/music licenses and open source disclosures (attributions panel)
Added end game ideas:
- Win condition: all other factions defeated
- Mid-game progression: King recognition events
Moved "What's new" changelog to nice-to-have.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add battalion initial backstory generation
Adds LLM-generated backstories for battalions created at game start.
Changes:
- Add backstoryVersions field to Battalion proto and BattalionT/BattalionC
- Add BattalionInitialBackstoryRequest to GeneratedTextRequestT
- Create BattalionInitialBackstoryPromptGenerator for LLM prompts
- Wire up in LlmResolver and NewGameCreation
- Update BattalionConverter to handle backstory versions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Rename hero_backstory_version to backstory_version
Since BackstoryVersion is used for both heroes and battalions, rename:
- hero_backstory_version.proto -> backstory_version.proto
- hero_backstory_version_proto -> backstory_version_proto
- hero_backstory_version_scala_proto -> backstory_version_scala_proto
Also rename leading_hero_id to province_ruler_hero_id in
BattalionInitialBackstoryRequest to clarify this is the hero who
rules the province, not a battalion commander.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Fix bug report panel not showing on first click
Change Start() to Awake() so initialization happens at load time
rather than when the GameObject first becomes active. This prevents
Start() from disabling the panel after Show() has enabled it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Enable BugReportPanelController GameObject at scene start
The controller needs to be active so Awake() runs at load time,
allowing Show() to work on first click.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add bug report form to Unity client
Adds a Report Bug button to the Settings panel that opens a bug report
form. Reports include:
- User description
- Game state (game ID, faction, date, active battles)
- System info (OS, CPU, GPU, resolution)
- Recent connection logs
Reports are sent via webhook (supports Discord and Slack).
Configure webhook URL with BugReportPanelController.SetWebhookUrl().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Configure Discord webhook URL for bug reports
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add escape key handling for bug report and attributions panels
- Bug report panel closes on Escape
- Attributions panel closes on Escape
- Settings panel only toggles if other panels aren't open
- Wire up bug report panel UI in Gameplay scene
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The warmup binary was being copied from a hardcoded bazel-bin path that
doesn't work reliably with cross-compilation and remote caching. When the
binary was cached but not materialized locally, the cp command would fail.
Fix by:
- Create a warmup_tar pkg_tar target that packages the warmup binary
- Use tar extraction instead of cp, which forces Bazel to materialize
the output file before the command runs
- Rename the binary from warmup_linux_amd64 to warmup in the tar
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Update Recruit command panel layout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update Diplomacy toggles to button-style like Improve
Change radio-style toggles to highlighted button toggles using
ToggleGroup and CanvasGroup alpha for disabled state.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Make HeroGenerator immutable with private constructor
- Change `var remainingPregeneratedHeroes` to `val`
- Return tuple `(HeroGenerationResponse, HeroGenerator)` from getHero()
- Add `forTesting()` factory method for test usage
- Filter excluded names during construction instead of lazily
- Make BattalionNameGenerator immutable
- Change `var excludingNames` to `val` (was never mutated anyway)
- Update callers to properly thread the generator through recursion/fold
- PerformUnaffiliatedHeroesAction: thread generator through `go` recursion
- NewGameCreation: thread generator through fold, extract at end
- EngineImplTest: use forTesting() instead of mock
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
casualtyCount was incorrectly set to total damage (including hero vigor
loss) instead of just battalion troop losses. Now:
- No battalion: 0 casualties
- Battalion survived: actual troop losses
- Battalion destroyed: entire battalion size
This ensures casualtyCount semantically represents battalion casualties,
not hero damage which is tracked separately.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a hero suppresses beasts alone (no battalion), casualtyCount can
still be > 0 because casualties are applied to hero vigor. The code
incorrectly tried to access the battalion name for casualty text even
when no battalion existed.
Now only show battalion casualty text when a battalion actually exists.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>