From 03d04f0a33c2f33bd0b9c6a250c41aa60332a9a8 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Mon, 16 Feb 2026 14:48:39 -0500 Subject: [PATCH] Update combat docs to match 3-state machine and correct field names --- docs/how/combat.rst | 49 ++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/docs/how/combat.rst b/docs/how/combat.rst index b188c60..c645c66 100644 --- a/docs/how/combat.rst +++ b/docs/how/combat.rst @@ -50,29 +50,21 @@ the state machine :: - IDLE → TELEGRAPH → WINDOW → RESOLVE → IDLE + IDLE → PENDING → RESOLVE → IDLE IDLE: no active move. attacker can initiate attack. defender can do nothing combat-specific. -TELEGRAPH: - attacker has declared a move. defender sees the telegraph message. - "goku winds up a right hook!" - defender can queue a defense during this phase. - duration: brief (implementation decides, not move-defined). - -WINDOW: - the timing window opens. defender can still queue defense. - if defender queued correct counter during TELEGRAPH or WINDOW, they succeed. - duration: move.timing_window_ms (defined in TOML). +PENDING: + attacker has declared a move. telegraph message sent to defender. + the move is now in flight — defender can queue a defense any time + during this phase. duration is the attack's hit_time_ms. RESOLVE: - timing window closes. check if defense counters attack. - calculate damage based on attacker PL, damage_pct, and defense success. - apply stamina costs. - check for knockouts (PL = 0) or exhaustion (stamina = 0). - return to IDLE. + hit_time_ms elapsed. check if defender's active defense counters the + attack. calculate damage, apply stamina costs, check for knockouts + or exhaustion. return to IDLE. entity stats @@ -205,7 +197,7 @@ moves live in content/combat/. two formats: simple and variant. move_type = "attack" stamina_cost = 8.0 telegraph = "{attacker} spins into a roundhouse kick!" - timing_window_ms = 600 + hit_time_ms = 600 damage_pct = 0.25 countered_by = ["duck", "parry high", "parry low"] @@ -215,7 +207,7 @@ moves live in content/combat/. two formats: simple and variant. name = "punch" move_type = "attack" stamina_cost = 5.0 - timing_window_ms = 800 + hit_time_ms = 800 damage_pct = 0.15 [variants.left] @@ -228,7 +220,7 @@ moves live in content/combat/. two formats: simple and variant. telegraph = "{attacker} winds up a right hook!" countered_by = ["dodge left", "parry high"] -shared properties (stamina_cost, timing_window_ms, damage_pct) are defined at +shared properties (stamina_cost, hit_time_ms, damage_pct) are defined at the top level. variants inherit these and can override them. variant-specific properties (telegraph, countered_by, aliases) live under [variants.]. @@ -236,13 +228,28 @@ each variant produces a CombatMove with a qualified name like "punch left". the ``command`` field tracks the base command ("punch") and ``variant`` tracks the key ("left"). simple moves have command=name and variant="". +**defense move** (directional):: + + # content/combat/dodge.toml + name = "dodge" + move_type = "defense" + stamina_cost = 3.0 + active_ms = 800 + recovery_ms = 2700 + + [variants.left] + + [variants.right] + TOML field reference: - name: the command name (simple) or base command (variant) - move_type: "attack" or "defense" - stamina_cost: stamina consumed when using this move -- timing_window_ms: how long defender has to respond -- telegraph: shown to defender during TELEGRAPH phase. {attacker} replaced +- hit_time_ms: (attacks) time in ms from initiation to impact +- active_ms: (defenses) how long defense blocks once activated, in ms +- recovery_ms: (defenses) lockout after active window ends, in ms +- telegraph: shown to defender during PENDING phase. {attacker} replaced - damage_pct: fraction of attacker's PL dealt as damage - countered_by: list of qualified move names that counter this move - aliases: short command aliases registered as standalone commands