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

87 lines
4.9 KiB
Markdown
Raw 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).
## Archetype reference
| Archetype | Instance id | Marker | maxHp | Pulses to defeat | NPC damage | Windup | Cooldown |
|-----------|-------------|--------|-------|------------------|------------|--------|----------|
| Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 100 | **4** | 15 | 1.5 s | 3.0 s |
| Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 80 | **4** | 12 | 2.0 s | 4.0 s |
| Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 200 | **8** | 25 | 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 **`100/100`**.
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): **`PlayerCombatHpLabel`** drops to **`85/100`** (melee **15** damage).
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. Cast without lock still shows **`ability_cast_denied: invalid_target`** on **`CastFeedbackLabel`** (NEO-28).
20. **`CombatTargetHpLabel`** + cooldown HUD still refresh after accepted casts (NEO-85 / NEO-32).
## 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 120 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).