# Weapon experience and upgrades (weapons.mastery) ## What it is for `weapons.mastery` is an optional companion of `combat.ranged` for action platformers, shooters and RPGs. Every named gun keeps its own experience for each owner. Damage that is actually applied earns XP for the gun that fired it, including a projectile still flying after a weapon switch. Misses, scenery, blocked damage and zero damage earn nothing. Each level multiplies the damage of the next shots. Progress is saved; loading a save never replays rewards. The kit has no screen of its own: it publishes variables for your HUD. Anonymous default guns earn nothing, so declare named guns in `combat.ranged`. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "weapons.mastery" } gripforge_gamekit_configure { project_id: "gkp_…", id: "weapons.mastery", config: { "maxLevel": 5, "baseXp": 100, "growth": 1.5, "damagePerLevel": 0.2 } } ``` It requires `game.engine` and `combat.ranged`. ## First example With the default settings, a script grants 260 XP to the gun `rifle` of an entity: ```json { "service": "weapons.mastery", "method": "grant", "args": ["e1", "rifle", 260] } ``` The answer is `{ ok: true, cancelled: false, by: null, reason: null }`. The kit emits one `mastery.gained` (`amount` 260, `totalXp` 260, `reason` `script`), then one `mastery.levelled` for level 2 and one for level 3 (`damageMultiplier` 1.3). ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `maxLevel` | integer 1 to 100 | `5` | highest level; no XP is awarded at the cap | | `baseXp` | number | `100` | XP from level 1 to level 2 | | `growth` | number 1 to 3 | `1.5` | each level costs `ceil(previous cost * growth)` | | `xpPerDamage` | number 0 to 100 | `1` | XP per point of applied damage; `0` leaves awards to scripts | | `damagePerLevel` | number 0 to 10 | `0.15` | added to the multiplier for each level after the first (1, 1.15, 1.30…) | | `trackAllGuns` | boolean | `true` | `false`: only guns listed in `weapon_mastery` earn XP | | `ownerComponent` | string | `mastery.owner` | entity component holding a stable owner id | All settings are read live and are moddable. With the defaults, level 2 needs 100 XP, level 3 250, level 4 475, level 5 813. Changing a curve reinterprets the saved total XP. The `weapon_mastery` collection overrides `maxLevel`, `baseXp`, `growth`, `xpPerDamage` and `damagePerLevel` per gun; omitted fields inherit the settings: ```json { "id": "pulse", "maxLevel": 5, "baseXp": 100, "growth": 1.5, "xpPerDamage": 1, "damagePerLevel": 0.2 } ``` ## Services, events, variables - `weapons.mastery` (service) `state(entity, gun)`: `{ gun, level, totalXp, xp, toNext, damageMultiplier }`, or `null` for an empty or excluded gun. - `weapons.mastery` (service) `grant(entity, gun, amount, reason?)`: needs an existing entity and a positive finite amount; `reason` defaults to `script`. Answers `{ ok, cancelled, by, reason }`; a refusal has `ok: false` and a `reason` such as `invalid_award`, `max_level` or `zero_award`. - `mastery.gained` (event): an accepted award, with `entity`, `gun`, `amount`, `totalXp`, `reason`. - `mastery.levelled` (event): one per level crossed, with `entity`, `gun`, `level`, `damageMultiplier`. - Listens to `combat.hit` (applied hits carrying a gun id), `combat.fired` (remembers the gun of each projectile) and `projectile.impact` (credits that gun, then forgets the shot). - Variables for the controlled player's equipped gun: `mastery.gun`, `mastery.level`, `mastery.xp` (progress in the level), `mastery.toNext`, `mastery.damageMultiplier`. They read empty or `0` (multiplier `1`) when no gun is tracked. ## Hooks and modding The hook `mastery.gain` runs before each positive award to a gun below its cap, with `{ entity, gun, amount, reason }`. It can change `amount` or cancel; a refusal leaves progress unchanged. The kit also taps `ranged.fire` to multiply the damage of a shot. Set the entity component `mastery.owner` (or the field named by `ownerComponent`) to a stable id on successive heroes to keep progression across scenes and respawns; without it, progress belongs to the entity id. A mod that doubles all XP: ```json { "schema": "gripforge.mod/1", "id": "double_weapon_xp", "name": "Double weapon XP", "version": "1.0.0", "requires": { "weapons.mastery": "^1" }, "data": { "hooks": { "add": [{ "id": "double_weapon_xp", "hook": "mastery.gain", "mul": { "amount": 2 } }] } } } ``` ## Engines The rules are one shared implementation for the web and native players; the engine wrappers show only your HUD variables. ## When it does not do what you expect - No XP is earned: the gun has no id (declare named guns in `combat.ranged`), the hit was not applied, `xpPerDamage` is `0`, or `trackAllGuns` is `false` and the gun has no `weapon_mastery` row. - `state` answers `null`: the gun id is empty or excluded. - Progress is lost on a new hero: set the same `mastery.owner` on each hero entity. ## Limits No weapon assets, no mandatory screen, no XP for guns without a name. ## Versions Kit `weapons.mastery` 1.0.0, requires `game.engine@^1` and `combat.ranged@^1.1`.