# NEO-97 — Manual QA checklist | Field | Value | |-------|-------| | Key | NEO-97 | | Title | E5M2-11: Client telegraph HUD + NPC archetype markers | | Linear | https://linear.app/neon-sprawl/issue/NEO-97/e5m2-11-client-telegraph-hud-npc-archetype-markers | | Plan | `docs/plans/NEO-97-implementation-plan.md` | ## 1) Server - [ ] Start server: `cd server/NeonSprawl.Server && dotnet run`. - [ ] `curl -s http://localhost:5253/health` returns JSON with `status: ok`. - [ ] Optional reset between runs (Development host): `curl -sS -X POST http://localhost:5253/game/__dev/combat-targets-fixture -H 'Content-Type: application/json' -d '{"schemaVersion":1}'` returns **200** when the dev fixture route is enabled. ## 2) Client — NPC markers + tab cycle - [ ] Open Godot main scene with server running; after hotbar sync, slot **0** auto-binds to **`prototype_pulse`** when empty. - [ ] Three NPC markers near spawn: **Elite** (gold, origin), **Melee** (orange, west), **Ranged** (purple, south-east); each has a lock ring. - [ ] **Tab** cycles locks in order **`prototype_npc_elite`** → **`prototype_npc_melee`** → **`prototype_npc_ranged`** → wrap; locked marker **brightens**. - [ ] **`TargetLockLabel`** shows server-acknowledged lock id + validity (no optimistic lock). ## 3) Client — telegraph HUD + player HP - [ ] Walk to **Elite** marker (origin); **Tab** until **`prototype_npc_elite`** is locked with **`Validity: ok`**. - [ ] Press **1** (damaging cast): **`CastFeedbackLabel`** shows damage; **`NpcStateLabel`** eventually shows **`NPC state: Elite → aggro`** (after ~1 Hz poll). - [ ] **`PlayerCombatHpLabel`** shows **`Player HP: 100/100`** once combat poll starts (lock or aggro). - [ ] Wait **≥ 5 s** while staying in range (elite attack cooldown): **`NpcStateLabel`** shows **`telegraph_windup`**; **`TelegraphLabel`** shows countdown (e.g. **`Telegraph: Elite prototype_elite_slam · 2.x s (elite)`**) ticking down between polls. - [ ] Wait for windup to complete (**≥ 2.5 s** after telegraph appears, **≥ 7.5 s** total from first damaging cast): **`PlayerCombatHpLabel`** drops to **`75/100`** (elite **25** damage). - [ ] Telegraph countdown at poll boundaries matches server within one poll frame (~1 s); local tick-down is smooth between polls. ## 4) Incoming threat row - [ ] With elite aggro on you, **Tab** lock to **Melee** (different NPC): **`NpcStateLabel`** shows both **`NPC state: Melee → …`** and **`Incoming: Elite → …`** when elite still holds aggro. - [ ] **`TelegraphLabel`** prefers locked NPC telegraph; when locked NPC has no telegraph, shows incoming elite telegraph during windup. ## 5) Regression - [ ] **`CombatTargetHpLabel`** still updates on cast + lock change (NEO-85). - [ ] Cast without lock still shows **`ability_cast_denied: invalid_target`** (NEO-28). - [ ] Cooldown HUD still refreshes after accepted casts (NEO-32).