Guns
Usage guide of combat.ranged: hitscan or projectile guns with magazines, reload, fire rate, spread, falloff, charge, beams, jets and sentries, the guns collection, settings and defaults, service, events, hooks and verbs. The shared damage rules are in the combat guide.
Guns and ranged fire (combat.ranged) #
What it is for #
combat.ranged gives any entity a gun: the player through the inputs (fire held for automatic fire at fireRate, aim to tighten the spread, reload), and NPCs or turrets through the service. A gun has a magazine, a fire rate, a reload, spread and recoil, and damage that fades with distance. A shot is either a physics ray (instant) or handed to combat.projectiles, which flies it. Damage goes through combat.damage (or vehicle.damage, or the health component). A gun is the kit settings, or a model of the guns collection that overrides them for whoever holds it: shotguns, charged shots, melee swings, continuous beams, cone jets and hovering sentries. The rules shared by every fighting kit (health, shield, statuses, knockback) are in the combat guide.
Turn it on #
Install the kit in a project and set its settings with the tools below; gripforge kit api combat.ranged lists every setting, and gripforge docs combat-ranged prints this guide offline.
gripforge_gamekit_install { project_id: "gkp_…", id: "combat.core" }
gripforge_gamekit_install { project_id: "gkp_…", id: "combat.ranged" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "combat.ranged",
config: { "damage": 20, "fireRate": 8, "magazine": 24, "hud": "both" } }
{ "id": "jet", "damage": 10, "fireRate": 10, "magazine": 50, "range": 10, "jet": { "angle": 40 } }
First example #
<!-- test: kits/game_engine/host/tests/ranged_special.rs::cone_hits_each_enemy_once_excludes_allies_back_and_walls --> A jet gun (10 damage, 50 rounds) fired at an enemy 6 m ahead hits every enemy in its cone once, leaves allies, targets behind and targets behind a wall alone, and spends one round per pulse.
combat.ranged.equip(player, "jet")
combat.ranged.fire(player, { yaw: 0, pitch: 0 }) // true: the two enemies in the cone lose 10 each
combat.ranged.ammo(player) // 49
combat.ranged.specialFrame() // the 9 rays of the pulse, to draw
Settings and defaults #
| Setting | Default | Meaning |
|---|---|---|
meleeWeapons | false | {{s_meleeWeapons}} |
damage | 25 | damage of a shot before falloff (1 to 500) |
fireRate | 6 | {{s_fireRate}} |
magazine | 30 | rounds in a magazine (1 to 200) |
reloadSeconds | 1.8 | {{s_reloadSeconds}} |
projectile | false | false: hitscan; true: projectiles flown by combat.projectiles (without that kit the gun does not fire) |
range | 100 | reach of a shot in metres: the hitscan ray, and where the falloff ends (1 to 1000) |
falloffStart | 25 | {{s_falloffStart}} |
falloffMin | 0.5 | {{s_falloffMin}} |
spreadHip | 0.03 | {{s_spreadHip}} |
spreadAim | 0.008 | {{s_spreadAim}} |
targeting | not set | optional targeting assist of the Rust host (an object of the shared targeting core; see gripforge kit api combat.ranged) |
aimFromView | false | {{s_aimFromView}} |
holdIdle | idle_guns | {{s_holdIdle}} |
hud | none | what the kit's HUD view shows of the player's gun: ammo (name, magazine, reloading), reticle (spread drawn around the centre), both or none (a game that draws its own) |
Services #
combat.ranged(service):fire(entity, aim?),reload(entity),ammo(entity),state(entity),setAiming(entity, on),equip(entity, gun),gun(entity),held(); on the Rust host alsoresolveAim(player, fromView?)(a fresh targeting preview of the controlled player),targeting(entity, command),targetingStep(entity, observation),targetingFrame(entity),specialFrame()(transient observations of jets and sentries) andbeams()(the beams to draw).entityis an id or the player.- The
gunscollection holds gun models; every field a model gives wins over the kit settings for whoever holds it. Fields:id,name, the settingsdamage,fireRate,magazine,reloadSeconds,range,falloffStart,falloffMin,spreadHip,spreadAim,projectile, thenspeed,gravityandlifetimeof a projectile,pellets(1 to 16 shots per pull, one round),charge { seconds, damage, min }(held to a full charge),melee { range, arc, damage, windup, active, recovery, knockback, lunge }(the trigger swings it, no round spent),beam { width, color }(held, an exact ray atfireRate, damage and rounds per tick, no spread),jet { angle }(Rust host: held cone pulses atfireRate, capped at 20 m, each enemy once per pulse, fresh line of sight, not combinable with beam, melee, charge or deploy),deploy { lifetime, distance, maxActive, fireRate }(Rust host: a stationary hovering sentry, 12 s, 2 m ahead, 2 active per owner and 4 pulses per second by default, using the gun damage and range),anim,meleeCombat,model,hold,grip,colorandpresentationProfile. An entity with the componentranged { damage }is a turret or a shooting NPC placed by hand; the componentcombat.target { enabled, offset }opts a scene instance into the Rust targeting.
Events #
combat.fired: a shot left the gun:entity,origin,yaw,pitch,ammoleft,projectile(the idcombat.projectilesgave the first shot),gun,pellets,charge(0 to 1) andmeleefor a swing.combat.hit: a hitscan shot reached something:entity(the shooter),target,damage,point,distance,applied(true when the damage already went through a service or the health component),gun.combat.reloading(a reload began:entity,seconds),combat.reloaded(entity) andcombat.empty(the trigger was pulled on an empty magazine, and a reload starts).combat.equipped(a model ofgunsis now in the hands ofentity:gun,magazinesize,ammoit holds) and, on the Rust host,combat.deployed(a hovering sentry was accepted:entity,owner,gun,at). The kit listens toinput.actionandentity.despawned.
Hooks and modding #
ranged.fire: a loaded, cooled-down gun that is not reloading is about to fire (entity,yaw,pitch,spreadin radians recoil included,damagebefore falloff,costin rounds,ammo,aiming,projectile,gun);yaw,pitch,spread,damageandcostare mutable (0 cost: a free shot), and cancelling makesfirereturnfalsewith nothing drawn, spent or emitted (a jammed or holstered gun).ranged.reload: a gun that is not full and not already reloading is about to reload (entity,ammo,magazine,seconds,rounds);secondsandrounds(how many rounds go in, fewer when a reserve runs low) are mutable, and cancelling means no reload (no reserve left, a silenced zone).ranged.hit: a hitscan shot of this kit reached an entity (entitythe shooter,target,distance,damageafter falloff);damageis mutable, and cancelling stops the shot there with no damage and nocombat.hit. Shots handed tocombat.projectilesaskprojectile.impactinstead.ranged.equip: a model ofgunsis about to go into the hands ofentity(serviceequip, verbequip_gun):gunandammo(the rounds it comes in with, full by default; an arsenal gives each gun its stored magazine back) are mutable, and cancelling makesequipanswerfalseand keeps the gun in hand.
{ "id": "silenced_zone", "hook": "ranged.reload", "if": [{ "var": "zone.silent", "op": "==", "value": true }], "cancel": true, "reason": "silent" }
Using it from content #
Script verbs: the actions fire (instance or entity, default the player, optional yaw and pitch; refused while reloading or cooling down, an empty magazine reloads), reload, equip_gun (gun, magazine full) and damage (entity or target, amount: through combat.damage; registered only when no other kit owns the verb). Inputs: fire (Mouse0), aim (Mouse2), reload (KeyR). Variables: combat.ammo, combat.magazine, combat.reloading, combat.gun, combat.charge.
{ "equip_gun": "rifle" }
{ "fire": "turret_1" }
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
fire returns false | The gun is reloading, cooling down between shots, or empty (it starts a reload and emits combat.empty), or a ranged.fire tap cancelled it. |
| A projectile gun does not fire | combat.projectiles is not installed: it flies the shots of projectile: true. A hitscan-only game works without it. |
| A shot hits but nothing loses health | The target was not registered with combat.health (see the combat guide), is on the shooter's team, or is invulnerable; read blocked in the combat.damage answer. |
Limits #
- The beam, jet, deploy, targeting and direct melee-weapon modes are Rust host features; the web player and the other engines run the plain guns (hitscan or projectile, charge, pellets, melee swing) and ignore them.
- NPC shooters read
npc.behavior, which no native module serves yet. Magazines and reserves are per gun: a reserve comes fromweapons.arsenal. - The ammo view and the reticle are web display views; the gun model in hand is drawn by the display module on the hand bone of the shooter.
Versions #
Kit combat.ranged 1.25.0 (2026-10-26): optional meleeCombat.rangedDefense for guard, parry and dodge decisions on direct ranged arrivals, Rust host only. 1.20.0 moved projectile flight to combat.projectiles; the hooks ranged.fire, ranged.reload, ranged.hit and ranged.equip run on the web and the Rust host. It needs character.control, input.actions, spawn.entities, physics.port and game.engine ^1.