# The player's melee weapon in your game (weapons.loadout) ## What it is for `weapons.loadout` describes the weapon in the player's hands as data, in the `weapons` collection. Pressing `attack` plays the next step of the combo if the previous step ended less than `comboWindow` seconds ago, otherwise the first. `special` plays the special when its cooldown is 0. An attack during a dash, or within `dashAttackWindow` seconds after it, plays the weapon's dash attack. A press made while a strike is running is remembered for `buffer` seconds. Each step is a timed strike handed to `combat.melee`; the kit aims and lunges through `character.motor` when a kit serves it. Boons adjust range, speed and cooldowns through weapon modifiers. The bare hands are the built-in weapon `fists`. The kit has no display module. See also the [combat guide](guide:combat). ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "weapons.loadout" } gripforge_gamekit_configure { project_id: "gkp_…", id: "weapons.loadout", config: { "weapon": "sword", "buffer": 0.18, "aimSnap": true } } ``` It requires `input.actions`, `combat.melee` and `game.engine`, and registers the `attack` and `special` actions itself. With the `fists` weapon it also needs `character.control` and `combat.damage`. Without documents in `weapons`, the default weapon `ember_blade` is used. ## First example A sword with a three-step combo and a special with a cooldown: ```json { "id": "sword", "name": "Sword", "attack": { "comboWindow": 0.3, "combo": [ { "shape": "arc", "range": 2.0, "arc": 100, "damage": 10, "windup": 0.05, "active": 0.05, "recovery": 0.1 }, { "shape": "arc", "range": 2.5, "arc": 100, "damage": 12, "windup": 0.05, "active": 0.05, "recovery": 0.1 }, { "shape": "arc", "range": 3.0, "arc": 100, "damage": 20, "windup": 0.05, "active": 0.05, "recovery": 0.1 } ] }, "special": { "shape": "circle", "range": 3, "damage": 25, "windup": 0.1, "active": 0.1, "recovery": 0.1, "cooldown": 1.5 }, "dashAttack": { "shape": "line", "range": 4, "width": 1, "damage": 7 } } ``` With `weapon: "sword"`, `use("attack")` returns true and emits `weapon.used` with `step` 0; once the strike ended, an attack inside the 0.3 s window plays step 1, then 2, then the combo wraps to 0. `weapon.combo` follows the step. ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `weapon` | string | `ember_blade` | id of the equipped weapon (`fists` for the bare hands) | | `buffer` | number (s) | `0.18` | how long a press is remembered while the previous strike finishes | | `aimSnap` | boolean | `true` | turn toward the aim target before striking | | `aimSnapCone` | number (deg) | `120` | cone in which the aim snap looks for a target | | `dashAttackWindow` | number (s) | `0.25` | seconds after a dash during which `attack` plays the dash attack | | `weaponLayers` | object | `{}` | animation layer of the strikes, by weapon id | | `fists` | object | see below | the bare hands | A strike is `{ shape: arc | circle | line, range, arc?, width?, offset?, damage, windup, active, recovery, knockback?, lunge?, tags? }`. A weapon is `{ id, name, slot?, attack: { combo[], comboWindow }, special: Strike & { cooldown }, dashAttack? }`; the special cooldown is `special.cooldown` times the `cooldownMult` of the modifiers. A weapon without a combo or a special is left out. `fists`: `damage` 16, `range` 0.85, `arc` 65, `windup` 0.18, `active` 0.1, `recovery` 0.32, `comboWindow` 1.15 (left jab, then right cross), `inputBuffer` 0.18, `knockback` 0.24, `assaultHeat` 1, `showDamageNumbers` false. The fists have no special. ## Services, events, variables - `weapons.loadout` (service): `equipped()`, `weapons()`, `equip(id)` (resets combo and cooldown), `use("attack" | "special")` (false while busy, on cooldown, or when the player cannot act), `busy()`, `cooldown()`, `addModifier({ id, owner, on, rangeMult?, arcAdd?, speedMult?, cooldownMult? })` where `on` is `attack`, `special` or `all`, `removeModifier(id)`. - `combat.unarmed` (service): `punch(source?)`, `cancel(source?)`, `busy(source?)`, the fists for the player or a scripted actor. - Events: `weapon.used` (`entity`, `weapon`, `action`, `step`, `strike`), `weapon.equipped`, `combat.unarmed.started`. - Variables: `weapon.id`, `weapon.name`, `weapon.special.cooldown`, `weapon.combo` (-1 when idle). - Content: action `equip_weapon`, and the archetype component `loadout { weapon }` on the player. ## Hooks and modding | Hook | Payload | What a tap may do | |---|---|---| | `weapon.use` | `entity`, `weapon`, `action`, `step`, `damage`, `knockback`, `lunge`, `rangeMult`, `arcAdd`, `speedMult`, `cooldownMult` | change those values, or cancel the step | | `weapon.equip` | `weapon`, `from` | cancel: `equip` answers false | | `unarmed.punch` | `source`, `hand`, `damage`, `range`, `arc`, `windup`, `active`, `recovery`, `knockback` | change them, or cancel (no punch, combo stays) | The `weapons` registry lets a document `{ "id": "new", "extends": "sword" }` inherit and patch an entry. The settings and the collection are moddable. ## When it does not do what you expect - `use` answers false: a strike is under way (the key buffers a press, `use` does not), the special is cooling down, or the player is dead or out of play. - Nothing is played: `combat.melee` is missing. - The strike ignores the target: no `character.motor` serves aim and lunge, so the body yaw is used. - The weapon is not what you set: its id is unknown, so the first weapon is used. ## Limits Melee only; guns are `weapons.arsenal` and `combat.ranged`. Weapon modifiers are not saved: the kits that own them add them again. ## Versions Kit version 1.7.0 (animation layers); the fists, formerly `combat.unarmed`, joined in 1.6.0.