Files
Project-M/Docs/Vault/06_Roadmap/Iteration_2026-07_CoopHades.md
T

200 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 36 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 (the pre-flagged PostTransformMatrix-on-root risk is real).
> → **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:** the shrink/pop drives `PostTransformMatrix` on the ghost ROOT, but node meshes are
render (LEG) children → scale the render children instead (the 07-07 session log pre-flagged exactly this).
**Verify ON-SCREEN this time** — the operator's eyes are the test for skinned/scaled visuals.
2. **Collision precision pass:** operator reports collisions imprecise/not working well. Diagnose scope FIRST
(environment collision vs body-blocking vs melee/projectile hit registration — each is a different system) with a
live repro session, then fix. Swept-not-point rules apply to anything hit-reg.
### Short-term wins (asset/scene/client layer)
3. **Lighting/atmosphere pass (direction-agnostic):** ambient way down, dynamic point lights on projectiles / portal /
pickups / braziers / ability impacts, per-biome fog + color-grade tune. Build AS IF no pixel filter (it composes on
top). Then the **art-look decision gate**: side-by-side screenshots pixel filter ON vs OFF over the lit scene →
operator locks pixel-art-3D vs dark-Synty vs both. Every later visual choice hangs off this lock.
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:** Hades-style urns/crates/Blight growths seeded per room; shatter on hit → small
resource drops. Reuses the destructible-ghost + `BlightClutter` + pickup patterns — netcode-cheap.
6. **Attack distinctness:** every enemy kind + class ability gets a unique read — anim + VFX + effect shape (not more
hit-stop). Builds on the shipped Blender clip pipeline + sword-combo work; creature locomotion for monsters still
open from Phase 1.3.
### Long-term (server-sim; adversarial design-review REQUIRED per slice)
7. **Environmental hazards:** exploding barrels, Blight geysers, trap tiles — damage BOTH sides so enemies can be
baited into them. Real combat interplay; replication + predicted-damage surface needs the review.
8. **Destructible cover:** in-room cover rocks take damage and crumble (Charger smashes through, players carve LOS).
Structures already have Health; **re-validate the enemy stuck-fix backstop when cover can disappear mid-fight.**
**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.