neon-sprawl/docs/manual-qa/NEO-98.md

89 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# NEO-98 — Manual QA checklist
| Field | Value |
|-------|-------|
| Key | NEO-98 |
| Title | E5M2-12: Playable NPC telegraph combat capstone (Godot) |
| Linear | https://linear.app/neon-sprawl/issue/NEO-98/e5m2-12-playable-npc-telegraph-combat-capstone-godot |
| Plan | `docs/plans/NEO-98-implementation-plan.md` |
| Branch | `NEO-98-e5m2-12-playable-npc-telegraph-combat-capstone` |
## Preconditions
- **Fresh dev player:** stop any running server, then start a new instance so in-memory **`dev-local-1`** NPC HP, aggro/runtime rows, and player combat HP reset.
- **No Bruno/curl seeding** for this checklist — hotbar **`prototype_pulse`** bind is automatic (NEO-85 dev bootstrap).
- NEO-97 telegraph HUD landed on `main` (PR #136).
- **`CombatTargetHpLabel`** uses NEO-85 format **`Target HP: {id} {current}/{max}`** (e.g. **`Target HP: prototype_npc_melee 100/100`**) — match HP substring or full line.
## Archetype reference
| Archetype | Instance id | Marker | maxHp | Pulses to defeat | NPC damage | Strike range | Windup | Cooldown |
|-----------|-------------|--------|-------|------------------|------------|--------------|--------|----------|
| Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 100 | **4** | 15 | **2 m** (close) | 1.5 s | 3.0 s |
| Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 80 | **4** | 12 | 10 m | 2.0 s | 4.0 s |
| Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 200 | **8** | 25 | **4 m** | 2.5 s | 5.0 s |
Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
## Melee defeat math
| Cast # | Expected `CastFeedbackLabel` | `CombatTargetHpLabel` |
|--------|------------------------------|------------------------|
| 1 | `Cast: 25 dmg → 75 HP` | `75/100` |
| 2 | `Cast: 25 dmg → 50 HP` | `50/100` |
| 3 | `Cast: 25 dmg → 25 HP` | `25/100` |
| 4 | `Cast: 25 dmg → 0 HP — defeated!` | `0/100 (defeated)` |
| 5 | `ability_cast_denied: target_defeated` | unchanged defeated |
## Checklist
### Boot
1. Start server: `cd server/NeonSprawl.Server && dotnet run`.
2. Run Godot main scene (**F5**). Confirm slot **0** auto-binds **`prototype_pulse`** after hotbar sync.
### Melee — full telegraph + player HP spine
3. Walk to orange **Melee** marker west of spawn **`(-3, -3)`**.
4. Press **Tab** until **`prototype_npc_melee`** is locked with **`Validity: ok`** — marker **brightens**; **`CombatTargetHpLabel`** shows **`Target HP: prototype_npc_melee 100/100`** (or **`…`** briefly until GET completes).
5. Press **1** (damaging cast): **`CastFeedbackLabel`** shows damage; **`NpcStateLabel`** eventually shows **`NPC state: Melee → aggro`** (~1 Hz poll).
6. **`PlayerCombatHpLabel`** shows **`Player HP: 100/100`** once combat poll starts.
7. Wait **≥ 3 s** from first cast: **`NpcStateLabel`** shows **`telegraph_windup`**; **`TelegraphLabel`** shows countdown (e.g. **`Telegraph: Melee … · ~1.x s (melee)`**) ticking between polls.
8. Wait **≥ 4.5 s** total from first cast (windup completes): stay **within ~2 m** of the melee marker (close combat — tab-lock is 6 m but strike range is **2 m**). **`PlayerCombatHpLabel`** drops to **`85/100`** (melee **15** damage). Back off during windup → telegraph may finish but **no** player damage (whiff).
9. Press **1** three more times (respect ~3 s cooldown) until **`CombatTargetHpLabel`** shows **`0/100 (defeated)`** per defeat table above.
10. Press **1** again: **`ability_cast_denied: target_defeated`**.
### Ranged — defeat + telegraph visible
11. Walk to purple **Ranged** marker south-east **`(3, 3)`**; **Tab** lock **`prototype_npc_ranged`**.
12. Press **1** (first damaging cast) → **`NpcStateLabel`** shows **`aggro`**.
13. Wait **≥ 4 s** from first cast: **`telegraph_windup`** + readable **`TelegraphLabel`** (2.0 s windup after 4.0 s cooldown).
14. Press **1** until defeated (**4** pulses total); verify **`0/80 (defeated)`** on **`CombatTargetHpLabel`** and deny on re-cast.
### Elite — defeat + telegraph visible
15. Walk to gold **Elite** marker at origin **`(0, 0)`**; **Tab** lock **`prototype_npc_elite`**.
16. Press **1** (first damaging cast) → **`NpcStateLabel`** shows **`aggro`**.
17. Wait **≥ 5 s** from first cast: **`telegraph_windup`** + readable **`TelegraphLabel`** (2.5 s windup after 5.0 s cooldown).
18. Press **1** until defeated (**8** pulses total); verify **`0/200 (defeated)`** on **`CombatTargetHpLabel`** and deny on re-cast.
### Regression
19. Press **Esc** to clear lock: **`CombatTargetHpLabel`** shows **`Target HP: — (Tab → elite/melee/ranged near spawn)`** (or equivalent no-lock line).
20. Cast without lock: **`CastFeedbackLabel`** shows **`ability_cast_denied: invalid_target`** (NEO-28).
21. **`CombatTargetHpLabel`** + cooldown HUD still refresh after accepted casts (NEO-85 / NEO-32) — re-lock any NPC and press **1** once to confirm.
## Notes
- Capstone baseline prefers **server restart** over mid-session fixture POST.
- Optional reset (Development host): `POST /game/__dev/combat-targets-fixture` — see [NEO-97 manual QA](NEO-97.md) / [server README — dev fixture](../../server/README.md#dev-combat-target-fixture-brunomanual-qa).
- Component-level telegraph HUD regression (elite incoming-threat row): [NEO-97 manual QA](NEO-97.md).
- Slice 1 combat capstone (gig XP): [NEO-86 manual QA](NEO-86.md).
## Acceptance
- [ ] Steps 121 completable in one session without Bruno/curl.
- [ ] Melee telegraph countdown readable **before** player HP drops to **85/100** (steps 78).
- [ ] All three archetypes show **`defeated`** in **`CombatTargetHpLabel`** (steps 9, 14, 18).
- [ ] Aggro on first damaging cast feels deterministic (no silent failures).