feat: close the combat loop — creatures retaliate, players die & resurrect (#10) #28

Merged
marco merged 2 commits from feat/combat-loop into main 2026-07-17 15:50:07 +02:00
Owner

Closes #10.

Summary

The combat loop is now two-sided: the rat fights back, and you can die.

  • Retaliation (aggro v1): a struck creature targets its attacker, chases within a leash range, and swings when adjacent — giving up (back to wandering) if the target dies, turns ghost, or leaves the leash. No proactive aggro-on-sight yet (chosen for a calm, deterministic v1).
  • AI seam grew from "propose a move" (Direction?) to "propose an action" (Move/Attack/Idle) with a narrow AiPerception; World drives creatures under its lock, starting creature swings through CombatSystem.
  • CombatSystem generalised player→creature ⇒ Mobile→Mobile. A lethal hit removes+respawns a creature, or turns a player into a ghost that auto-resurrects at the spawn with full HP after a delay (ResurrectDelayTicks, ~5s). A ghost walks but cannot attack or be attacked.
  • Rat is dangerous but fair: low damage (4) on a slow swing (12 ticks) — it can kill a careless or swarmed player, but never wins a straight 1-on-1 (you drop it in ~2–4 hits).
  • HP stays server-only. Two new AoI-scoped messages, PlayerDied / PlayerResurrected, carry no HP — just the ghost transition and the resurrect position.
  • Client: players gained the same Tint channel (translucent grey ghost); Swing/Attacked now work both directions (a rat hitting you shows a damage number over your player + the rat faces you); a ghost can neither engage nor auto-attack.

Death model

You chose the ghost/delay path: on death you become a grey ghost, still able to walk, then auto-resurrect at the spawn after the delay. Manual resurrection (ankh/healer) is a future refinement.

How it was tested

WorldTests: a creature retaliates and damages its attacker; a player killed by a creature becomes a ghost (cannot swing even at an adjacent living target) and resurrects at the spawn with combat restored. Protocol round-trips for PlayerDied/PlayerResurrected. Existing wander/combat/equip/persistence tests unchanged. 184 tests green, zero warnings, CSharpier clean.

Needs your eyes (GUI)

Please confirm in-game: hit a rat → it chases and hits back (damage numbers over your player); stand in it long enough (or pull two) → you die, go grey ghost, and pop back at spawn after ~5s. Tell me if the rat's lethality (4 dmg / slow swing) and the ~5s ghost delay feel right — both are one-line tunables.

Checklist

  • just lint clean · [x] just test green (184) · [x] whole solution builds, 0 warnings · [x] multi-platform preserved · [x] tests added
Closes #10. ## Summary The combat loop is now two-sided: the rat fights back, and you can die. - **Retaliation (aggro v1):** a struck creature targets its attacker, chases within a **leash range**, and swings when adjacent — giving up (back to wandering) if the target dies, turns ghost, or leaves the leash. No proactive aggro-on-sight yet (chosen for a calm, deterministic v1). - **AI seam grew** from "propose a move" (`Direction?`) to "propose an action" (`Move`/`Attack`/`Idle`) with a narrow `AiPerception`; **World drives creatures under its lock**, starting creature swings through `CombatSystem`. - **CombatSystem generalised** player→creature ⇒ **Mobile→Mobile**. A lethal hit removes+respawns a creature, or turns a **player into a ghost** that auto-resurrects at the spawn with full HP after a delay (`ResurrectDelayTicks`, ~5s). A **ghost walks but cannot attack or be attacked**. - **Rat is dangerous but fair:** low damage (4) on a slow swing (12 ticks) — it can kill a careless or swarmed player, but never wins a straight 1-on-1 (you drop it in ~2–4 hits). - **HP stays server-only.** Two new **AoI-scoped** messages, `PlayerDied` / `PlayerResurrected`, carry **no HP** — just the ghost transition and the resurrect position. - **Client:** players gained the same `Tint` channel (translucent **grey ghost**); `Swing`/`Attacked` now work **both directions** (a rat hitting you shows a damage number over your player + the rat faces you); a ghost can neither engage nor auto-attack. ## Death model You chose the **ghost/delay** path: on death you become a grey ghost, still able to walk, then **auto-resurrect at the spawn** after the delay. Manual resurrection (ankh/healer) is a future refinement. ## How it was tested `WorldTests`: a creature **retaliates and damages its attacker**; a player **killed by a creature becomes a ghost** (cannot swing even at an adjacent living target) and **resurrects at the spawn** with combat restored. Protocol round-trips for `PlayerDied`/`PlayerResurrected`. Existing wander/combat/equip/persistence tests unchanged. **184 tests green**, zero warnings, CSharpier clean. ## Needs your eyes (GUI) Please confirm in-game: hit a rat → it chases and hits back (damage numbers over your player); stand in it long enough (or pull two) → you die, go **grey ghost**, and pop back at spawn after ~5s. Tell me if the rat's lethality (4 dmg / slow swing) and the ~5s ghost delay feel right — both are one-line tunables. ## Checklist - [x] `just lint` clean · [x] `just test` green (184) · [x] whole solution builds, 0 warnings · [x] multi-platform preserved · [x] tests added
feat(combat): creatures fight back, players die and resurrect
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m29s
b4a5f0ee5d
Closes the combat loop (issue #10). Creatures now retaliate: a struck creature
acquires its attacker as CombatTarget, chases within a leash range, and swings
when adjacent, giving up (back to wandering) if the target dies, turns ghost, or
leaves the leash. The AI seam grows from "propose a move" to "propose an action"
(Move/Attack/Idle) with a narrow AiPerception, and World drives it under its lock.

CombatSystem is generalised from player→creature to Mobile→Mobile: a lethal hit
removes+respawns a creature or turns a player into a ghost, scheduled to
auto-resurrect at the spawn with full HP after a delay. A ghost walks the world
but cannot attack or be attacked. HP stays server-only; two new AoI-scoped
messages (PlayerDied/PlayerResurrected) carry no HP. Rat given low retaliation
damage on a slow swing — it can kill a careless or swarmed player, never win a
straight duel.

Client: players gain a Tint channel (grey ghost look), Swing/Attacked are handled
in both directions (creature→player too), damage numbers float over players as
well as creatures, and a ghost can neither engage nor auto-attack.
test: widen integration WebSocket receive timeout for slow CI runners
All checks were successful
ci / Lint & Test (pull_request) Successful in 2m7s
149cc82c68
The 5s per-receive timeout was too tight for a cold, shared CI runner (app
startup + JIT + the 100ms tick loop), causing a flaky OperationCanceledException
in the WebSocket integration tests while an expected broadcast was merely late,
not missing. Widen to 20s — the happy path still returns as soon as the message
arrives, so this only affects how long a genuine failure waits.
marco merged commit 7437687411 into main 2026-07-17 15:50:07 +02:00
marco deleted branch feat/combat-loop 2026-07-17 15:50:08 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marco/IsoMmo!28
No description provided.