Duel

A two-fighter arcade fight on one line: frame-timed attacks, guard, jumps, energy special, combos, rounds, reactive AI, local versus or solo.

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

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

Arcade duel, 2.5D (combat.duel) #

What it is for #

combat.duel is a complete versus-fighting game mode. Two fighters stand on a line; the kit simulates frame-timed attacks, high and low guard, jumps, projectiles, an energy special, three combos per fighter with their own clock, hit stop, rounds and a reactive opponent. It reads the duel.* and duel.p2.* input actions, mirrors the fighters as entities, publishes the round on variables, follows the arena scenes of game.engine and saves the whole match. The presenter draws it in 2.5D. It is the mode, not a building block for other kits: for the guard, parry and move logic as separate cores see the defense and moveset guides. Damage rules of the wider family are in the combat guide.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "combat.duel" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "combat.duel",
                              config: { "roundSeconds": 60, "winsRequired": 2, "difficulty": 0.55 } }

It requires input.actions and game.engine, and cannot be installed with a character kit (character.third_person, character.top_down, character.platformer), fps.tactical or race.kart. Assets to provide: fighter_a, fighter_b (rigged characters with idle, walk, guard, crouch, jump, punch, kick, projectile, super, hit, death, victory and combo1 to combo3 clips), duel_stage, and optional sounds and combo effects.

First example #

<!-- test: kits/game_engine/host/tests/combat_duel.rs::a_round_starts_and_a_punch_lands_in_local_versus --> Start a local versus match, wait for the intro (about 1.8 s), walk the first fighter up to the second and punch.

{ "op": "call", "service": "combat.duel", "method": "restart", "args": ["local"] }
{ "op": "step", "ticks": 110 }
{ "op": "key", "code": "KeyD", "down": true }
{ "op": "key", "code": "KeyJ", "down": true }
{ "op": "call", "service": "combat.duel", "method": "view", "args": [] }

The test sees duel.round, duel.attack and duel.hit events, duel.phase equal to fight, the second fighter at 92 health and the first fighter's energy meter at 12.

Settings and defaults #

SettingDefaultMeaning
roundSeconds60Length of a round (15 to 180).
winsRequired2Rounds to win the match (1 to 5).
moveSpeed3.5Walk speed in metres per second (1 to 7).
arenaWidth14Width of the fighting line in metres (8 to 20).
difficulty0.55Reactive AI strength (0 to 1), used in solo mode.
firstStyleboxerStyle of the first fighter: boxer or acrobat.
secondStyleacrobatStyle of the second fighter.
comboColorsper style#rrggbb colors combo1, combo2, combo3 for each style; an invalid color keeps the default.

All are moddable. A scene whose world is { kit: "combat.duel", config? } is an arena: its config overrides the options for that scene, and first and second entries place the fighters. Entering the scene starts a new match; loading a save keeps the current one.

Services, events, variables #

  • Service combat.duel: restart(mode?) starts again in ai (solo, default) or local (two players); view() returns the phase, clocks, mode, fighters (health, energy meter, style, combos) and shots; tactical(command) drives the resolution mode.
  • Events duel.attack, duel.hit, duel.block, duel.shot, duel.round, duel.ko: payload { type, x, y, actor, move?, damage?, strike?, limb?, finisher? }, actor being 0, 1 or -1. duel.resolution carries the result of the tactical mode.
  • Variables duel.phase (intro, fight, round_end, finished), duel.round, duel.remaining.
  • Actions: player one duel.move (axis), duel.jump, duel.crouch, duel.guard, duel.punch, duel.kick, duel.projectile, duel.super, combo actions numbered 1 to 3; player two has the same set under duel.p2move and the prefix duel.p2. (jump, crouch, guard, punch, kick, projectile, super and combos 1 to 3).

Hooks and modding #

HookMutableEffect
duel.attackcostA fighter is about to start a buffered move; cancel or too little energy: it does not start (the input stays buffered for 0.14 s).
duel.guardblockedA strike reached a fighter; decide whether the guard holds.
duel.hitdamageA strike is about to land after the guard; cancel: nothing lands.
duel.end_roundwinnerA round is over (timeout says why); give it to either fighter or call a draw with -1.

Engines #

Web and the native player run the Rust simulation. Godot, Unity and Unreal receive the gameplay as files and keep the simulation of kit version 1.2 until the hooks are ported to them.

When it does not do what you expect #

  • Nothing happens after restart: wait for the intro to finish (duel.phase is fight).
  • The kit refuses to install: a character, tactical shooter or kart kit is already installed (they conflict).
  • The second fighter ignores the second player keys: in the default ai mode it is the AI; use restart("local") for two players.

Limits #

Two fighters, one line, one arena. The arcade moves are the kit's own: it does not read arbitrary movesets from combat.moveset.

Versions #

Kit 1.5.0 (optional Rust tactical adapter: simultaneous decisions and bounded prediction, live duel hooks refused in that mode). Requires input.actions 1 and game.engine 1.