The grpc 1.78.0 upgrade eliminated the rules_swift version conflict
that required SparklePlugin to live in a separate Bazel workspace.
Move it back into the main workspace under src/main/objc/.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add giant beast type using 3x-scaled peasant model
Reuse Polytope peasant prefabs at 3x scale (animalScale 45) with a single
wandering giant per province. Uses HumanMapAnims controller for idle/walk/
attack animations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix giant test method to use correct province name (Elekes)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wire up GiantEffect prefab in Gameplay scene
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Fix Bazel Xcode version caching causing CI build failures
When Xcode updates on self-hosted runners, Bazel's cached
local_config_xcode still references the old version, causing
"xcode-locator <old_version> failed" errors.
Add sync_bazel_xcode.sh which detects Xcode version changes
and runs `bazel sync --configure` to refresh the config without
nuking the build cache. Added to all 8 CI workflows that use Bazel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use rm of cached repo instead of bazel sync --configure
bazel sync --configure requires WORKSPACE mode and fails with
bzlmod. Instead, delete the stale local_config_xcode from the
output base directly — the next bazel build regenerates it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use bazel clean --expunge instead of targeted repo deletion
Deleting just local_config_xcode is insufficient — the stale Xcode
version is also embedded in cached actions and other toolchain repos.
The only reliable fix is a full expunge. Since Xcode updates are
infrequent, the one-time rebuild cost is acceptable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use action_env to bake Xcode version into cache keys
Instead of expunging the cache (which doesn't help with the remote
cache anyway), write the Xcode build version to .bazelrc.xcode via
--action_env. This makes the version part of every action's cache
key, so stale entries in both local and remote caches are naturally
ignored after an Xcode update — no deletion needed anywhere.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add expunge back alongside action_env for belt-and-suspenders fix
action_env alone isn't enough — local_config_xcode is a cached
repository rule that bakes in the old Xcode version before any
actions run. Need expunge to clear the local toolchain config,
plus action_env to prevent stale remote cache hits afterward.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add Xcode sync to mac_build build-and-sign job
The sync step was only in the deploy job, but build-and-sign calls
bazel via build_protos.sh before that. This runs on the unity-mac
runner which also has the stale Xcode cache.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
It uses the Butcher 2D sprite via ButcherBeastNames HashSet,
but was missing from the documentation table.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
grpc 1.78.0 dropped its rules_swift dependency, resolving the version
conflict (rules_swift 3.x vs 2.x) that forced SparklePlugin into a
separate workspace. This removes the rules_swift single_version_override.
Includes a patch for a known BCR bug (grpc/grpc#41438) where grpc 1.78.0
requests Python 3.14.0b2 but rules_python >= 1.6.0 replaced it with 3.14.
The patch backports the upstream fix (commit 459279b).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace the 2D PSD-based DragonRed sprite with a 3D FBX model from 3dFoin
Dragon. The dragon now alternates between flying (circling at altitude with
fly/flyAttack/flyBreathFire/flyFast/flyHit actions) and grounded (wandering
with walk/run/attack/breathFire/whipTail/hit/stand/idle actions) modes.
- Add DragonMapAnims.controller with 15 animation states
- Configure dragon_skin.FBX for Generic animation with avatar
- Rewrite DragonEffect.cs with 4-mode state machine
- Delete old 2D DungeonMonsters2D dragon assets
- Add Dragon/ to LFS rules and clang-format excludes
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add 5 Polytope character archetypes for human beast animations
Replace the single Butcher sprite for all 34 human-type beasts with
5 thematic 3D archetypes using Polytope Studio Lowpoly Medieval
Characters: Knight (6 beasts), Soldier (8), Archer (3), Militia (8),
and Peasant (9). All share a HumanMapAnims controller that retargets
Clown animation clips via Unity's Humanoid system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Rename humanEffectPrefab to butcherEffectPrefab; route psychopath to it
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Move butcherEffectPrefab under Human Effect Prefabs header
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wire up Polytope prefabs in scene; rename HumanEffect to ButcherEffect
Wire all 6 human effect prefabs (butcher, knight, soldier, archer,
militia, peasant) in Gameplay.unity scene. Rename HumanEffect.prefab
to ButcherEffect.prefab to match the field rename.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Exclude third-party asset packs from clang-format hook
Skip DungeonMonsters2D, Polytope Studio, RRFreelance-Characters,
and Raccoon directories — these are vendor code that should not
be reformatted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* LFS-track all files under third-party asset pack directories
Track all files under DungeonMonsters2D/, Raccoon/, Polytope Studio/,
and RRFreelance-Characters/ via Git LFS. These are imported third-party
assets that are never manually edited.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Convert DungeonMonsters2D and Raccoon assets to Git LFS
Re-add all files under DungeonMonsters2D/ and Raccoon/ through
the LFS filter so they're stored as LFS objects going forward.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The warmup-binary artifacts from docker_build were accumulating and
exceeding the 500 MB storage threshold. GitHub's retention-days cleanup
wasn't keeping up with deploy frequency. Add explicit artifact deletion
after deploy, matching what mac_build already does.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add raccoon beast animation using Sketchfab 3D model
Adds Raccoon.fbx (WildMesh 3D, CC BY 4.0) with textures, wires up
raccoonEffectPrefab in ProvinceBeastsController, and updates both
attributions.json files and BEAST_EFFECTS.md.
Editor steps still needed: create RaccoonMapAnims controller, create
RaccoonEffect prefab (duplicate HoneyBadgerEffect), wire in Gameplay.unity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wire up raccoon animation with Blender-converted FBX
Convert GLB to FBX via Blender (original FBX had no animation data).
Add RaccoonMapAnims controller, RaccoonEffect prefab, materials with
textures, scene wiring, and fix province name (Hella, ID 19).
Known issue: gray sphere artifact under each raccoon.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove Icosphere/hair artifacts from raccoon FBX and update scene
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Smooth 3D animal turning with Quaternion.Slerp
Animals now rotate smoothly toward their target instead of snapping.
UpdateFacing is called every frame during walking, and uses Slerp
with a configurable turnSpeed (default 5) for gradual rotation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Eliminates the duplicate attributions.json by making the Unity copy
a symlink to src/main/resources/net/eagle0/attributions.json, ensuring
a single source of truth that can never diverge.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add honey badger 3D model and wire up AnimalEffect
Import HoneyBadger FBX (63 animations) and texture from Sketchfab.
Add honeyBadgerEffectPrefab field and switch case in
ProvinceBeastsController. Still needs Unity Editor setup: Animator
Controller, effect prefab, and scene wiring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix honey badger test province name (ID 1 is Shumal, not Onmaa)
Onmaa is province ID 14, already used by TestWildPig.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wire up HoneyBadgerEffect prefab and animator controller
- HoneyBadgerMapAnims controller with idle/walk/eat/attack states
mapped to HoneyBadger FBX clips
- HoneyBadgerEffect prefab with AnimalEffect referencing the model
- Wired into Gameplay.unity ProvinceBeastsController
- Includes Unity-generated .meta files for imported assets
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix HoneyBadger FBX avatar setup to enable animations
avatarSetup: 0 (No Avatar) prevented the Animator from driving the
skeleton. Changed to avatarSetup: 1 (Create From This Model) to match
how the Animal Pack Deluxe models are configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add attribution for recently added Unity asset packs
Add Animal pack deluxe (janpec), 2D Monster Pack Basic Bundle/PSB
(SP1/DungeonMonsters2D), and Honey Badger 3D model (WildMesh 3D) to
ASSET_AUDIT.md. Update 3D model count in summary table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add 3D model attributions to in-app/website credits
Add Animal pack deluxe, 2D Monster Pack, and Honey Badger
to both server and Unity client attributions.json files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Prevents Claude from combining bash commands with &&, ||, or ;.
Each command must be a separate tool call, which makes permission
rules work correctly per-command.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add clown beast animation using both Clown Pack models
- Add per-prefab animator controller overrides to AnimalEffect
(animatorControllers[] array, indexed to match animalPrefabs[])
- Create ClownMapAnims and FatClownMapAnims controllers mapping
idle/walk/eat/attack states to each model's animation clips
- Create ClownEffect prefab using both Clown and Fat Clown models
- Add clown case to ProvinceBeastsController, remove from HumanBeastNames
- Wire up in Gameplay.unity scene
- Update BEAST_EFFECTS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix ClownEffect prefab (recreated via Unity editor)
The hand-written prefab YAML was rejected by Unity's PrefabImporter.
Recreated by duplicating the working OgreEffect prefab in the editor
and configuring the AnimalEffect fields there.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Update BEAST_EFFECTS.md: ogre/troll now have custom animation
Reflects the addition of the Orc-Ogre pack AnimalEffect for ogre and
troll beast types (PR #6287). Removes them from the "no custom
animation" list and adds them to the custom animations table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add complete beast coverage details to BEAST_EFFECTS.md
- Add missing animal effect entries (crab, frog, rabbit, salamander,
scorpion, stag, wild goat, wild pig) to custom animations table
- Add human-type beast breakdown by likelihood with thematic clusters
for potential visual differentiation beyond the generic Butcher prefab
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace unsafe asInstanceOf casts with pattern matching via helper
methods. This is more idiomatic Scala and will give clearer error
messages if the map contains unexpected types.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Fixes two issues with beast balance:
1. Demons and vampires were impossible to defeat - reduced maxCountMultiplier
from 0.5 to 0.15 so an elite battalion (1000 troops, 100/100 stats) can
just barely defeat them.
2. Clowns had a 39% chance of being deadlier than demons due to their huge
power variance (0.8-50). Added a powerExponent field to beasts.tsv that
controls how the random roll translates to power. Default is 4 (quartic),
clowns use 20 which reduces the chance of deadly clowns to ~10%.
The casualties formula is: casualties = beastsPower² / totalPower
Where beastsPower = count × relativePower
This means overwhelming force results in minimal casualties (intended),
but also means high beast power causes quadratically more damage.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
ProvinceWasSelected accessed Model.AvailableCommandsByProvince and
Model.Provinces without checking if Model was null. This caused a
crash when the user clicked a province before the game model was
received from the server on first load.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add animatorController override field to AnimalEffect so it can swap
the prefab's controller at runtime (needed because the Orc-Ogre pack
uses state names like Ogre_Idle1 instead of the expected idle/walk/etc)
- Create OgreMapAnims.controller with idle/walk/eat/attack states mapped
to Orc-Ogre FBX animation clips
- Create OgreEffect.prefab using AnimalEffect + controller override
- Add ogre/troll cases to ProvinceBeastsController.GetEffectPrefab()
- Wire OgreEffect in Gameplay.unity scene
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Wire up animations for 8 new beast types
Add effect prefabs and scene wiring for crab, frog, rabbit,
salamander, scorpion, stag, wild goat, and wild pig using
Animal Pack Deluxe 3D models with AnimalEffect controller.
Multi-variant prefabs: frog (3), scorpion (2), rabbit (2),
stag (2), wild goat (2), wild pig (2).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix ContextMenu test labels to use real province names
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix animal effect prefab references to use root GameObjects
Each Animal Pack prefab contains many child objects (bones, meshes, etc).
The effect prefabs were incorrectly referencing the first child object
instead of the root prefab object (the one with m_Father: {fileID: 0}).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Tune animal effect scales per beast type
Adjusted animalScale values from the Unity editor after visual testing:
- Frog, salamander, scorpion, crab: 50 (small creatures need more zoom)
- Rabbit, stag, wild goat, wild pig: 20 (medium animals)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Order beasts without custom animations by how commonly they appear,
making it easier to prioritize which to add next.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Document all three effect types (MonsterEffect, AnimalEffect,
DragonEffect), list all beasts with custom animations vs vulture
fallbacks, and add 3D rendering tips.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add animal wandering effect for bear, boar, crocodile, snake, wolf
New AnimalEffect.cs drives Animal Pack Deluxe 3D prefabs using their
lowercase state names (idle, walk, run, eat, attack) and Y-rotation
for facing direction. Wolverine reuses the wolf prefab.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add animal effect prefabs and scene wiring for bear, boar, crocodile, snake, wolf
Wire AnimalEffect prefabs to ProvinceBeastsController and include the
Animal Pack Deluxe asset pack. RatEffect now has both MonsterEffect
(2D sprites) and AnimalEffect (3D model) for a mixed group.
Add LFS tracking for .tga and .fbx files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix animal facing direction to use full angle rotation
3D models need to rotate Y by the actual movement angle, not just
0/180 degrees. Use atan2 of the XY direction vector so animals face
their actual travel direction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix animal rendering and remove die animation
Use sortingOrder=103 on 3D mesh renderers instead of Z offset hack
to render animals above the map. Guard against die animation state.
Default scale to 15. Remove unused run state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Disable depth test on animal renderers to prevent map clipping
When 3D animals rotate to face away, their geometry extends into
positive Z and clips behind the map plane. Setting ZTest=Always
ensures they always render on top regardless of orientation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix animal depth clipping with renderQueue and ZWrite/ZTest overrides
Use renderQueue=4000 (Overlay), disable ZWrite, and set ZTest=Always
via SetFloat (compatible with more shader types) to prevent 3D animal
meshes from clipping behind the map when rotated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The first hero departure notification in the tutorial has no narrative
context. Old Marek now comments when a non-player faction loses a hero,
noting that Bregos has always inspired loyalty and something deeper must
be at work after the upheaval with Tarn.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add wandering monster animations for beast events on Eagle map
Replace generic vulture effects with animated DungeonMonsters2D monsters
for skeleton, zombie, rat, spider, demon, orc, and human-type beasts.
Each MonsterEffect spawns a group of 3 monsters that wander randomly,
idle, and occasionally attack within a province.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add ContextMenu test actions for monster effects
MonsterEffect: Test All Idle/Move/Attack/SpecialAttack
ProvinceBeastsController: Test spawn for each beast type in Motcia
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Spread test beast spawns across different provinces
Also add "Test All Beast Types" to spawn all 8 at once.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix monster sprite facing direction
DungeonMonsters2D prefabs default to facing left, so invert the
X scale flip logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove malformed AnimationEvents from SkeletonArcher anims
The asset pack shipped with empty functionName fields on these events,
causing "AnimationEvent has no function name specified" errors at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wire humanEffectPrefab in Gameplay scene
The HumanEffect prefab was created but never assigned to the
ProvinceBeastsController Inspector field, so human-type beasts
fell through to generic vultures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add vampire beast type and remove unused DungeonMonsters2D assets
- Add VampireEffect prefab, code mapping, scene wiring, and test entry
- Remove Bat, Ghost, GhostKnight, and four Golem variants (animations,
characters, PSBs) that aren't mapped to any beast type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove DragonEffect component from monster effect prefabs
These were created by duplicating the dragon prefab, which left a
DragonEffect component that spawned an extra dragon alongside the
intended monsters.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Update Eagle appearance trigger for Hedrick and Sadar expansion
Replace Bridget (faction 4) with Hedrick (faction 5) as the tutorial
antagonist, and add a second trigger path: Sadar controlling 4+ provinces.
The Eagle now appears when either Hedrick is eliminated OR the player
faction grows strong enough to warrant attention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Lower weak King province hero loyalty to 20
Makes the heroes in the King's weak provinces much more likely to
defect, as they barely have any loyalty to the King.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Adjust weak King province hero loyalty to 25
Loyalty 20 was causing heroes to depart too quickly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Horseshoe prints were facing forward (open end leading) instead of
trailing behind the horse. Added 180° rotation for mounted units.
Duel accepted animation was never playing because DuelAccepted wasn't
matched as a result of the pending DuelChallenge command. Added it to
IsResultVariant and cached source/target grid indices in
PendingCommandSound so the animation plays even when units have been
removed from the model by later duel combat results in the same batch.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add tutorial-specific initial chronicle text
The tutorial was using the same initial chronicle text ID as regular
games, but the text content references "The Eagle" character which
doesn't exist in the tutorial scenario. When the LLM tries to generate
a chronicle update, it looks up the previous chronicle entry's text
as a dependency, causing "Unknown dependency for LLM request" errors.
This adds a tutorial-specific chronicle text that describes the
actual tutorial scenario: Sadar Rakon defending Onmaa against
King Bregos Fyar's army led by Ikhaan Tarn.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update tutorial chronicle text wording
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Register SupportField dynamically for tutorial dialogue highlight
The SupportField highlight in the tutorial_rebuild_support and
tutorial_support_deadline dialogues wasn't appearing because the
static Inspector reference on TutorialTargetRegistry was not wired up.
Dynamically register the field from EagleGameController, matching the
pattern used for GoToBattleButton and CommandPanel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix Elena's reinforcement dialogue referencing Tarn incorrectly
Tarn and the King are still allies at this point, so "half of them
had already fled before Tarn's men even arrived" doesn't make sense.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Vary Ranil's siege dialogue to avoid repeating Marek's phrasing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix highlight not rendering inside layout groups
The dialogue highlight was invisible when targeting UI elements inside
a layout group (e.g. SupportField). The highlight container was being
treated as a layout child, which collapsed its rendering. Adding
LayoutElement with ignoreLayout=true makes it overlay correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Make Reset Tutorials also reset dialogue and trigger state
ResetAllProgress previously only cleared the old tutorial system's
PlayerPrefs state. Now it also clears DialogueManager's completed
script IDs and TutorialTriggerRegistry's one-shot flags, so all
narrative dialogues can replay without restarting the game.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix NRE: add RectTransform before LayoutElement
LayoutElement is a UI component that auto-creates a RectTransform,
so the subsequent AddComponent<RectTransform>() returned null.
Reorder so RectTransform is added first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The conditional `if po.support > 0` prevented explicitly setting
support to 0. Now support always uses the JSON value directly.
Provinces 37 and 40 already have their support values specified.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Remove the special case that allowed Ikhaan Tarn to flee.
Now all units in the tutorial battle must fight to the end.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When we added Hedrick as an independent faction (ID 5), we didn't
add it to the aiFids list in createTutorialGameForUser. This caused
the game to get stuck waiting for commands from a faction that had
no AI controller.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Override duel_base_accept_odds to 200 (max roll is 100) for tutorial
games so the player's first duel challenge is always accepted,
ensuring the tutorial can teach dueling mechanics reliably.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Split reinforcement dialogue into per-hero events for staggered arrivals
Now that reinforcements arrive at different times (Elena round 5, Ranil
round 6), inspect the arriving unit's profession to fire hero-specific
dialogue triggers instead of one generic event for all reinforcements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update tutorial dialogue and add capture/duel triggers
- Update Elena Fyar's reinforcement dialogue: escaped captivity in Pieska
- Update John Ranil's reinforcement dialogue: pushed through from Nikemi
- Add enemy hero captured dialogue trigger with dynamic hero name
- Add friendly hero captured dialogue with special cases for Marek/Sadar
- Prioritize duel tutorial over melee when target is not Ikhaan Tarn
- Add GetScriptForTrigger to DialogueManager for dynamic text injection
- Cache unit names for capture detection (units removed before processing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix capture detection to scan removed units instead of action type
CapturedWhileFleeing only fires for flee-based captures. Heroes also
leave the battle via duels, destruction, etc. Now scans every action
result's GameStateViewDiff.RemovedUnits for hero units in the name
cache, catching all forms of hero removal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Make Ranil reinforce from Tarn's direction
Elena continues to reinforce from position 6, but John Ranil
now enters the battle from the same starting position as Tarn
and the other attackers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Delay Ranil's arrival to round 7
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Reduce Sadar's unit sizes by 10%
- Rakon's Loyalists: 511 → 460
- Onmaa Defenders: 300 → 270
- Hunters of the Steppe: 384 → 346
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Refactor beast prefab selection to switch and add extensibility doc
Replace IsDragon boolean check with GetEffectPrefab switch on beast
name string, providing a clear extension point for adding new
beast-type-specific effects. Add docs/BEAST_EFFECTS.md explaining
the architecture and step-by-step process for adding new beast types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use exact beast name matching from beasts.tsv
Switch from case-insensitive substring matching to exact string
matching on the canonical singularName from beasts.tsv. Update doc
with beasts.tsv reference and candidates for custom effects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add dragon beast animation on eagle map
When a province has a dragon beast event, show an animated 2D dragon
(DungeonMonsters2D DragonRed) circling the province instead of generic
vultures. The dragon plays its Move animation while orbiting and
periodically triggers Attack with fire rain particles falling below.
- New DragonEffect.cs: instantiates animated dragon prefab, drives
circular orbit with vertical bobbing, flips sprite to face travel
direction, emits fire rain particle bursts on attack
- ProvinceBeastsController: extracts beast name from BeastsEvent,
selects dragonEffectPrefab when name contains "dragon"
- Add DragonRed from DungeonMonsters2D asset pack (dragon-only files)
- Add .psb and .psb.meta to Git LFS tracking in .gitattributes
- Add 2D PSD Importer package dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix dragon animation and improve fire breath effect
Add com.unity.2d.animation package required for SpriteSkin bone
deformation at runtime. Rewrite fire breath as directional cone aimed
at province center using stretch render mode. Continuously enforce Move
animation state to prevent controller defaulting to Idle. Add context
menu test helpers for spawning dragon effects in editor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add animation variety and disable fire breath for now
Dragon now cycles through Move, Jump, Attack, and SpecialAttack
animations with weighted random selection. Fix IsInTransition check
so action animations play fully before returning to Move. Update
defaults to match tuned Inspector values. Disable fire breath
particle system pending direction/sizing fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add Hedrick faction in Kojaria, move Bridget to Alah
- Move Bridget's faction from Kojaria (39) to Alah (18)
- Create new faction for Hedrick the Hedge-Merchant in Kojaria (39)
with 300 light infantry, 23 support, same development as Onmaa
- Remove Hedrick from battle reinforcements (now only Elena and
John Ranil arrive as reinforcements at rounds 6 and 7)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix reinforcement hero IDs and adjust timing
- Update TutorialReinforcementHeroIds to Set(100, 101) to match
the two remaining reinforcement heroes (John Ranil and Elena)
- Change reinforcement timing: Elena arrives after round 5,
John Ranil arrives after round 6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
ExecuteReinforcementsAction was placing ALL PENDING_REINFORCEMENT
units when any reinforcement event fired, instead of only the units
belonging to that specific event. Match pending units by eagle_hero_id
against the event's CommonUnit list so each event only activates its
own reinforcement.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The updateWith call was only setting gold and food, ignoring the
support, economy, agriculture, and infrastructure values from the
tutorial_parameters.json configuration. This caused Onmaa to have
default values (0 support, 20/20/20 development) instead of the
configured values (23 support, 45/41/42 development).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Set up 12 King's provinces with single noProfession heroes, no troops,
no resources, and low loyalty to portray the realm falling apart:
- East Faluria, Regigia, Tegrot, Berkorszag, Oscasland, Wichel,
Oriyslia, Mesh, Musland, Motcia: loyalty 50-55
- Nikemi, Pieska: loyalty ~40 (even weaker)
Also refactored the attacking army (Ikhaan Tarn's force) to be
created directly in TutorialGameCreation.scala rather than read
from JSON, since the army is already in transit when the game
starts - it's not actually stationed in Nikemi.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add fear success and fear resisted animations
Fear success: dark cloud engulfs the target, pulses ominously, then
slowly dissipates. Fear resisted: a white flash at the target deflects
the wave back toward the source where it shrinks and fades.
Split Fear into three animation types (Fear attempt, FearSuccess,
FearResisted) so the server result triggers a distinct visual. The
pending command handler now also plays result animations, not just
sounds. Rename IsFailureVariant to IsResultVariant to handle both
success and failure result matching.
Add test buttons for Fear Success and Fear Resisted in the animation
test controller.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Refactor test controller to use real sound+animation flow and fix fear attempt sound
Route most animation tests through TestPlayAnimationAndSound to exercise
the real two-stage sound pipeline. Consolidate duplicate PlayAnimation
methods and remove ?? fear fallback that caused double-play.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix fear sound routing and remove test debug logging
Add FearSuccess/FearResisted to ActionTypeForSound so they play the
correct result sounds. Pass isOwnCommand=true in test path so Fear
exercises the two-stage attempt sound.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Improve fear success and fear resisted animations
Fear success: tendrils start 2x farther out with ease-in spiral, add
ghost skull at 40% opacity filling the hex. Fear resisted: shield sprite
pops up and bashes the skull back toward the source with spin and flash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Cut defending unit sizes by 25% (681→511, 400→300, 512→384)
- Cut reinforcement unit sizes by 25% with battle-worn variation
(450→443, 375→382, 450→446)
- Double food in Onmaa (2000→4000) to support larger army
- Set Onmaa development stats: 45 economy, 41 agriculture, 42 infrastructure
Reinforcements already arrive one at a time (rounds 5, 6, 7).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Tutorial game creation was passing an empty pregeneratedHeroes pool to
HeroGenerator, causing a crash when PerformUnaffiliatedHeroesAction
tried to spawn new heroes in provinces (e.g., when building support in
Onmaa).
Changed to use GameParametersUtils.pregeneratedOthers as the pool,
excluding hero names already used in the tutorial to avoid duplicates.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>