# Hit reactions (combat.hit_reactions) ## What it is for `combat.hit_reactions` decides what a body does after it is hit: stunned, launched into the air, knocked down, then landing, lying down, getting up and a short protection window. It is a clock and a set of rules, one instance per actor. It owns no health, gravity, collision world or animation: the game says whether the body is grounded, applies the returned velocity exactly once, and plays the clips. It is a driver you step yourself, with no hidden tick. Use it after `combat.defense` ([guide](guide:combat-defense)) has decided that a hit lands, with `combat.moveset` ([guide](guide:combat-moveset)) for the attacker and `combat.grabs` ([guide](guide:combat-grabs)) for throws. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "combat.hit_reactions" } gripforge_gamekit_configure { project_id: "gkp_…", id: "combat.hit_reactions", config: { "downFrames": 24, "getupFrames": 18, "getupInvulnerabilityFrames": 18 } } ``` Durations are whole fixed simulation frames (normally 60 Hz); call `step` once per frame with the `grounded` flag from your collision code. ## First example With `downFrames: 3`, `getupFrames: 2` and `getupInvulnerabilityFrames: 4`, a knockdown goes to phase `downed`; after three grounded steps `getup_started` fires and the body is protected (`canBeHit` is false). A hit during the protection answers `accepted: false` with an `ignored` event (reason `invulnerable`); two more steps give `recovered` and the phase is `ready` again. ```json { "service": "combat.hit_reactions", "method": "request", "args": ["default", { "op": "hit", "sequence": 1, "kind": "knockdown", "grounded": true }] } { "service": "combat.hit_reactions", "method": "request", "args": ["default", { "op": "step", "grounded": true }] } ``` ## Settings and defaults Fixed at creation; unknown keys are refused. | Setting | Default | Meaning | |---|---|---| | `downFrames` | `24` | Frames spent on the ground before getting up (1 to 600). | | `getupFrames` | `18` | Frames of getting up before control returns (1 to 600). | | `getupInvulnerabilityFrames` | `18` | Protected frames counted from the start of getting up (0 to 600). | | `maxAirFrames` | `600` | Airborne steps allowed since the last accepted hit or transition (1 to 600). | | `recoveries` | none | Up to 16 getup choices `{ id, frames, invulnerabilityFrames, velocity }` (a roll, a quick rise). | ## Services Service `combat.hit_reactions` (up to 128 named instances): `create(id, config)`, `remove(id)`, `ids()` and `request(id, command)` with the commands: - `hit { sequence, kind, grounded, stunFrames?, velocity? }`: `kind` is `stun`, `launch` or `knockdown`; `sequence` is an integer strictly above the last impact of that actor; a `launch` needs `velocity` (world metres per second, Y up). Answers `accepted` and the events. - `step { grounded, frozen? }`: advances the clocks; `grounded` is required. A frozen step changes nothing. - `land { sequence }`: the engine tells that the body landed during the current accepted reaction. - `recovery { sequence, id }`: picks one of the `recoveries` while down. - `invulnerability { frames }`: extends the protection (never shortens it). - `interrupt`, `reset`, `status`, `config`, `save`, `load { save }`, `preview { command }`. Answers hold `state`, `canAct` (the phase is `ready`), `canBeHit` and `events`. Script verbs: a request verb and an exists condition named after the kit id with dots turned into underscores (`_request`, `_exists`). ## Events - In the answer of a request: `reaction { sequence, kind, phase, velocity }` (apply the velocity once), `ignored`, `airborne`, `landed`, `getup_started` (with `recovery` and `velocity` when a choice was made), `recovered`, `air_timeout`, `interrupted`. - Bus events, named `.`: `.created`, `.removed`, `.changed` (a decided command applied) and `.refused` (a tap cancelled it). ## Hooks and modding | Hook | Effect | |---|---| | `combat.hit_reactions.create` | Before an instance is created; may change its `config` or cancel. | | `combat.hit_reactions.request` | Before a decided command; may change the `command` or cancel. | `create(id, { preset })` reads the presets collection of the kit (its id with dots turned into underscores, then `_presets`). ## Engines The same Rust core runs on the web, the native player and as a C library and WebAssembly module for the engine wrappers. The engine provides `grounded`, applies velocities and plays the animation. ## When it does not do what you expect - A launch is refused: it needs a `velocity`. - A hit answers `accepted: false`: the body is protected (`invulnerable`) or the sequence is stale; the sequence is still consumed. - A launched body never lands: send `grounded: false` first, then `grounded: true`, or use `land`; otherwise `air_timeout` ends it after `maxAirFrames`. ## Limits No health, gravity, ragdoll, root motion or clips. It does not decide whether a body is alive: gate new actions yourself. ## Versions Kit 1.2.0 (modding contract), 1.1.0 (`recoveries`). Save format `gripforge.motion/1`.