89 lines
5.6 KiB
Markdown
89 lines
5.6 KiB
Markdown
# 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 1–21 completable in one session without Bruno/curl.
|
||
- [ ] Melee telegraph countdown readable **before** player HP drops to **85/100** (steps 7–8).
|
||
- [ ] All three archetypes show **`defeated`** in **`CombatTargetHpLabel`** (steps 9, 14, 18).
|
||
- [ ] Aggro on first damaging cast feels deterministic (no silent failures).
|