ATY Scripts Logo
ATY Scripts/Docs/Inventory/Weapons & Ammo

Weapons & Ammo

Weapons & Ammo

Weapons are unique units

A weapon never stacks. Each one gets a serial (a uid) when it is created and carries its own durability and loaded ammo; attachments, and anything else another resource writes onto it, ride on the same unit.

invtrace <uid>

answers "whose gun was this" for that exact unit — not for weapons of that type. The uid is the one the admin panel shows for that unit.

Ammo

Ammo is an item, and — as in ox_inventory — one item is one round (Config.Ammo.mode = 'single'). Loading moves as many rounds as the weapon has room for out of one stack into the weapon's own metadata; the ledger records both halves. mode = 'box' makes one item a box of its rounds instead.

A server that held ammunition before switching to single mode converts it once: invammoconvert (dry run), then invammoconvert confirm. Until then loading and adding ammunition is held and the console says why. Items put back rather than made — qb's SetInventory re-adding what it just cleared — still go in while it is held.

  • Stored ammo is recognised by category = 'ammo', not by its name, so ammo you named your own way (rounds_9mm, or anything made ammo with invoverride item <name> category ammo) is held and converted too.
  • Nothing is converted without an answer from the database. If the backup or the read of the table times out, the command stops before touching anything.
  • A conversion that stops halfway can be finished. Before it touches anything, confirm lists every container in ammo_convert_unfinished.json. If the database stops taking writes midway, the run stops and says so, and the next invammoconvert confirm converts only the containers it had not reached. It never converts one twice.
  • Writes never overwrite newer saves. A container saved after the command read it (a player joined, moved things and left) is read again and converted from its newer copy. Every converted container's version goes up by 1,000,000, not 1. That jump is how a later run tells it was already done.
  • If the boot cannot reach the database, ammunition stays held and invdoctor says so. invammoconvert (even a dry run) asks again and releases it when nothing needs converting. Run it rather than skip.
  • force <item>=<rounds> is only for after the conversion: boxes that arrived later through invmigrate or invimport. Before it, force is refused.
invammo <playerId|invId>   self-test: loads a weapon that has room from a stack that fits
invspecialammo             self-test: special rounds, in a throwaway stash

The loaded count travels with the weapon. Trade a half-loaded pistol and it arrives half-loaded.

Which round fits which gun

A weapon names one ammunition item and how many rounds it holds:

weapon_pistol = { ..., ammoType = 'ammo_pistol', capacity = 96 },

Loading refuses anything else, and refuses once capacity is reached. A special round says which ordinary round it stands in for with ammoFor (ammo_pistol_hollow → ammoFor = 'ammo_pistol'), so every weapon that takes 9mm takes it without being told its name.

invitemdef <item> prints both halves: what a weapon takes and holds, and what a round loads as.

Framework weapons

Weapons adopted from the framework's catalogue carry their ammunition across:

Framework field Loads
qb ammotype = 'AMMO_PISTOL' ammo_pistol, capacity 96
qb AMMO_SMG ammo_smg, capacity 180
qb AMMO_RIFLE ammo_rifle, capacity 120
qb AMMO_SHOTGUN / AMMO_MG / AMMO_SNIPER / AMMO_EMPLAUNCHER the framework's own ammo item
ox ammoname that item

qb's pistol_ammo, smg_ammo and rifle_ammo load as this resource's ammo_pistol, ammo_smg and ammo_rifle, so a player holding either goes into the same guns. A weapon that needs a different number is defined in data/items.lua, which always wins over adoption.

Before 1.7.6 adopted weapons arrived with no capacity at all, and loading an empty SNS Pistol or Pistol Mk II answered **"Already full"**.

Loading and the reload animation

Using a magazine, dragging one onto the weapon and pressing the reload key all load the same way. A new magazine swaps the old one out — its rounds go back to the reserve, none are lost — and the hands are seen putting the new one in, every time. The game never reloads on its own: as in ox_inventory (inventory:autoreload is off), an empty magazine waits for the reload key.

Every press of the reload key does something. When the bag holds a magazine that fits the drawn weapon and the weapon has room for it, the magazine goes in. Otherwise it is the game's own reload, from the rounds already in the gun. The game is never left to reload on that key by itself while a weapon is drawn, so one press is one reload, never two.

The driver of a moving vehicle is the one exception to the animation. The game does not play a reload for a driver at speed, so, as in ox_inventory, the magazine is filled at once from the rounds already in the gun instead. A passenger, or a driver who has stopped, reloads with the hands as usual.

As in ox_inventory, the key does nothing during any progress bar, or while the player is dead, ragdolled, falling or shooting. While a weapon is drawn the same key never pistol-whips a nearby ped, and in a vehicle it never switches to the cinematic camera.

The magazine picked is the same kind as the rounds already loaded, and for an empty gun the weapon's own round before a stand-in (ammoFor). In box mode a load spends a whole box, so a box only goes into an empty gun or one with room for all of it — R never throws away a box for six rounds.

