Skip to content

Weapon files

A weapon is a file of the mod’s, <path>.weapon.luau, such as weapons/ak47.weapon.luau. It returns the weapon’s numbers as a table. Its path is its name: the mod gives it as p:give("weapons/ak47"). To make one, copy one of the stock mod’s. The stock AK-47, shortened:

-- weapons/ak47.weapon.luau
return {
model = "ak47",
damage = 34,
locations = { head = 2 },
interval = 0.1,
automatic = true,
range = 200,
spread = 0.5,
spread_moving = 4,
spread_air = 8,
view_kick = { up = { 60, 65 }, left = { -75, 65 }, center = 1800 },
gun_kick = { up = { -50, -45 }, left = { -20, 20 }, accel = 1000, speed_max = 500, speed_decay = 16, static_decay = 20 },
gun_kick_max = { up = 8, left = 25 },
magazine = 30,
reserve = 90,
reload = 2.5,
drop = 0.25,
raise = 0.6,
sprint_out = 0.4,
aim_fov = 55,
aim_time = 0.3,
aim_spread = 0.1,
aim_view_kick = { up = { 55, 65 }, left = { -70, 60 }, center = 1800 },
aim_gun_kick = { up = { -28, -20 }, left = { -20, 20 }, accel = 800, speed_max = 2000, speed_decay = 32, static_decay = 40 },
melee_damage = 150,
melee_time = 0.55,
melee_delay = 0.22,
}

The server and every player’s game read the same file, so a shot feels the same on both. The file runs on its own, with Luau’s safe libraries alone. A file that is wrong fails the call that names it, saying why.

The server reads weapons at each match start. With --reload it reads an edited one again during play: those carrying it keep it as it now is. An edit that makes it wrong keeps the weapon as it was, and the server says so once.

Angles are in degrees, times in seconds, distances in metres.

The weapon is drawn as the model of its path, weapons/ak47.model, unless model names another. Its sounds and clips lie beside that model, named after it and the act: ak47_fire, ak47_reload, ak47_melee.

Every weapon needs magazine, the rounds it holds, up to 999; 0 makes a melee weapon. A gun, one with a magazine and no offhand, needs each of these too:

Key What it is
damage the damage of a shot. A gun of 0 shoots nothing: the mod hears only fired, as for bandages.
interval the seconds between shots; a grenade needs it too
automatic true to fire while the trigger is held
range the metres a shot reaches; a grenade needs it too
spread, spread_moving, spread_air how far a shot strays standing, moving and in the air
view_kick how a shot turns the view: {up = {low, high}, left = {low, high}, center}, degrees a second picked between each pair, center turning it back
gun_kick how a shot turns the weapon in hand: {up, left} as view_kick’s, and its spring, accel, speed_max, speed_decay and static_decay
gun_kick_max {up, left}: the most the weapon turns
reload the seconds a reload takes

A melee weapon needs none of them, and a grenade needs only interval and range.

Every kick is within ±10000, and each rate and limit from 0 to 10000. Every time is up to 60 s.

These may be left out:

Key What it is
reserve the rounds a weapon given by name starts with for its reloads, 0 to 9999; 0 if left out
pellets shots a pull, each straying and hitting on its own, 1 to 32; 1 if left out
burst {count, interval}: a pull fires count shots, 2 to 10, interval seconds apart, a tick to 60 s
falloff {from, to, damage}: full damage up to from metres, then down to damage at to and beyond
penetrate metres of wall a shot goes through, 0 to 10; 0 if left out
locations what a shot’s damage is multiplied by on each limb, 0 to 10; 1 where left out
move_speed how much the weapon in hand scales the player’s speed, 0.1 to 2; 1 if left out

A reload takes only what the magazine lacks. p.slots gives the rounds a weapon has, and p:set_ammo sets them.

After a burst the weapon waits its own interval. Held, an automatic weapon fires the next burst; any other takes another pull. An empty magazine ends a burst. A switch, a reload, a sprint, a bash or a throw drops what is left of it.

Each wall a shot goes through uses up its thickness of penetrate, 2.54 cm at least, and the damage drops by the same share: through 0.1 m of 0.5, 80% is left. A shot goes through 5 walls at most.

The ten limbs are head, neck, chest, stomach, upper_arm, lower_arm, hand, upper_leg, lower_leg and foot, as locations = { head = 4, upper_leg = 0.75 }.

A shot meets a body by its limbs, as the shooter saw it, so one between the legs goes on to what is behind. A shot through several limbs strikes the one of the highest multiplier, a tie going to the first in that list. A bash reports the limb it strikes but keeps its melee_damage. A projectile and an explosion strike no limb.

