Moveset

Move definitions with frame clocks, a bounded input buffer, directional motion commands and hit or block confirmed cancels for fighting games.

Source: module-kits:kits/combat_moveset/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs combat-movesetMCP tool: gripforge_docs { "topic": "combat-moveset" }

Move clocks and input buffer (combat.moveset) #

What it is for #

combat.moveset runs the timing of a fighter's attacks: which move starts, how long it is in startup, active and recovery, which buttons and directions start it (a quarter circle is [2,3,6]), how long an early press stays buffered and which cancels open on a hit or a block. One instance per actor. It owns no collision, damage, root motion or animation: the game applies the contacts, spends the resource and plays the clip when a move started event arrives. It is a driver you step yourself, with no hidden tick. It works with combat.defense (guide), whose outcomes feed the cancel confirmations, and shares its scheduler with combat.duel (guide).

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "combat.moveset" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "combat.moveset",
                              config: { "bufferFrames": 8, "moves": [ … ] } }

Without moves the kit has the three default moves below. Call step once per fixed simulation frame (normally 60 Hz); times are whole frames.

First example #

<!-- test: kits/game_engine/host/tests/combat_moveset.rs::confirmation_and_save_replay_on_host --> Queue jab, step five times (the jab is then active), confirm that it hit, queue heavy: the jab cancels into the heavy on hit. The test also saves and loads the instance and gets the same result.

{ "op": "queue", "move": "jab" }
{ "op": "step" }
{ "op": "confirm", "sequence": 1, "result": "hit" }
{ "op": "queue", "move": "heavy" }
{ "op": "step", "resource": 100 }

Each line is the command of request("default", command); the single step stands for the five steps of the test. After the last step the answer has state.active.move equal to heavy.

Settings and defaults #

Fixed at creation; unknown keys are refused.

SettingDefaultMeaning
movesjab, heavy, shot1 to 64 move definitions (see below).
bufferFrames8How long an early press waits (1 to 60).
historyFrames30Direction history kept for motion commands (1 to 60).

A move needs id, button, startup (0 to 600), active (1 to 600) and recovery (0 to 600). Optional: cost (default 0), ground (any, ground or air), directions (numpad directions, [] for a plain button), maxGapFrames (12), priority (0 to 1000: highest wins, then the longest motion, then the smallest id) and up to 32 cancels { to, from, until, on } with on being always, hit or block. The defaults are jab (4/3/10, cancels into heavy on hit), heavy (9/4/18, cost 10) and shot (a quarter circle, 10/1/20, cost 20, on the ground).

Services #

Service combat.moveset (up to 128 named instances): create(id, config), remove(id), ids() and request(id, command) with the commands:

  • step { direction?, facing?, buttons?, grounded?, resource?, enabled?, frozen? }: direction is a numpad value 1 to 9 in world space (5 neutral), facing is 1 or -1, buttons are press edges (up to 16), resource is the balance the game holds. enabled: false blocks starts and cancels; frozen: true stops the clocks (hit stop).
  • queue { move }: buffers a known move by hand (for AI); grounds, cost and cancels still apply.
  • confirm { sequence, result }: hit or block for the current attack, after it started.
  • interrupt, reset, status, config, save, load { save }, preview { command }.

Answers hold state, phase and events. Script verbs: a request verb and an exists condition named after the kit id with dots turned into underscores (<kit>_request, <kit>_exists).

Events #

  • In the answer of a request: started { move, sequence, cost } (spend the cost once), active, ended, cancelled.
  • Bus events, named <kit id>.<suffix>: .created, .removed, .changed (a decided command applied) and .refused (a tap cancelled it).

Hooks and modding #

HookEffect
combat.moveset.createBefore an instance is created; may change its config or cancel.
combat.moveset.requestBefore 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 game checks hitboxes during the whole active phase and keeps its own table of already hit targets per attack sequence.

When it does not do what you expect #

  • A command does not start: check ground, cost against the resource you send, enabled and the buffer.
  • A cancel never opens: the window [from, until) is in frames of the current move and on must match the confirmation.
  • confirm is refused: the sequence is stale or the attack has not started yet.

Limits #

No collision, damage, animation or resources: the game owns them. The duel kit does not yet read arbitrary movesets from this kit.

Versions #

Kit 1.1.0 (modding contract). Save format gripforge.moveset/1.