Police armory for FiveM. Officers walk up to the armory, pick a ready-made loadout for their rank or single pieces of equipment, choose attachments on a turning 3D model of the weapon, and sign it all out. Every weapon gets a serial number; returns are checked against what was issued, and every issue and return is logged.
Features
- Rank based loadouts (Patrol, Shotgun Patrol, Patrol Rifle, SWAT by default) and single equipment
- Turning 3D weapon preview in a dark studio view; drag to turn, attachments appear on the model as you pick them
- Attachments limited by rank (example: suppressor for Lieutenant and up)
- Serial number on every issued weapon (
ARM-XXXXXX), shown in ox_inventory and QBCore item info - One loadout at a time; a weapon cannot be taken twice before it is returned
- Return checks the exact weapons the armory gave out (by serial), and that their attachments are still on them or come back as items; unused ammo and returnable items (radios) go back too
- Anything not returned stays on the officer's record as missing and keeps the loadout locked; supervisors see open records with
/armorylistand write them off with/armoryclear - Rounds that do not come back are written in the log; after such a return new gear waits a short cooldown, so ammo cannot be pulled again and again
- QBCore / Qbox: only officers on duty take gear; anyone with gear signed out can always bring it back
- Issue / return log in
data/log.json, optional Discord webhook - Optional stock per weapon; weapons written off stay out of stock until
/armoryrestock - Exports for MDT and evidence scripts:
GetIssued(source),IsArmoryWeapon(serial) - Works with ox_inventory, QBCore, Qbox, ESX Legacy, or standalone
- ox_target / qb-target support, or a marker and a key (
E) without a target script - Everything is checked on the server: job, rank, distance to the armory, cooldown
- Works together with Gunrack (Torpil Studio): load issued long guns into a vehicle rack from the armory; weapons left in a rack count when returning
- 9 languages included: English, Turkish, German, French, Spanish, Portuguese (Brazil), Polish, Dutch, Italian.
Config.Locale = 'auto'shows every player the language of their GTA game. Add your own inlocales/
Requirements
- OneSync (on by default on current servers): the server checks each player's position
- FXServer build 5181 or newer
Installation
- Put the
armoryfolder in yourresourcesfolder. - Add to
server.cfg(after your framework, inventory and target):
ensure armory
- Open
config.luaand set at least:Config.Armories: where the armory is on your map (coords= where the officer stands,heading= the way they face)Config.AllowedJobs: jobs that may use itConfig.Loadouts: what each rank gets
Without a framework
Give the ACE permission armory.use, and a rank with armory.grade.<n>:
add_ace group.police armory.use allow
add_ace group.police armory.grade.2 allow
Discord log
Put the webhook in server.cfg, never in config.lua (every player's game can read config.lua):
set armory_webhook "https://discord.com/api/webhooks/..."
Inventory notes
| System | Weapons | Ammo | Attachments | Serial |
|---|---|---|---|---|
| ox_inventory (ESX / QBCore / Qbox) | item | ammo-9, ammo-rifle... |
ox attachment items | serial + registered |
| QBCore inventories | item | pistol_ammo, rifle_ammo... |
info.attachments |
info.serie |
| ESX Legacy (loadout) | loadout | with the weapon | ESX components | - |
| Standalone | game | game | game | - |
Item and component names can be changed in config.lua (Config.AmmoItems, Config.Attachments, Config.Items).
Weapons are handed out loaded with one magazine (clip in Config.Weapons); the rest of the rounds come as ammo items. On return, the rounds still in the weapon count, and at most the ammo items the armory gave are taken back (never the officer's own).
Attachments: with ox_inventory an officer can take an attachment off a weapon as an item. On return the armory checks the weapon: an attachment that is gone must come back as its item, otherwise it stays on the record as missing. For QBCore weapon resources that do the same, set the attachment item name as qb = '...' in Config.Attachments.
ESX loadout: ESX holds one weapon of each kind and has no serial numbers, so on ESX the armory takes back the weapon by its name.
Your police job may have its own armory: qb-policejob and esx_policejob come with an armory point at Mission Row. Turn it off or move it so officers use one armory.
ox_inventory has its own "Police Armoury" shop at Mission Row (ox_inventory/data/shops.lua, PoliceArmoury). Remove it or move it, otherwise officers see two options at the same counter.
Commands
| Command | Who | What |
|---|---|---|
/armorylist |
rank Config.SupervisorGrade+, ACE armory.admin, console |
open records: who still has gear out, what is missing (in the F8 console) |
/armoryclear <server id or identifier> [reason] |
same | writes off an officer's record (lost, seized, left the job). Works for offline officers by identifier (shown in /armorylist). Nobody clears their own record without armory.admin |
/armoryrestock [WEAPON_NAME] |
ACE armory.admin, console |
weapons written off are replaced, stock goes back to config.lua |
The key (E) is saved in each player's FiveM key bindings the first time; changing Config.Key later only applies to players who never opened the armory.
Exports
-- gear signed out to a player: { { type = 'weapon', name = 'WEAPON_X', tag = 'ARM-...', missing = false, rack = nil }, ... }
local list = exports.armory:GetIssued(source)
-- is this serial an armory weapon? ok, officer name, weapon name
local ok, officer, weapon = exports.armory:IsArmoryWeapon('ARM-1A2B3C')
Editing
config.lua, locales/, server/framework.lua and server/inventory.lua are open to edit (to support another framework or inventory). The rest is protected by Cfx asset escrow.
Performance
With ox_target or qb-target there is no loop at all. In marker mode a distance check runs every 800 ms, and every frame only within 12 m of an armory (to draw the marker). The preview runs only while the panel is open.