In place of its kicks, view_kick = { pattern = "rifle_heavy" } makes a weapon follow one of the engine’s spray patterns: rifle_heavy, rifle or rifle_light, measured from CS’s AK-47, M4A4 and M4A1-S. A mod cannot make its own.

Each shot lands where the pattern is as it fires, at any interval. Once the weapon stops firing, the view walks back along the pattern, the whole of it in 0.3 s. A weapon keeps its pattern across a switch, and a shot of another pattern starts that one from its first point.

Nothing goes beside pattern, and the pattern holds with the sights up, so the weapon takes no aim_view_kick. gun_kick still moves the weapon in hand.

A player’s yaw and pitch are the mouse’s aim, without the pattern. fired’s dir is turned by it.

A weapon aims down the sights only with aim_fov, the view’s field of view while aiming, 1 to 179. One wider than the player’s own zooms out.

  • A number aims while aim is held, or toggled on.
  • A list of 1 to 4 levels, each narrower than the last, as the AWP’s { 40, 10 }, steps to the next on each press of aim, and past the last back to the hip. It eases from one level to the next over aim_time, and a shot keeps the level.

The mouse slows by each level’s field of view. A press of aim while the weapon comes up, after a sprint or a switch, is kept: the sights come up at its level once the weapon is ready.

With aim_fov, the weapon needs aim_time, the seconds the sights take to come up, aim_spread, and the aim kicks aim_view_kick and aim_gun_kick, shaped as the hip’s. aim_view_bob, how much the bob tips the view with the sights up, is 0 to 10, 0.25 if left out. Without aim_fov, aim does nothing with the weapon, and any of these fails the file. The mod still hears aim as p.pressed.aim.

A switch, a reload, a sprint, a bash, a throw or p:disable_weapon takes the sights back to the hip.

scope names an image that fills the view in place of the weapon once the sights are fully up, at every level, as a sniper’s scope: square and as tall as the screen, black beyond its sides. Only its holder sees it.

Key What it is Needed by
drop the seconds to put the weapon down when switching away every weapon but a grenade
raise the seconds to bring it up every weapon
sprint_out the seconds to bring it up after a sprint, before it fires every weapon but a grenade

Every weapon but a grenade bashes, on the melee key (V), and a melee weapon’s fire bashes too. Each of these is needed:

Key What it is
melee_damage its damage, 1 or more
melee_time the seconds a bash takes
melee_delay the seconds into it that it lands, before the end of melee_time
melee_range how far it reaches, over 0 and up to 25.4 m; 1.6256 m if left out

Held, melee bashes once. A bash blocks firing and reloading for its melee_time. A sprint, mantling or p:disable_weapon drops it.

A melee weapon, of magazine = 0, neither shoots, reloads nor aims. One with no model is fists.

projectile makes a weapon fire one in place of a bullet, as a rocket or a grenade:

projectile = {
model = "grenade_thrown",
speed = 23.876,
speed_up = 3.048,
gravity = 1,
bounce = 0.4,
fuse = 3.5,
explode = { radius = 6.5, damage = 200, min_damage = 20 },
effect = "explosion",
sound = "explosion_boom",
}
Key What it is
model the model that flies
speed its speed leaving the eye, over 0 and up to 300 m/s
speed_up more speed upward, for a throw, 0 to 300 m/s
gravity how much it falls, times a player’s gravity, 0 to 10; 0 if left out
radius its size, as a ball, 0.01 to 0.25 m; 0.05 if left out
bounce the share of its speed it keeps bouncing off what it meets, 0 to 1. Without it, it bursts there.
fuse the seconds after which it bursts wherever it is, up to 30
explode {radius, damage, min_damage}: what its burst does, as explode does. radius is up to 50 m.
effect, sound the effect and the sound of its burst

The weapon needs pellets = 1 and a finite range. The projectile is gone past range, or after 30 s. It hits every body but its shooter’s, and its burst hits its shooter too.

offhand = "frag" or "smoke" makes a weapon a grenade. A player carries one of each kind, apart from the slots, and throws it with its action’s key: a frag on lethal, G by default, and a smoke on tactical, Q. A grenade needs only magazine, the most carried, raise, interval, range and projectile; fire_delay is the seconds into interval that it leaves the hand.

Its key puts the weapon in hand down over its drop, then brings the grenade up and pulls the pin over raise. Held, the grenade cooks, its fuse burning; cooked to the end, it bursts in the hand. Let go, it is thrown over interval. Before the pin is out, a sprint or mantling stops the throw and keeps the grenade; after, nothing does.

An edit that makes a weapon a grenade, or a grenade a weapon, moves it to its new place, unless that place is taken.