# 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](guide:combat-defense) and [moveset](guide:combat-moveset) guides. Damage rules of the wider family are in the [combat guide](guide:combat). ## Turn it on ```text 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 Start a local versus match, wait for the intro (about 1.8 s), walk the first fighter up to the second and punch. ```json { "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 | Setting | Default | Meaning | |---|---|---| | `roundSeconds` | `60` | Length of a round (15 to 180). | | `winsRequired` | `2` | Rounds to win the match (1 to 5). | | `moveSpeed` | `3.5` | Walk speed in metres per second (1 to 7). | | `arenaWidth` | `14` | Width of the fighting line in metres (8 to 20). | | `difficulty` | `0.55` | Reactive AI strength (0 to 1), used in solo mode. | | `firstStyle` | `boxer` | Style of the first fighter: `boxer` or `acrobat`. | | `secondStyle` | `acrobat` | Style of the second fighter. | | `comboColors` | per 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 | Hook | Mutable | Effect | |---|---|---| | `duel.attack` | `cost` | A 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.guard` | `blocked` | A strike reached a fighter; decide whether the guard holds. | | `duel.hit` | `damage` | A strike is about to land after the guard; cancel: nothing lands. | | `duel.end_round` | `winner` | A 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.