An empty gun stays in the hands. The game used to swap to bare hands at the last shot; that is turned off while this resource runs, so the reload key and magazines always find the weapon where the player left it.

Config.Weapons.reload = {
    onlyWhenEmpty = false, -- true: a magazine only when the gun is dry
    duration      = 0,     -- ms the reload takes; 0 = instant, as in ox_inventory
    bar           = true,  -- show a progress bar when there is a duration
    cooldown      = 1200,  -- ms before the key is answered again
}

With a duration the reload is a timed action checked by the server, and the magazine goes in when the bar finishes. That covers using a magazine and the reload key; dragging one onto the weapon still loads at once. The bar is drawn by whoever draws bars on the server — see Config.Consume.progress.

Attachments

Attachments live on the unit's metadata and are shown in the detail column. They survive storage, trading and restarts.

Drawing and holstering

Drawing a weapon leaves it in its slot and puts it in the player's hands: the server records which slot is drawn and hands the client the weapon, its rounds and its attachments. The inventory stays the source of truth for what exists; the game handles what is held.

The draw and holster animations are ox_inventory's (inventory:weaponanims):

Weapon Draw Weapon in hand at
Melee melee@holster · unholster 0.2 s
Pistol or stun gun, police job reaction@intimidation@cop@unarmed · intro 0.4 s
Anything else reaction@intimidation@1h · intro 1.2 s

On a motorcycle or a bicycle nothing plays and the weapon is there at once. Steering is not locked during a draw in a vehicle; set Config.Weapons.draw.lockSteering = true to lock it. The clips and timings live in Config.Weapons.draw.styles and Config.Weapons.holster.styles.

invweapon <playerId|invId>   self-test: draws the first weapon, spends ten rounds, checks ammo and wear move together
weapcheck                    F8, as the player: what the game thinks is in the hands

Weapons the inventory did not give

As in ox_inventory (inventory:weaponmismatch, inventory:suppresspickups), both on by default:

Config.Weapons.mismatch        = true  -- a weapon in the hands with nothing drawn from the bag is taken away
Config.Weapons.ignore          = {}    -- names or hashes left alone, e.g. { 'WEAPON_PETROLCAN' }
Config.Weapons.suppressPickups = true  -- the game's weapon and ammunition pickups pay out nothing

With nothing drawn from the bag, a weapon that turns up in the hands — a world pickup, a menu, another resource's GiveWeaponToPed — is taken away within 200 ms. Bare hands, handcuffs, the garbage bag, OBJECT, the hose and the parachute are always left alone. A server whose weapons come from somewhere else lists them in ignore or sets mismatch = false. A police car's shotgun is never handed out while Config.Weapons.enabled is on.

The weapon wheel

Config.Weapons.wheel = false   -- the default

Off, on purpose. While the wheel is held open the ped is handed every other weapon in the bag with no ammunition — enough to draw an icon, not enough to fire — and they are taken back when it closes. For that fraction of a second the ped carries models it does not own, and a melee weapon needs no ammunition at all: not a trade an inventory should make for a server that never asked for it. The quick slots reach the same weapons and hand the ped nothing.

Set it to true to have the wheel, with that cost understood. The wheel opens on TAB, which is also the quick-slot key: whenever the game's wheel can open, TAB opens the wheel and the quick slots stay hidden, as in ox_inventory. That includes Config.Weapons.enabled = false with wheel = true, for a server whose weapons belong to another script. Only Config.OpenKey on TAB cannot work — the wheel then stands down and says so once in the console.

With the wheel off, it still opens in a seat that has a vehicle weapon (a turret, an armed car) so that seat's guns can be picked, as in ox_inventory — unless Config.OpenKey is on TAB, where one press would open the glovebox and the wheel together; there the wheel stays off in every seat.

Death

Config.Death = { … }

Off by default (Config.Death.enabled = false), as in ox_inventory, which has no drop-on-death. A dead player's things stay in their pockets, where anyone standing over the body can go through them (Config.Search.allow.dead, see Search & Evidence).

Turned on, what matches categories ({ 'weapon' }) or items falls into one pile at the body — with heldOnly = true, the default, only the weapon that was in the hand. A pinned stack stays (keepPinned), and so does an item bound against dropping. The drop is an ordinary move, so every item that falls is a ledger row (reason = 'death').

invdeath <playerId> [spill]   what would fall, and why; spill runs it for real
invdeathtest                  self-test
ATY Scripts LogoATY SCRIPTS

Creamos scripts de FiveM altamente optimizados para QBCore y ESX. Máximo rendimiento, código preciso, cero lag.

Unirse a la comunidad

Socio

Socios oficiales de Tebex. Pago seguro e integración con Cfx.re Keymaster.

Legal

Sin afiliación con Rockstar Games, Cfx.re, FiveM ni Take-Two Interactive. Las compras se rigen por los Términos de Servicio de Tebex.

© 2026 ATY SCRIPTS. Todos los derechos reservados.