03083eb735
CLAUDE.md: the enemy anti-stuck nudge is now cover-aware (budget 38.5 KB). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
218 lines
18 KiB
Markdown
218 lines
18 KiB
Markdown
---
|
||
title: Iteration 2026-07 — Co-op Hades Conversion (Trunk + Hub-ification + Depth + Blender)
|
||
date: 2026-07-06
|
||
tags: [roadmap, iteration, coop-hades, direction, plan]
|
||
permalink: gamevault/06-roadmap/iteration-2026-07-coophades
|
||
---
|
||
|
||
# Iteration 2026-07 — Co-op Hades Conversion
|
||
|
||
**Operator decision (2026-07-06, dev-loop iteration session):** commit the *Fix-the-Fight-in-Place trunk* PLUS the full
|
||
*Co-op Hades* direction — cut/mothball the tower-defense layer, base becomes a Hades-house hub, boons become
|
||
mechanic-changers, kit gains a second ability, real node types, second boss, co-op revive. **Depth folds in now** (not
|
||
after a playtest gate). **Blender scope: hero props + decals.** No time estimates (operator directive). Grounded by a
|
||
9-agent analysis workflow (`wf_8afc6e5a-b9e`, 9/9 clean) + a live end-to-end play tour with screenshots
|
||
(`Assets/Screenshots/iter_*.png`).
|
||
|
||
## Evidence base (why this direction)
|
||
|
||
- Live tour findings: half of all rooms (sub-slot X+1500) have **no ground/colliders/decor**; enemies interpenetrate
|
||
into a blob and spawn converges on the player; HUD header reads "AT BASE" inside expedition rooms; boon offer
|
||
contained a strictly-dominated pair (-25% vs -15% ability cooldown); portal beacon renders as a blown-out white egg;
|
||
storage crate floats; **save-persisted `RunRuntime.WasAllReady=1` deadlocks the next session's launch** (un-ready →
|
||
re-ready is the only escape).
|
||
- Critique consensus: every reward is a flat stat mod (zero mechanic-changers/synergies); kit = 3 verbs/class with 1
|
||
distinct ability; run 2 ≡ run 1; threat is walk-out-able (boss slam escape needs 4.07 u/s vs 5.1 available; melee
|
||
knockback stunlocks all trash; death = free heal + re-conscription); the boss is a 1.6× Charger with one attack.
|
||
The code-side feel layer (cones, slash arcs, hit-stop, flashes) is STRONG — the gap is the asset/scene layer under it.
|
||
- Market: Windblown's chart-topping demo = 1 biome + 1 boss (loop is demo-sized already); Cult of the Lamb = the
|
||
base↔run tie done right, Moonlighter = the cautionary tale; HoH2's retention lever = every run banks something;
|
||
Synty-look ceiling proven by Death Scourges / RoR2 / Soulstone Survivors (dynamic-light-first, dark ambient).
|
||
|
||
## Phase 0 — Stabilize (bugs found live, do first)
|
||
|
||
1. Commit the working-tree portal fix (incl. the `_portalMat` comment-swallow NRE repair applied 2026-07-06 — the NRE
|
||
killed CombatFeedbackSystem every session and auto-paused the editor via Error Pause). Re-run 456 EditMode first.
|
||
2. ~~`WasAllReady` save deadlock~~ **RETRACTED (2026-07-06):** misdiagnosis caused by frozen-world polling (the
|
||
`execute_code` main-thread-sleep hazard) — `CycleDirectorSpawnSystem`'s restore builds `RunRuntime` fresh (HostSalt
|
||
only, WasAllReady=0) and nothing persists it; the observed "deadlock" was a run that had already launched between
|
||
MCP calls. Lesson reinforced: never sleep-poll; check `isPaused` first.
|
||
3. Lifecycle-aware HUD header (kill "AT BASE" in rooms; kill stale "choose your boon" after pick — the location-line
|
||
switch had NO RoomExplore case, so the RoomReward text stuck through the loot window).
|
||
4. Ground the floating storage crate (**root cause: `GridOrigin.y=1` is the CC capsule-center plane** —
|
||
`CellToWorld` returns it; center-pivot meshes (Turret/Wall) look grounded there, base-pivot meshes (crate) float
|
||
1 u. Watch this on every future grid-placed base-pivot mesh); tame the portal-beacon HDR (2.6/3.4 bloomed to a
|
||
white egg) + ground the beacon (its `pos.y` was the capsule plane too).
|
||
|
||
## Phase 1 — Trunk (direction-agnostic physical/feel/teaching layer)
|
||
|
||
1. **Rooms become places:** fix the X+1500 void (ground + collider ring + decor for sub-slot 1); seed 3–6 collidable
|
||
Environment-layer props per room so cover/LOS/Charger-baiting exist; readable room edge.
|
||
2. **Enemy separation** (server-side repulsion, MaxAlive=12 so O(n²) is fine) + soft player pushout; no standing
|
||
inside the boss. Verify spawn ring staggering reads (spawn VFX).
|
||
3. **Animation triage:** Synty Sword/Bow Combat anim packs (shared Generic skeleton, no retarget) — death clips +
|
||
corpse window, spawn, hit-react, ranged-fire, dash; creature locomotion for monsters (stop human jog on Husks).
|
||
4. **Threat repair:** poise byte (light hits stop stunlocking trash); boss second attack (re-enable its baked Charger
|
||
lunge) + party-size HP scaling.
|
||
5. **Live knobs:** promote all Boss*/enemy/grace-timer knobs into the TuningConfig overlay + values-to-clipboard.
|
||
6. **Teaching:** RMB class ability + dash coach-marks; fix stale copy (StartingOre 50→90 etc.); run-failed banner.
|
||
7. **Clarity swaps:** distinct spit/pickup/harvest meshes (Synty interim), class weapon meshes on the hand bone,
|
||
ground darkening + character rim/outline, point lights on projectiles (RoR2 trick).
|
||
|
||
**Gate:** one honest solo campaign to Victory + one 2-instance LAN lap with the overlay open.
|
||
|
||
> **Gate outcome (2026-07-07 operator playtest):** trunk holds mechanically, but the verdict is *"not cohesive, very
|
||
> static, visually boring — comparable games' environments are dynamic and interactable"* + ability upgrades boring +
|
||
> the 07-07 harvest shrink/pop never showed on-screen (root cause later pinned same day: a swallowed
|
||
> `[RuntimeInitializeOnLoadMethod]` attribute — NOT the pre-flagged PTM-on-root risk, which live-verified correct).
|
||
> → **Phase 1.5 (World Alive) inserted below; mechanic-changer boons PULLED FORWARD from Phase 3 (Phase 1.7).**
|
||
> Explicit operator framing: make the game **look better**, not more "juice" — the code-side hit-feel layer stays as-is.
|
||
|
||
### Slice B folded design (design-review `wf_fd177263-b67`, 2026-07-06 — 3 lenses done, 15 verify verdicts ALL isReal=true; synthesis died on session limit, folded by hand from the verified findings)
|
||
|
||
- **B3 Dying window:** server-only `Dying{uint UntilTick}` (TickUtil.NonZero, stamp ONCE on the 0-crossing in
|
||
HealthApplyDamageSystem for EnemyTag; destroy after ~54 ticks via Temp ECB). At the mark: zero the REPLICATED
|
||
`AttackWindup`, disable `IsLunging`, zero `KnockbackState` (else corpses keep live telegraphs). CONFIRMED: no AI
|
||
pass self-health-gates today and EVERY count edge counts entities — gate the actor passes (EnemyAI/BossAI move,
|
||
windup, contact) and make every count LIVING-only: RoomEnemyDirectorSystem :48/:68 (room clear + MaxAlive fit),
|
||
ExpeditionObjective.Remaining, boss-summon cap, base-siege cleared checks, aggro snapshots, ProjectileDamageSystem
|
||
:83-91 target snapshot + gamepad auto-aim (no Health>0 filter today — corpses become shields/aim magnets). Client:
|
||
EnemyAnimationDriveSystem writes `IsDead = Health.Current<=0` (param exists, never written); CombatFeedbackSystem
|
||
fires the kill CRUNCH at the 0-crossing (today it fires at prune — would land ~1 s late), prune keeps only a
|
||
cleanup puff; hide health bars at <=0.
|
||
- **B1 separation:** a pass INSIDE EnemyAISystem (sole-position-writer invariant; BossAISystem only has
|
||
[UpdateAfter(EnemyAISystem)]). Pairwise among LIVING enemies, skip lunging/knocked/Dying receivers, boss immovable
|
||
(others push out of its radius), displacement through the swept EnemyMoveUtil move (no wall-shoving). Player
|
||
pushout radius SMALL (< melee range, ~HitRadius+0.35) or grunts can't strike + Spitter cornered-hold re-breaks.
|
||
- **B2 poise:** the windup-cancel is the knockback CONTINUE branch (EnemyAISystem :119-133 grunt, :234-248 charger).
|
||
Threshold on the EXISTING `KnockbackState.Speed` channel (no per-kind data): below it, kb velocity nudges but the
|
||
windup/lunge survives; at/above it, stagger as today. Make the finisher + Warrior cone stamp a higher kb Speed so
|
||
the channel actually distinguishes (light 6 / heavy 9, threshold ~7).
|
||
- **B4 boss lunge:** BossState gains a server-only attack byte; lunge = reposition move (no unique damage — the
|
||
slam stays the damage beat). Telegraph rides `AttackWindup` + the boss's already-baked `IsLunging` ghost bit;
|
||
the client boss-ring override SKIPS the slam ring while IsLunging (draws the standard Charger lunge tell). The
|
||
windup-elapse branch keys on the state byte (today it would deal SLAM AoE on any elapse).
|
||
- **B5 party HP scale:** in the RoomEnemyDirectorSystem boss branch (sole spawn site), scale Health by LIVING
|
||
EXPEDITION players (RegionTag+Health>0), NOT RunParticipant (dead-respawned keep the tag at base).
|
||
- **B6 run-failed banner:** client-only; cache Charge + a wentInRun flag at launch; on the (in-run)->Staging
|
||
transition with Charge unchanged -> "EXPEDITION FAILED" banner. NEVER key on Returning (1-tick transient, and the
|
||
bank lands one tick after it). Launching->Staging aborts don't count (wentInRun gate).
|
||
- **B7 fire-anim pulse:** stateless absolute window derived from AbilityCooldown (the SwingActive idiom) — no
|
||
cached edges (rollback/join-unsafe).
|
||
- **Hygiene:** bytes not enums in Bursted systems; no new [UpdateBefore/After] edges; ~54-tick window + stagger
|
||
threshold + separation strength as live TuningConfig knobs. ⚠ Bursted query-set edits on an UNFOCUSED editor can
|
||
leave a stale Burst binary — have the editor focused for the compile, or expect the restart cure.
|
||
|
||
## Phase 1.5 — World Alive (inserted 2026-07-07 from playtest verdict; visual + dynamism, explicitly NOT juice)
|
||
|
||
Operator interactivity scope (all four selected + two write-ins): breakable clutter with drops · environmental
|
||
hazards · cosmetic reactivity + ambient motion · destructible cover · **collision precision** · **more distinct
|
||
attacks/animations/effects**. Art direction deliberately UNDECIDED — lighting pass first, then pick (see gate).
|
||
|
||
### Stabilize first (bugs, do before the pass)
|
||
|
||
1. ~~Node harvest feedback fix~~ **FIXED (2026-07-07 session B).** Root cause was NOT the pre-flagged
|
||
PTM-on-root risk — live inspection proved the Model child properly parented and root-PTM propagation exact
|
||
(root PTM 0.783 → child LTW 1.723 = 2.2×0.783). The 07-07 knob edit had **swallowed the
|
||
`[RuntimeInitializeOnLoadMethod]` attribute** off `WorldFeelConfig.ResetDefaults` → `Enabled=false` → the WHOLE
|
||
feedback slice (shrink/pop + chips + SFX + micro-punch) silently dead. One-line restore; verified on-screen +
|
||
numerically on a live server-spawned node; 455/455. Operator still eyeballs a real harvest in the next playtest.
|
||
2. ~~Collision precision pass~~ **DONE (2026-07-09, gate-approved incl. missing-collider adds).**
|
||
`ColliderFitTools` (Editor, audit/apply) refit everything to the Game.unity visuals: rings rebuilt
|
||
16/24/24→54/82/82 fine segments fitted to torso-band cliff vertices; cover = convex MeshColliders of the
|
||
actual rock meshes (needed Read/Write on 2 PNB meshes — new CLAUDE.md gotcha); landmarks hint-matched OBB
|
||
fits; 11 solid-prop colliders added (tree/turbine/crates/dish/solar). Verified in the baked CollisionWorld
|
||
(ring closure, cover 8/8 solid, server==client parity) + enemy backstop re-validated live (embedded enemy
|
||
depenetrates out of a cover hull and keeps moving). Operator feel-lap still pending. See
|
||
[[2026-07-09_B4d_Tail_Collision_Grounding]].
|
||
|
||
### Short-term wins (asset/scene/client layer)
|
||
|
||
3. ~~Lighting/atmosphere pass~~ **DONE (2026-07-09, `414f9ff62`)** — dark ambient + DynamicLightSystem
|
||
(projectile/portal/node/impact-flash lights) + landmark mood lights + per-biome dark palettes; found+fixed
|
||
the dead Linear-fog density knob. **ART LOOK LOCKED (operator, 2026-07-09): CLEAN DARK-SYNTY — pixel filter
|
||
OFF** ("everything feels smoother & sharper without it"); the PixelOutline feature stays dev-toggleable (F3)
|
||
with `_MasterEnabled=0` shipped. Operator is open to experimenting with OTHER fullscreen/shader effects
|
||
later (sharpen/vignette/grade variants — backlog). Every later visual choice keys off clean dark-Synty.
|
||
4. **Ambient motion layer (client-only, zero netcode):** foliage sway/rustle on walk-through, per-biome dust/embers/fog
|
||
drift particles, critters that scatter, flags/banners. Biggest bang-per-effort for "not static".
|
||
5. ~~Breakable clutter with drops~~ **DONE (2026-07-09, `53bc21143`)** — the BlightClutter chain already
|
||
existed end-to-end (seeding/unified-sweep/drops); the gap was feel: barrels (SM_Prop_Barrel_01) replace the
|
||
rock chunk, ONE-hit pop (Remaining 8→2), density 6→8/room. Live-verified pop + drop credit.
|
||
6. **Attack distinctness — CODE-SIDE DONE (2026-07-09, `a335ca3f2`):** per-kind telegraph colours (shapes
|
||
were already per-kind), per-kind windup voices, ownership-keyed projectile lights. The anim-side depth
|
||
(per-kind clips, creature locomotion — still open from Phase 1.3) rides the parallel Blender workstream.
|
||
|
||
### Long-term (server-sim; adversarial design-review REQUIRED per slice)
|
||
|
||
7. **Environmental hazards — v1 SHIPPED (2026-07-10, `cd607ae15`, review-first `wf_2cb10454-fdf`):**
|
||
exploding barrels — ~25% of clutter seeds explosive; pop lights a ~0.6s FUSE (replicated Remaining=0 =
|
||
the client cue, strobing red glow) then radius-damages BOTH sides (bait mechanic; escapable). Zero new
|
||
replication. Geysers/trap tiles = later hazard variants on the same HazardExplosionSystem chassis.
|
||
See [[Exploding_Barrels_Build_Spec]].
|
||
8. **Destructible cover — SHIPPED (2026-07-10, `bbf418e77`, review-first `wf_e14dd739-069`): PHASE 1.5 IS
|
||
COMPLETE.** Cover = BlightClutter ghosts (Variant 4) with baked env-layer colliders — genuinely block
|
||
(the anti-stuck nudge is now cover-aware) until carved (8 hits, zero yield — deposit decoupled from
|
||
durability); no cover in Boss rooms; backstop re-validated live (block/depenetrate/carve all proven).
|
||
Follow-ups: Charger smashes cover; true projectile-blocking. See [[Destructible_Cover_Build_Spec]].
|
||
|
||
**Gate:** operator playtest says "no longer static"; node harvest feedback visibly works; art direction LOCKED.
|
||
|
||
## Phase 1.7 — Boon overhaul (PULLED FORWARD from Phase 3, operator call 2026-07-07)
|
||
|
||
- **Boons → ~12 mechanic-changers** on existing hooks: dash damage trail, finisher AoE detonation, projectile
|
||
pierce/fork/chain, ability-SWAP boons (replicated AbilityRef byte via the ClassSwapUtil pattern), knockback→pull…
|
||
plus synergy tags, duplicate/dominated-offer protection. Design-review before coding (replicated ability swaps).
|
||
|
||
**Gate:** two consecutive runs feel different from boons alone.
|
||
|
||
## Phase 2 — Hub-ification (structural; adversarial design-review REQUIRED before coding)
|
||
|
||
- **Mothball, don't delete:** sieges/CoreIntegrity/turret-ammo retired from the flow via baked toggles (the
|
||
`ScheduleEnabled` pattern); code + tests keep compiling for reversibility.
|
||
- **Win condition moves fully into the expedition** (N boss-clears / final-boss Victory; `GoalReachedSystem` +
|
||
`RunOutcome` rework; SaveData v7 additive).
|
||
- **Base = hub:** class/prep/meta/ready + deposit; visible growth (unlocks at Charge milestones); staging HUD →
|
||
progressive disclosure (5 dense panels → contextual).
|
||
- **Economy simplification** (4 currencies is bureaucracy; turret-ammo Charge frees up) — scope at the design review.
|
||
|
||
**Gate:** returning player goes staging→launch in <60 s; hub reads as prep+growth, not friction.
|
||
|
||
## Phase 3 — Depth (folded in now; design-review per netcode-heavy slice)
|
||
|
||
- **Kit:** second ability slot + one new active per class (reuse AbilityRef catalog + predicted-input review).
|
||
- ~~Boons~~ **MOVED to Phase 1.7** (pulled forward 2026-07-07 — operator playtest called flat-stat upgrades boring).
|
||
- **Real node types:** Elite (affixed alphas via the boss spawn-stamp pattern), Shrine (combat-free choice), Survive,
|
||
Cursed.
|
||
- **Second boss chassis** (Spitter artillery) so lap 2 differs.
|
||
- **Co-op:** downed/revive (ex-MC-5), duo boons, party-scaled spawns/HP; death-cost design lands here (with revive in,
|
||
death = run stakes, killing the suicide-heal exploit).
|
||
|
||
**Gate:** two consecutive runs feel different (build + path + boss); a duo playtest yields a clutch-revive moment.
|
||
|
||
## Phase 4 — Blender workstream (parallel from Phase 1; hero props + decals)
|
||
|
||
Portal gate ring · hub Core crystal centerpiece · boss bone-socket armor/spike kitbash (no new rig) + second-boss
|
||
silhouette parts · distinct projectile/pickup/harvest meshes · class weapons · ground decal/telegraph quad set.
|
||
Pipeline (validated + researched): UV new geometry onto the existing Synty atlas for style match (or Imphenzia palette
|
||
PNG); FBX for anything skinned (glTFast Mecanim-clip issues), glb via gltfast for statics; Apply Scalings = FBX Units
|
||
Scale; Key All Bones for clips; realize geo-nodes instances before export; Play-verify materials (dark-frame hazard).
|
||
|
||
## Phase 5 — Dev tooling (woven through)
|
||
|
||
New DebugOps: KillRoom (death-path kill — ClearEnemies destroys without kill credit), SkipToRoom/SpawnBoss, GrantBoon,
|
||
run-state line in the overlay · pause-proof screenshot rig (MCP bridge `ScreenshotUtility` calls `EditorApplication.Step()`
|
||
and leaves the editor PAUSED — unpause after every capture; never `Thread.Sleep`-poll in `execute_code`, it freezes the
|
||
sim) · encounter-composition buttons in DevSandbox · WasAllReady regression test.
|
||
|
||
## Consolidation notes
|
||
|
||
Supersedes the DR-042 "final beat = base siege" lock (win moves fully expedition-side). DR-034 Core / EB-1/2 siege
|
||
systems → mothballed, not deleted. The "present forks" ritual re-runs at each phase's design review.
|
||
|
||
**2026-07-07 restructure (Phase 1 gate playtest):** Phase 0 + Phase 1 SHIPPED (commits `7c1fee097`…`cc2e7ad95`, incl.
|
||
Blender clips, sword combo, pixel-art render style, enemy-stuck fix, markers, harvest feedback). Gate playtest verdict
|
||
= static/boring world → **Phase 1.5 World Alive** inserted (stabilize: node-feedback fix + collision precision; short:
|
||
lighting→art-look gate, ambient motion, breakables, attack distinctness; long: hazards + destructible cover, review-first)
|
||
and **boons pulled forward to Phase 1.7**. Phase 2 (hub) now follows 1.7. Order: 1.5 → 1.7 → 2 → 3 → 4/5 parallel.
|