Inventory: config files
These files stay readable in every build (escrow too), so you can change them. Shown as shipped in version 1.0.3.
config/config.lua
lua
Config = {
-- Player items are stored per framework (bridge/ picks the framework):
--
-- QBCore `players`.`inventory`, the native column. No migration.
-- Qbox/ESX/standalone `lumo_inventories`.`items`, created on first start.
--
-- On Qbox `players.inventory` already belongs to ox_inventory in a different
-- format, so it is never written to.
UseTarget = GetConvar('UseTarget', 'false') == 'true',
MaxWeight = 120000, -- grams
MaxSlots = 40,
-- Who equips weapons, loads ammo and fits attachments.
-- 'auto' qb-weapons when it runs (QBCore), otherwise the built-in
-- handler (Qbox, ESX, standalone). See Config.Weapons below.
-- 'qb-weapons' always qb-weapons.
-- 'builtin' always the built-in handler.
-- any other a resource with qb-weapons' (item, canShoot) contract;
-- set weaponEvent to its use event.
ItemUse = {weaponResource = 'auto', weaponEvent = 'qb-weapons:client:UseWeapon'},
-- Built-in weapon handler (used when qb-weapons is not running).
Weapons = {
-- Each ammo item loads this many rounds into the weapon in your hands,
-- if the weapon takes that ammo type.
Ammo = {
pistol_ammo = { type = 'AMMO_PISTOL', amount = 12 },
smg_ammo = { type = 'AMMO_SMG', amount = 20 },
rifle_ammo = { type = 'AMMO_RIFLE', amount = 30 },
shotgun_ammo = { type = 'AMMO_SHOTGUN', amount = 10 },
mg_ammo = { type = 'AMMO_MG', amount = 30 },
snp_ammo = { type = 'AMMO_SNIPER', amount = 10 },
emp_ammo = { type = 'AMMO_EMPLAUNCHER', amount = 10 },
},
MaxAmmo = 250, -- rounds one weapon can hold
-- A weapon at 0 quality cannot be fired. Each shot takes this much
-- quality off (0 = weapons never wear out).
WearPerShot = 0.05,
-- Block GTA's weapon wheel (TAB) and mouse-wheel weapon switching, which
-- open over the inventory. 'auto': while the built-in handler is in use
-- (ESX, Qbox, standalone); QBCore's qb-smallresources already does it.
DisableWeaponWheel = 'auto',
},
-- ESX only.
ESX = {
-- Replace xPlayer.addInventoryItem / removeInventoryItem /
-- getInventoryItem / canCarryItem / addWeapon / … so every ESX script
-- gives and takes items from this inventory. Leave on.
OverridePlayerFunctions = true,
-- Weapons are inventory items. xPlayer.addWeapon adds a weapon item,
-- xPlayer.removeWeapon removes it, getLoadout lists them.
WeaponsAsItems = true,
-- ESX's `items` table weighs in kilograms (bread = 1, 24 kg limit);
-- this inventory weighs in grams. ESX weight x scale = grams.
ItemWeightScale = 1000,
-- false: ignore ESX weights and use the built-in catalogue's.
UseESXWeights = true,
-- Copy each character's existing ESX items and weapons in the first
-- time they log in with lumo-inventory (once per character).
ImportESXInventory = true,
-- Items sold by these shop resources are read from their config: any
-- the inventory does not know yet are added (shop label, ShopItemWeight
-- grams), and they use the shop's own picture (nui://esx_shops/web/images/…).
ShopResources = { 'esx_shops' },
ShopItemWeight = 250,
-- esx_weaponshop sees only the weapons on your ped. At its counters,
-- put every weapon item on the ped (holstered) so it knows what you
-- own, offers ammo and upgrades, and does not sell the same gun again.
StageWeaponsAtShops = true,
},
-- Items to add on ESX and standalone without editing shared/items.lua.
-- QBCore/Qbox: add items to your core's item list as usual.
-- my_item = { label = 'My Item', weight = 100, image = 'my_item.png',
-- unique = false, useable = true, description = '…' },
ExtraItems = {},
--- Food, drink and alcohol handlers.
---
--- These exist because use-handlers are registered per item *name*, by
--- whichever smallresources your framework ships. On QBCore that is
--- qb-smallresources and it already claims these names; on Qbox it is
--- qbx_smallresources, which registers ox names (`water`, `burger`) and so
--- leaves the QBCore-named items with no handler at all -- using one did
--- nothing, silently.
---
--- auto: QBCore uses a live registered handler (qb-smallresources, medical,
--- etc.), falling back to this inventory if none exists. Other frameworks
--- use the built-in definitions below. Checked at use time, not startup.
--- inventory/always: force built-in definitions; false: external handlers only.
Consumables = {
mode = 'auto',
externalCooldown = 6500, -- guard repeated native consumable activation
esxStatusMax = 1000000, -- match esx_status Config.StatusMax
applyEffect = nil, -- optional custom (source, kind, percentAmount) hook
--- Replenish amounts are ranges; a value is rolled per use.
---
--- Only items present in your item catalogue can be used, so
--- listing an item you do not have costs nothing.
eat = {
sandwich = { 35, 54 },
tosti = { 40, 50 },
twerks_candy = { 35, 54 },
snikkel_candy = { 40, 50 },
burger = { 40, 55 },
taco = { 40, 55 },
donut = { 25, 40 },
momo = { 40, 55 },
chocolate = { 25, 40 },
pizza_ham = { 45, 60 },
taco_chicken = { 40, 55 },
},
drink = {
water_bottle = { 35, 54 },
water = { 35, 54 },
kurkakola = { 35, 54 },
cola = { 35, 54 },
coffee = { 40, 50 },
sprunk = { 35, 50 },
energy_drink = { 40, 55 },
grapejuice = { 35, 50 },
},
--- Alcohol replenishes thirst but also builds drunkenness.
alcohol = {
whiskey = { 20, 30 },
whiskey_bottle = { 20, 30 },
luxury_whiskey = { 25, 35 },
beer = { 30, 40 },
beer_bottle = { 30, 40 },
vodka = { 20, 40 },
vodka_bottle = { 20, 40 },
wine = { 20, 35 },
blackberry_ale = { 30, 40 },
},
--- Restores health rather than hunger or thirst.
heal = {
bandage = { 20, 30 },
firstaid = { 45, 60 },
painkiller = { 15, 25 },
painkillers = { 15, 25 },
},
duration = { eat = 5000, drink = 4000, alcohol = 4000, heal = 4000 },
},
Money = {
useCashAsItem = false, -- Keep in sync with qb-core: QBConfig.Money.UseCashAsItem
cashItemName = 'cash', -- Keep in sync with qb-core: QBConfig.Money.CashItemName
cashItemSlot = 6, -- Keep in sync with qb-core: QBConfig.Money.CashItemSlot
-- Pin cash to cashItemSlot and forbid moving/splitting/dropping it.
-- Off by default: cash is still a real item, it just behaves like every
-- other item (drag anywhere, stack, split, drop, hand over).
lockCashSlot = false,
},
PlayerInventoryOverride = {
enabled = true,
infiniteMaxWeight = 2147483647,
infiniteSlots = 500,
licenses = {
-- ['license:xxxxxxxx'] = true,
},
},
UISettings = {
closeOnDoubleUse = true,
tooltipDelayShow = 140,
tooltipDelayHide = 40,
compactMode = false,
sharpMode = true,
enableTypeGlow = true,
enableRarityGlow = true,
showTooltipHints = true,
notificationDuration = 3000,
notificationMaxStack = 3,
},
-- ═══════════════════════════════════════════════════════════════════
-- Encumbrance
--
-- The pane header has always drawn a weight gauge that nothing consumed:
-- 119/120 kg moved exactly like carrying nothing at all. This makes the
-- limit a trade-off instead of a number that only bites when a pickup is
-- refused. Purely client-side handling — nothing is sent to the server.
-- ═══════════════════════════════════════════════════════════════════
Encumbrance = {
enabled = true,
threshold = 0.75, -- fraction of max weight before any penalty starts
minMoveRate = 0.88, -- move rate at 100% capacity (1.0 = normal)
staminaDrain = 6.0, -- sprint stamina drained per tick while overloaded
noSprintAt = 0.95, -- above this fraction, sprinting is refused
tickMs = 250,
notify = true, -- one notification when you cross the threshold
},
-- ═══════════════════════════════════════════════════════════════════
-- Character panel: equipment (wear/remove clothing) + body damage
-- ═══════════════════════════════════════════════════════════════════
CharacterPanel = {
enabled = true, -- master switch for the whole left character panel
showEquipment = true, -- clickable clothing slots that toggle pieces on/off
showBody = true, -- body silhouette + HP / armor / bleed
bodyResource = 'qb-ambulancejob', -- resource exporting GetBodyStatus
refreshInterval = 800, -- ms between live body-status refreshes while open
-- Each slot toggles a GTA clothing component or prop on the ped.
-- kind = 'component' (SetPedComponentVariation) or 'prop' (SetPedPropIndex)
-- id = the GTA component/prop index
-- off = drawable value used when the piece is "taken off"
-- (props always use ClearPedProp, so 'off' is ignored for them)
-- icon = key matched to an inline SVG in the NUI
-- Order here is the order shown in the panel.
EquipmentSlots = {
{ key = 'hat', label = 'Hat', kind = 'prop', id = 0, icon = 'hat' },
{ key = 'glasses', label = 'Glasses', kind = 'prop', id = 1, icon = 'glasses' },
{ key = 'ears', label = 'Ears', kind = 'prop', id = 2, icon = 'ears' },
{ key = 'mask', label = 'Mask', kind = 'component', id = 1, off = 0, icon = 'mask' },
{ key = 'jacket', label = 'Jacket', kind = 'component', id = 11, off = 15, icon = 'jacket' },
{ key = 'shirt', label = 'Shirt', kind = 'component', id = 8, off = 15, icon = 'shirt' },
{ key = 'vest', label = 'Vest', kind = 'component', id = 9, off = 0, icon = 'vest' },
{ key = 'gloves', label = 'Gloves', kind = 'component', id = 3, off = 15, icon = 'gloves' },
{ key = 'pants', label = 'Pants', kind = 'component', id = 4, off = 14, icon = 'pants' },
{ key = 'shoes', label = 'Shoes', kind = 'component', id = 6, off = 0, icon = 'shoes' },
{ key = 'bag', label = 'Bag', kind = 'component', id = 5, off = 0, icon = 'bag' },
{ key = 'chain', label = 'Chain', kind = 'component', id = 7, off = 0, icon = 'chain' },
{ key = 'watch', label = 'Watch', kind = 'prop', id = 6, icon = 'watch' },
{ key = 'bracelet', label = 'Brace', kind = 'prop', id = 7, icon = 'bracelet' },
},
-- Body regions on the silhouette, mapped to the ambulance BodyParts keys
-- that feed each one. Highest severity among the listed parts wins.
BodyRegions = {
{ key = 'head', label = 'Head', parts = { 'HEAD', 'NECK' } },
{ key = 'chest', label = 'Chest', parts = { 'SPINE', 'UPPER_BODY' } },
{ key = 'stomach', label = 'Stomach', parts = { 'LOWER_BODY' } },
{ key = 'leftArm', label = 'Left Arm', parts = { 'LARM', 'LHAND', 'LFINGER' } },
{ key = 'rightArm', label = 'Right Arm', parts = { 'RARM', 'RHAND', 'RFINGER' } },
{ key = 'leftLeg', label = 'Left Leg', parts = { 'LLEG', 'LFOOT' } },
{ key = 'rightLeg', label = 'Right Leg', parts = { 'RLEG', 'RFOOT' } },
},
},
WeaponPreview = {
Base = {
distance = 2.7,
height = 0.9,
side = 0.0,
fov = 47.0,
},
Groups = {
pistol = { distance = 2.6, height = 0.88, fov = 45.0 },
smg = { distance = 2.8, height = 0.95, fov = 48.0 },
long = { distance = 3.1, height = 1.05, fov = 51.0 },
heavy = { distance = 3.4, height = 1.1, fov = 54.0 },
},
Offsets = {
distance = 0.0,
height = 0.0,
side = 0.0,
fov = 0.0,
},
Smooth = {
enter = 350,
exit = 600,
},
},
-- Once Human-style character stage: while the inventory is open, a scripted
-- camera frames your ped front-and-centre between the two panels.
-- IDLE ONLY: the camera activates only when standing still on foot — while
-- running / driving / fighting the inventory opens with no camera change.
InventoryCam = {
-- Disabled: the inventory no longer reframes the ped on open.
enabled = false,
distance = 2.6, -- metres in front of the ped
height = 0.45, -- camera height above the ped origin
side = 0.0, -- sideways offset (+right / -left)
fov = 40.0,
enter = 400, -- ms blend in
exit = 400, -- ms blend out
},
-- Weapons slung on the player's back are drawn as real weapon objects, so
-- whatever is fitted to the gun in the inventory -- scope, suppressor, grip,
-- extended clip -- and whatever tint is applied to it show on the back too.
-- Entities are local to each client and driven by a replicated statebag, so
-- back items cost nothing on the networked entity budget. See
-- client/backitems.lua for the full rationale.
BackItems = {
enabled = true,
-- Performance knobs. Nothing here polls inventories: content updates
-- arrive through events, and these only govern how often the renderer
-- checks who is standing nearby.
renderDistance = 30.0, -- metres; a gun on a back is not readable past this
maxRenderedPlayers = 12, -- hard cap so a crowded street cannot balloon
streamInterval = 1500, -- ms between attach/detach sweeps
publishInterval = 500, -- ms between checks of our own weapon/vehicle state
refreshDebounce = 250, -- ms to coalesce a burst of inventory updates
tuner = true, -- enables /backitemtune (see below)
hideInVehicle = true,
-- Clean weapons-only back: only guns show, filling the two prime
-- upper-back slots. Small utility items never clutter it. To allow
-- bulky gear (armor/parachute) below the guns, set maxItems = 1.
maxDisplayed = 2,
maxWeapons = 2,
maxItems = 0,
weaponSlots = { 1, 2 },
itemSlots = { 3, 4 },
-- IMPORTANT -- how these offsets actually work.
--
-- A spine bone's local axes are NOT world axes. On SKEL_Spine1 (24816):
--
-- offset.x = ALONG the spine (+ up towards the head)
-- offset.y = DEPTH (- out behind the back)
-- offset.z = ACROSS the back (+/- to either side)
--
-- This is what the old values got wrong: they separated the two weapon
-- slots with x = +0.19 / -0.19 expecting a side-by-side pair, and instead
-- put one gun 38 cm higher up the spine than the other -- one literally
-- stacked on top of the other, with the upper one clipping through the
-- head. Two guns are separated on Z, not on X.
--
-- The values below follow the placement every established weapons-on-back
-- script converges on: bone 24816 (SKEL_Spine1, low enough that upper-body
-- animation does not swing the gun around), lifted ~0.22 up the spine,
-- ~0.18 out behind the back, and rotated ~170 on Y so the weapon hangs
-- muzzle-down along the back rather than standing upright.
--
-- TGIANN weapons-on-back : 24816, (0.285, -0.17, 0.13/0.0/-0.13), (0, 170, 0)
-- qb-weaponsonback : 24816, (0.2275, -0.16, 0.016), (0, 0, 1)
-- OneWithoutAName : 24816, (0.15, -0.18, -0.02), (0, 165, 0)
--
-- Fine-tune with /backitemtune <slot> in game; it prints a ready-to-paste
-- line to the F8 console.
Slots = {
[1] = { bone = 24816, offset = vector3(0.22, -0.175, 0.105), rotation = vector3(0.0, 170.0, 0.0) },
[2] = { bone = 24816, offset = vector3(0.22, -0.195, -0.105), rotation = vector3(0.0, 170.0, 0.0) },
[3] = { bone = 24816, offset = vector3(0.16, -0.135, 0.0), rotation = vector3(0.0, 178.0, 0.0) },
[4] = { bone = 24816, offset = vector3(0.02, -0.15, 0.155), rotation = vector3(0.0, 100.0, 0.0) },
},
MaleSlots = {
[1] = { bone = 24816, offset = vector3(0.22, -0.175, 0.105), rotation = vector3(0.0, 170.0, 0.0) },
[2] = { bone = 24816, offset = vector3(0.22, -0.195, -0.105), rotation = vector3(0.0, 170.0, 0.0) },
[3] = { bone = 24816, offset = vector3(0.16, -0.135, 0.0), rotation = vector3(0.0, 178.0, 0.0) },
[4] = { bone = 24816, offset = vector3(0.02, -0.15, 0.155), rotation = vector3(0.0, 100.0, 0.0) },
},
-- Female peds have a shorter, slimmer torso: the same placement sits a
-- little lower on the spine and a little closer in on the depth axis.
FemaleSlots = {
[1] = { bone = 24816, offset = vector3(0.21, -0.155, 0.10), rotation = vector3(0.0, 170.0, 0.0) },
[2] = { bone = 24816, offset = vector3(0.21, -0.175, -0.10), rotation = vector3(0.0, 170.0, 0.0) },
[3] = { bone = 24816, offset = vector3(0.15, -0.12, 0.0), rotation = vector3(0.0, 178.0, 0.0) },
[4] = { bone = 24816, offset = vector3(0.02, -0.135, 0.145), rotation = vector3(0.0, 100.0, 0.0) },
},
-- A micro SMG and a heavy sniper differ by half a metre in length but
-- share one slot transform, so one rides up at the neck and the other
-- drags its muzzle through the legs. These corrections are ADDED to the
-- slot transform, per weapon size class, and are mostly on X -- the
-- along-the-spine axis -- so a longer gun is carried a little higher.
-- A per-weapon offset/rotation in the Weapons table below overrides the
-- slot outright and skips the class entirely.
--
-- Melee is the exception: a bat or a machete is slung low and diagonally,
-- not hung vertically like a rifle, so its correction is large. The
-- posture is taken from OneWithoutAName's weapons-on-back, which special
-- cases melee to (-0.40, -0.15, 0.0) / (-75, 185, 92) on the same bone.
Classes = {
rifle = { offset = vector3(0.0, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
sniper = { offset = vector3(0.03, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
shotgun = { offset = vector3(0.01, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
mg = { offset = vector3(0.02, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
heavy = { offset = vector3(0.04, -0.01, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
smg = { offset = vector3(-0.03, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
pistol = { offset = vector3(-0.06, 0.02, 0.0), rotation = vector3(0.0, 0.0, 0.0) },
melee = { offset = vector3(-0.55, 0.03, 0.0), rotation = vector3(-75.0, 20.0, 92.0) },
},
-- Weapons whose real size does not match their engine group. Anything
-- not listed here is classified automatically from GetWeapontypeGroup.
ClassOf = {
weapon_compactrifle = 'smg',
weapon_sawnoffshotgun = 'smg',
weapon_dbshotgun = 'smg',
weapon_machinepistol = 'pistol',
weapon_minismg = 'pistol',
},
-- Higher number = shown first and given the prime (upper-back) slots.
-- Tiers keep BIG guns on top, then bulky items, then small utility items.
-- Anything not listed here falls back to a size-based default (big guns
-- 800 / pistols 500 / melee 300 / bulky items 250 / small items 100).
Priority = {
-- Tier 1: big guns (always prioritized on the back)
weapon_carbinerifle = 1000,
weapon_assaultrifle = 990,
weapon_specialcarbine = 985,
weapon_bullpuprifle = 980,
weapon_advancedrifle = 975,
weapon_heavyrifle = 973,
weapon_militaryrifle = 972,
weapon_tacticalrifle = 971,
weapon_heavysniper = 970,
weapon_sniperrifle = 965,
weapon_marksmanrifle = 960,
weapon_precisionrifle = 958,
weapon_pumpshotgun = 950,
weapon_assaultshotgun = 945,
weapon_combatshotgun = 943,
weapon_heavyshotgun = 941,
weapon_bullpupshotgun = 940,
weapon_gusenberg = 935,
weapon_combatmg = 932,
weapon_mg = 930,
weapon_assaultsmg = 925,
weapon_combatpdw = 920,
weapon_smg = 915,
weapon_microsmg = 905,
-- Tier 2: bulky items
heavyarmor = 280,
armor = 275,
parachute = 270,
drill = 265,
police_stormram = 260,
goldbar = 255,
-- Tier 3: small utility items (always last on the back)
thermite = 130,
trojan_usb = 125,
radio = 120,
handcuffs = 110,
lockpick = 100,
advancedlockpick = 95,
},
blockedWeapons = {
weapon_unarmed = true,
weapon_petrolcan = true,
weapon_fireextinguisher = true,
weapon_stungun = true,
weapon_snowball = true,
weapon_ball = true,
weapon_smokegrenade = true,
weapon_flare = true,
weapon_bzgas = true,
weapon_molotov = true,
weapon_stickybomb = true,
weapon_pipebomb = true,
weapon_grenade = true,
weapon_proxmine = true,
},
-- Allow-list of weapons that may appear on the back. `model` is no
-- longer used for weapons (the gun is built from the weapon hash so it
-- keeps its components and tint) and is kept only as documentation.
-- `slot` pins an entry to one back slot; `offset` / `rotation` override
-- the slot transform outright for that one weapon.
Weapons = {
weapon_assaultrifle = { model = `w_ar_assaultrifle` },
weapon_carbinerifle = { model = `w_ar_carbinerifle` },
weapon_advancedrifle = { model = `w_ar_advancedrifle` },
weapon_specialcarbine = { model = `w_ar_specialcarbine` },
weapon_bullpuprifle = { model = `w_ar_bullpuprifle` },
weapon_heavyrifle = { model = `w_ar_heavyrifle` },
weapon_militaryrifle = { model = `w_ar_militaryrifle` },
weapon_tacticalrifle = { model = `w_ar_tacticalrifle` },
weapon_musket = { model = `w_ar_musket` },
weapon_compactrifle = { model = `w_ar_assaultrifle_smg` },
weapon_sniperrifle = { model = `w_sr_sniperrifle` },
weapon_heavysniper = { model = `w_sr_heavysniper` },
weapon_marksmanrifle = { model = `w_sr_marksmanrifle` },
weapon_precisionrifle = { model = `w_sr_precisionrifle` },
weapon_pumpshotgun = { model = `w_sg_pumpshotgun` },
weapon_sawnoffshotgun = { model = `w_sg_sawnoff` },
weapon_bullpupshotgun = { model = `w_sg_bullpupshotgun` },
weapon_assaultshotgun = { model = `w_sg_assaultshotgun` },
weapon_combatshotgun = { model = `w_sg_combatshotgun` },
weapon_heavyshotgun = { model = `w_sg_heavyshotgun` },
weapon_dbshotgun = { model = `w_sg_doublebarrel` },
weapon_microsmg = { model = `w_sb_microsmg` },
weapon_smg = { model = `w_sb_smg` },
weapon_assaultsmg = { model = `w_sb_assaultsmg` },
weapon_combatpdw = { model = `w_sb_pdw` },
weapon_gusenberg = { model = `w_sb_gusenberg` },
weapon_mg = { model = `w_mg_mg` },
weapon_combatmg = { model = `w_mg_combatmg` },
weapon_bat = { model = `w_me_bat`, slot = 2 },
weapon_crowbar = { model = `w_me_crowbar`, slot = 2 },
weapon_golfclub = { model = `w_me_gclub`, slot = 2 },
weapon_machete = { model = `w_me_machette_lr`, slot = 2 },
},
-- Non-weapon gear. These stay ordinary props: they have no components
-- and no tint palette, so there is nothing a weapon object would add.
Items = {
radio = { model = `prop_cs_hand_radio`, slot = 4 },
armor = { model = `prop_armour_pickup`, slot = 3 },
heavyarmor = { model = `prop_armour_pickup`, slot = 3 },
handcuffs = { model = `prop_cs_cuffs_01`, slot = 4 },
binoculars = { model = `prop_binoc_01`, slot = 4 },
parachute = { model = `p_parachute1_mp_s`, slot = 3, rotation = vector3(0.0, 90.0, 90.0) },
laptop = { model = `prop_laptop_lester2`, slot = 3 },
lockpick = { model = `prop_tool_screwdvr03`, slot = 4 },
advancedlockpick = { model = `prop_tool_screwdvr03`, slot = 4 },
electronickit = { model = `prop_cs_tablet`, slot = 4 },
thermite = { model = `hei_prop_heist_thermite`, slot = 4 },
trojan_usb = { model = `prop_cs_usb_drive`, slot = 4 },
drill = { model = `hei_prop_heist_drill`, slot = 3 },
tunerlaptop = { model = `prop_laptop_lester2`, slot = 3 },
radioscanner = { model = `prop_paper_bag_small`, slot = 4 },
police_stormram = { model = `prop_batteringram`, slot = 3 },
goldbar = { model = `hei_prop_heist_gold_bar`, slot = 3 },
markedbills = { model = `prop_money_bag_01`, slot = 4 },
cokebaggy = { model = `bkr_prop_meth_smallbag_01a`, slot = 4 },
weed_brick = { model = `bkr_prop_weed_drying_01a`, slot = 3 },
},
},
-- Equip slots (Gadget/Phone/Backpack/Armor/Radio) and backpack contents live
-- in reserved slot-number ranges above Config.MaxSlots. They are ordinary
-- player-inventory slots on the wire — reserving a numeric range is what
-- makes them real and persistent with no schema change. AddItem() must not
-- clamp them back into the visible grid, so keep these in sync with
-- SPECIAL_SLOT_BASE / BACKPACK_CONTENTS_BASE in nui/src/types.ts.
SpecialSlots = {
base = 9000,
count = 6,
backpackBase = 9100,
backpackMax = 60,
-- SIM bays on the phone. A handset needs at least one SIM fitted
-- before qb-phone will open, and a second bay allows a burner.
simBase = 9200,
simCount = 2,
simItems = { 'sim_card' },
},
-- Plate carriers use five readable protection levels. A fresh carrier
-- includes one plate; loose plates raise it one level at a time. Damage
-- can partially wear the active plate and that condition persists on the
-- unique carrier item when it is removed or stored.
Armor = {
sockets = 5,
plateInstallTime = 3500,
carrierEquipTime = 3000,
carriers = {
armor = { capacity = 75, startingDurability = 20 },
heavyarmor = { capacity = 100, startingDurability = 20 },
},
},
-- Hybrid crafting. Small field recipes remain available from ordinary
-- inventory; advanced recipes require a validated physical workbench.
-- Every recipe and access mode is enforced server-side.
Crafting = {
QueueSize = 3,
-- Hard server cap. The UI sizes the batch field from this value, so
-- three-digit quantities remain centered and readable.
MaxBatch = 999,
Personal = {
key = 'personal',
label = 'Field Crafting',
description = 'Quick assembly of simple supplies that needs no installed workbench.',
},
-- Merge recipes from the currently active qb-crafting bench into this
-- inventory's Crafting tab. XP requirements and rewards are retained.
IntegrateQbCrafting = true,
QbCraftingResource = 'qb-crafting',
DifficultySeconds = { easy = 6, medium = 10, hard = 14, expert = 20 },
Recipes = {
-- Supplemental utility recipes. Core workbench products live in
-- qb-crafting so they appear once with one authoritative cost.
{ key = 'cleaningkit', item = 'cleaningkit', amount = 1, category = 'Field Supplies', bench = 'personal', seconds = 6,
ingredients = { { item = 'plastic', amount = 6 }, { item = 'rubber', amount = 4 } } },
-- Bench tools
{ key = 'advancedlockpick', item = 'advancedlockpick', amount = 1, category = 'Tools', bench = 'item_bench', seconds = 12,
ingredients = { { item = 'lockpick', amount = 2 }, { item = 'steel', amount = 5 }, { item = 'electronickit', amount = 1 } } },
-- Simple medical assembly can be done in the field. Sterile and
-- specialist equipment still requires the utility workbench.
{ key = 'bandage', item = 'bandage', amount = 2, category = 'Field Medical', bench = 'personal', seconds = 5,
ingredients = { { item = 'plastic', amount = 2 }, { item = 'rubber', amount = 2 } } },
{ key = 'medkit', item = 'medkit', amount = 1, category = 'Field Medical', bench = 'personal', seconds = 10,
ingredients = { { item = 'bandage', amount = 4 }, { item = 'plastic', amount = 4 } } },
{ key = 'suturekit', item = 'suturekit', amount = 1, category = 'Medical', bench = 'item_bench', seconds = 9,
ingredients = { { item = 'bandage', amount = 2 }, { item = 'aluminum', amount = 4 } } },
-- Constructed gear requires the utility workbench.
{ key = 'backpack_small', item = 'backpack_small', amount = 1, category = 'Gear', bench = 'item_bench', seconds = 12,
ingredients = { { item = 'rubber', amount = 8 }, { item = 'plastic', amount = 6 }, { item = 'aluminum', amount = 4 } } },
{ key = 'backpack_medium', item = 'backpack_medium', amount = 1, category = 'Gear', bench = 'item_bench', seconds = 20,
ingredients = { { item = 'backpack_small', amount = 1 }, { item = 'rubber', amount = 10 }, { item = 'steel', amount = 6 } } },
{ key = 'backpack_large', item = 'backpack_large', amount = 1, category = 'Gear', bench = 'item_bench', seconds = 30,
ingredients = { { item = 'backpack_medium', amount = 1 }, { item = 'steel', amount = 12 }, { item = 'aluminum', amount = 10 } } },
},
},
-- ── Experience / progression ────────────────────────────────────────
-- Stored on the player's QBCore metadata (`metadata.experience`), so there
-- is no schema change and it survives across sessions like any other
-- character data. A category's level is derived from the sum of its
-- tracks, so working any skill under it advances the parent too.
Experience = {
enabled = true,
maxLevel = 20,
-- XP to go from level n to n+1 is base * growth^(n-1).
curve = { base = 120, growth = 1.24 },
-- Per-track daily ceiling; 0 disables the cap.
dailyCap = 2500,
notifyLevelUp = true,
-- Tracks whose XP and level ladder are owned by another resource. The
-- inventory mirrors them for display only: it takes their levels from
-- the owner's own ladder and never awards XP, applies the daily cap or
-- pays milestone rewards on them. See server/experience.lua.
externalTracks = {
farming = { resource = 'lumo-farming', profile = 'GetFarmerProfile', ladder = 'GetExperienceLadder' },
},
-- These disciplines intentionally mirror resources enabled by this
-- server.cfg. Disabled PRP fishing tracks are not advertised; Farming
-- is lumo-farming's own progression, mirrored via externalTracks.
categories = {
{ key = 'agriculture', label = 'Agriculture', icon = 'AG', tracks = {
{ key = 'farming', label = 'Farming', icon = 'FM' },
} },
{ key = 'enterprise', label = 'Enterprise', icon = 'EN', tracks = {
{ key = 'vineyard', label = 'Vineyard', icon = 'VY' },
{ key = 'business', label = 'Business', icon = 'BZ' },
} },
{ key = 'exploration', label = 'Exploration', icon = 'EX', tracks = {
{ key = 'diving', label = 'Deep Sea Diving', icon = 'DV' },
} },
{ key = 'outlaw', label = 'Outlaw', icon = 'OL', tracks = {
{ key = 'narcotics', label = 'Narcotics', icon = 'NC' },
{ key = 'robbery', label = 'Street Robbery', icon = 'RB' },
{ key = 'house_robbery', label = 'House Robbery', icon = 'HR' },
{ key = 'heists', label = 'Major Heists', icon = 'HS' },
{ key = 'chopping', label = 'Vehicle Chopping', icon = 'CH' },
{ key = 'racing', label = 'Street Racing', icon = 'SR' },
} },
{ key = 'trades', label = 'Skilled Trades', icon = 'TR', tracks = {
{ key = 'crafting', label = 'Fabrication', icon = 'CR' },
{ key = 'gunsmithing', label = 'Gunsmithing', icon = 'GS' },
{ key = 'mechanic', label = 'Mechanic', icon = 'MC' },
{ key = 'recycling', label = 'Recycling', icon = 'RC' },
} },
{ key = 'services', label = 'Public Services', icon = 'SV', tracks = {
{ key = 'police', label = 'Police Service', icon = 'PD' },
{ key = 'ems', label = 'Emergency Medical', icon = 'EM' },
{ key = 'taxi', label = 'Taxi Driver', icon = 'TX' },
{ key = 'towing', label = 'Tow Operator', icon = 'TW' },
{ key = 'sanitation', label = 'Sanitation', icon = 'SN' },
} },
},
-- One-time, per-character import from the retired standalone
-- player_reputation table. Values are merged into these tracks without
-- consuming the daily XP cap, then a metadata marker prevents repeats.
legacyImport = {
enabled = true,
marker = 'playerReputationV1',
tracks = {
racing = 'racing',
heists = 'heists',
mechanic = 'mechanic',
ems = 'ems',
police = 'police',
},
},
rankTitles = {
'Rookie', 'Trainee', 'Runner', 'Operator', 'Journeyman',
'Specialist', 'Adept', 'Veteran', 'Expert', 'Professional',
'Master', 'Elite', 'Mythic', 'Legendary', 'Renowned',
'Distinguished', 'Premier', 'Exalted', 'Icon', 'Pinnacle',
},
-- Perks unlocked by track level. Read by other resources through the
-- GetExperienceLevel export; lumo-inventory itself uses `craftSpeed`.
perks = {
house_robbery = {
{ level = 3, label = 'Practiced Search: 10% faster', effect = 'searchSpeed', value = 0.10 },
{ level = 6, label = 'Eye for Electronics: +10% bulky finds', effect = 'bulkyChance', value = 10 },
{ level = 10, label = 'Expert Search: 25% faster', effect = 'searchSpeed', value = 0.25 },
},
crafting = {
{ level = 3, label = 'Steady Hands', effect = 'craftSpeed', value = 0.10 },
{ level = 6, label = 'Efficient Bench', effect = 'craftSpeed', value = 0.20 },
{ level = 10, label = 'Master Fabricator', effect = 'craftSpeed', value = 0.35 },
{ level = 15, label = 'Assembly Line', effect = 'craftSpeed', value = 0.50 },
},
gunsmithing = {
{ level = 4, label = 'Component Familiarity', effect = 'gunsmithAccess', value = 1 },
{ level = 8, label = 'Precision Machining', effect = 'gunsmithAccess', value = 2 },
{ level = 12, label = 'Advanced Optics', effect = 'gunsmithAccess', value = 3 },
{ level = 16, label = 'Master Armorer', effect = 'gunsmithAccess', value = 4 },
},
mechanic = {
{ level = 5, label = 'Efficient Diagnosis', effect = 'mechanicEfficiency', value = 0.05 },
{ level = 10, label = 'Senior Technician', effect = 'mechanicEfficiency', value = 0.10 },
{ level = 15, label = 'Master Technician', effect = 'mechanicEfficiency', value = 0.15 },
},
diving = {
{ level = 5, label = 'Experienced Diver', effect = 'divingYield', value = 0.05 },
{ level = 10, label = 'Salvage Expert', effect = 'divingYield', value = 0.10 },
{ level = 15, label = 'Deep Sea Veteran', effect = 'divingYield', value = 0.15 },
},
},
-- Every track pays modest cash milestones; selected tracks substitute
-- useful RP items at levels 6 and 15. All rewards are one-time claims,
-- persisted in metadata and validated on the server.
rewards = {
defaults = {
[3] = { type = 'cash', amount = 250, label = '$250 cash' },
[10] = { type = 'bank', amount = 1000, label = '$1,000 bank deposit' },
[20] = { type = 'cash', amount = 3500, label = '$3,500 mastery bonus' },
},
tracks = {
vineyard = { [6] = { type = 'item', item = 'grapejuice', amount = 5 }, [15] = { type = 'item', item = 'wine', amount = 4 } },
business = { [6] = { type = 'item', item = 'radio', amount = 1 }, [15] = { type = 'bank', amount = 1800 } },
diving = { [6] = { type = 'item', item = 'diving_fill', amount = 2 }, [15] = { type = 'item', item = 'diving_gear', amount = 1 } },
narcotics = { [6] = { type = 'item', item = 'rolling_paper', amount = 20 }, [15] = { type = 'item', item = 'empty_weed_bag', amount = 20 } },
house_robbery = { [3] = { type = 'item', item = 'lockpick', amount = 2 }, [6] = { type = 'item', item = 'advancedlockpick', amount = 1 }, [10] = { type = 'bank', amount = 1500 }, [15] = { type = 'item', item = 'advancedlockpick', amount = 3 } },
robbery = { [6] = { type = 'item', item = 'lockpick', amount = 2 }, [15] = { type = 'item', item = 'advancedlockpick', amount = 1 } },
heists = { [6] = { type = 'item', item = 'electronickit', amount = 1 }, [15] = { type = 'item', item = 'thermite', amount = 1 } },
chopping = { [6] = { type = 'item', item = 'repairkit', amount = 1 }, [15] = { type = 'item', item = 'advancedrepairkit', amount = 1 } },
crafting = { [6] = { type = 'item', item = 'screwdriverset', amount = 1 }, [15] = { type = 'item', item = 'precision_toolkit', amount = 1 } },
gunsmithing = { [6] = { type = 'item', item = 'flashlight_attachment', amount = 1 }, [15] = { type = 'item', item = 'barrel_attachment', amount = 1 } },
mechanic = { [6] = { type = 'item', item = 'repairkit', amount = 2 }, [15] = { type = 'item', item = 'advancedrepairkit', amount = 2 } },
recycling = { [6] = { type = 'item', item = 'metalscrap', amount = 40 }, [15] = { type = 'item', item = 'steel', amount = 30 } },
taxi = { [6] = { type = 'cash', amount = 600 }, [15] = { type = 'bank', amount = 1800 } },
towing = { [6] = { type = 'item', item = 'repairkit', amount = 1 }, [15] = { type = 'bank', amount = 1800 } },
sanitation = { [6] = { type = 'cash', amount = 600 }, [15] = { type = 'item', item = 'cryptostick', amount = 1 } },
},
},
-- Picking an item up is the signal. lumo-inventory sees every item that
-- enters a player's inventory, so mapping item -> track awards XP for
-- farming, fishing, mining and so on without touching those resources.
itemXp = {
-- Enterprise / exploration
grape = { track = 'vineyard', xp = 3 },
grapejuice = { track = 'vineyard', xp = 5 },
wine = { track = 'vineyard', xp = 7 },
coral = { track = 'diving', xp = 8 },
coral_piece = { track = 'diving', xp = 8 },
goldchain = { track = 'diving', xp = 10 },
-- Outlaw
coke = { track = 'narcotics', xp = 5 },
cutted_coke = { track = 'narcotics', xp = 6 },
coke_brick = { track = 'narcotics', xp = 25 },
meth = { track = 'narcotics', xp = 5 },
markedbills = { track = 'robbery', xp = 10 },
goldbar = { track = 'heists', xp = 30 },
diamond = { track = 'heists', xp = 25 },
rolex = { track = 'robbery', xp = 8 },
stolen_bag = { track = 'robbery', xp = 10 },
-- Trades
metalscrap = { track = 'recycling', xp = 1 },
iron = { track = 'recycling', xp = 2 },
copper = { track = 'recycling', xp = 2 },
steel = { track = 'recycling', xp = 3 },
aluminum = { track = 'recycling', xp = 2 },
glass = { track = 'recycling', xp = 1 },
},
-- AddItem reasons let one item map differently depending on the actual
-- resource that produced it (for example marked bills from a drug run
-- versus a bank robbery). First matching prefix wins.
reasonXp = {
{ prefix = 'qb-diving:', track = 'diving', xp = 8 },
{ prefix = 'qb-vineyard:', track = 'vineyard', xp = 5 },
{ prefix = 'qb-drugs:', track = 'narcotics', xp = 7 },
{ prefix = 'qb-storerobbery:', track = 'robbery', xp = 10 },
{ prefix = 'qb-houserobbery:', track = 'robbery', xp = 10 },
{ prefix = 'qb-jewellery:', track = 'heists', xp = 14 },
{ prefix = 'qb-bankrobbery:', track = 'heists', xp = 18 },
{ prefix = 'qb-truckrobbery:', track = 'heists', xp = 16 },
{ prefix = 'qb-heist-reward', track = 'heists', xp = 20 },
-- Lumo OS boosting. Deliberately specific rather than a blanket
-- 'lumo-boosting' prefix: the same resource also hands over bought
-- tablets and trade-ins, and buying your own equipment is not a
-- skill. Only loot pulled out of a contract vehicle counts.
{ prefix = 'lumo-boosting-glovebox', track = 'chopping', xp = 6 },
{ prefix = 'lumo-boosting-market', track = 'chopping', xp = 2 },
{ prefix = 'qb-scrapyard:server:IllegalChop', track = 'chopping', xp = 10 },
{ prefix = 'qb-scrapyard:', track = 'recycling', xp = 4 },
{ prefix = 'qb-recyclejob:', track = 'recycling', xp = 4 },
{ prefix = 'qb-taxi:', track = 'taxi', xp = 8 },
{ prefix = 'qb-tow:', track = 'towing', xp = 8 },
{ prefix = 'qb-garbagejob:', track = 'sanitation', xp = 8 },
},
-- XP for actions lumo-inventory performs itself.
actionXp = {
craft = { track = 'crafting', xp = 12 },
gunsmith = { track = 'gunsmithing', xp = 16 },
},
},
StashSize = {
maxweight = 2000000,
slots = 100
},
DropSize = {
maxweight = 1000000,
slots = 50
},
-- How close you must stand to a dropped bag for the inventory key to open
-- it as the right-hand pane. Server-side openDrop still enforces 2.5.
DropOpenDistance = 2.5,
Keybinds = {
Open = 'TAB',
Hotbar = 'Z',
},
CleanupDropTime = 15, -- in minutes
CleanupDropInterval = 1, -- in minutes
-- Kept for compatibility with resources that read the old setting. The
-- drop system below now chooses a model per item and uses a small paper
-- bag for everything without an explicit, reliable GTA V prop.
ItemDropObject = `prop_paper_bag_small`,
ItemDropObjectBone = 28422,
ItemDropObjectOffset = {
vector3(0.260000, 0.040000, 0.000000),
vector3(90.000000, 0.000000, -78.989998),
},
-- New acquisitions may land on the ground; transfers still require room.
Overflow = { enabled = true, maxDropsPerPlayer = 12 },
GiveSelection = { distance = 3.0, timeout = 30000, refreshInterval = 250 },
-- The give hand-off. Both players turn to face each other and the item's
-- own prop (its DropSystem model) passes from the giver's right hand to
-- the receiver's. Everyone within broadcastDistance sees it.
GiveAnimation = {
enabled = true,
showProp = true,
broadcastDistance = 40.0,
turnTime = 350, -- ms spent turning to face before the animations start
giver = { dict = 'mp_common', anim = 'givetake1_a', duration = 2000, flags = 48 },
receiver = { dict = 'mp_common', anim = 'givetake1_b', duration = 2000, flags = 48 },
handoffAt = 950, -- ms after the animations start
pocketAt = 1750, -- the receiver puts it away
},
DropSystem = {
enabled = true,
fallbackModel = 'prop_paper_bag_small',
interactDistance = 2.5,
createTimeout = 5000,
-- One networked object is used for the ground item, carrying and the
-- throw. There are no decorative duplicates or per-frame proximity
-- scans; OneSync streaming and qb-target handle visibility/interact.
throwing = {
enabled = true,
-- A hidden stock snowball weapon supplies GTA's native throwable
-- aim camera, locomotion and release animation. The spawned dummy
-- projectile is removed and the real item prop takes its place.
nativeAimWeapon = 'WEAPON_SNOWBALL',
speed = 13.0,
upwardBoost = 2.1,
vehicleVelocityScale = 0.75,
vehicleCollisionGrace = 650,
settleTimeout = 8000,
settleSpeed = 0.22,
maxServerDistance = 25.0,
impactDamage = 5,
impactRadius = 1.15,
-- End-over-end tumble in rad/s, so a thrown bottle turns over in
-- the air instead of gliding flat. Sizes and items can override it.
spin = 6.0,
-- A stack at least this heavy in total (grams) throws as `heavy`
-- when its entry does not name a size.
heavyWeight = 4000,
},
placement = {
enabled = true,
maxDistance = 8.0,
alpha = 170,
rotateStep = 15.0,
fineRotateStep = 1.0,
heightStep = 0.05,
maxHeightAdjust = 2.0,
},
animations = {
pickup = { dict = 'pickup_object', anim = 'pickup_low', duration = 850, releaseAt = 450, flags = 48 },
place = { dict = 'pickup_object', anim = 'putdown_low', duration = 850, releaseAt = 430, flags = 48 },
-- Drop from the inventory: the item rides the hand and is let go at releaseAt.
drop = { dict = 'pickup_object', anim = 'putdown_low', duration = 850, releaseAt = 430, flags = 48 },
-- Two-handed toss for `bulky` items, which have no aim camera.
toss = { dict = 'anim@heists@narcotics@trash', anim = 'throw_b', duration = 1200, releaseAt = 650, flags = 48 },
},
-- Transform used while the object is in the right hand. Individual
-- entries can override this when a model needs a different grip.
hold = {
bone = 57005, -- SKEL_R_Hand
offset = vector3(0.12, 0.02, -0.02),
rotation = vector3(-90.0, 0.0, 15.0),
},
-- How an item is carried and thrown. An entry picks one with `size`;
-- anything unsized is `small`, or `heavy` past throwing.heavyWeight.
-- small one hand, native aim camera, full throw
-- heavy one hand, native aim camera, a shorter, flatter throw
-- bulky both arms (box carry), no sprint/jump, a short two-handed toss
-- `hold` is the grip for the whole size; an item's own `hold` wins.
Sizes = {
small = {},
heavy = { throw = { speed = 8.5, upwardBoost = 2.4, spin = 2.5 } },
bulky = {
carry = 'box',
anim = { dict = 'anim@heists@box_carry@', anim = 'idle', flags = 49 },
hold = { bone = 60309, offset = vector3(0.025, 0.08, 0.255), rotation = vector3(-145.0, 290.0, 0.0) },
throw = { speed = 4.5, upwardBoost = 2.6, spin = 1.2 },
},
},
-- Set true to get /dropgrip while holding an item: it re-attaches the
-- prop with the offsets you type and prints a ready-made Items line.
gripTuning = false,
-- Exact item names win. Models are stock GTA V (server.cfg enforces game
-- build 3751), except farm produce, which uses lumo-farming's stream.
-- model object used on the ground, in the hand and in a give
-- size 'small' | 'heavy' | 'bulky' (see Sizes)
-- hold grip override { bone, offset, rotation }
-- carry bulky only: { bone, offset, rotation } while it is carried in
-- the arms; unset = the two-hand box grip. Easier: carry it
-- and use /carrygrip, which saves in game for everyone.
-- throw { speed, upwardBoost, spin } override
-- amounts { { min = n, model = '...' }, ... } a bigger stack, a bigger prop
-- If this game build lacks a model, the first client to log in reports
-- it, the server console lists it and that item uses fallbackModel.
Items = {
-- Drinks
water_bottle = { model = 'prop_ld_flow_bottle' },
water = { model = 'prop_ld_flow_bottle' },
tap_water = { model = 'prop_ld_flow_bottle' },
kurkakola = { model = 'prop_ecola_can' },
cola = { model = 'prop_ecola_can' },
soda_can = { model = 'prop_ld_can_01' },
energy_drink = { model = 'prop_energy_drink' },
coffee = { model = 'p_amb_coffeecup_01' },
chiya = { model = 'p_ing_coffeecup_01' },
lassi = { model = 'prop_plastic_cup_02' },
milk = { model = 'prop_cs_milk_01' },
lumo_farm_milk = { model = 'prop_cs_milk_01' },
grapejuice = { model = 'prop_food_bs_juice01' },
beer = { model = 'prop_amb_beer_bottle' },
beer_bottle = { model = 'prop_cs_beer_bot_01' },
wine = { model = 'prop_wine_bot_01' },
whiskey = { model = 'prop_whiskey_bottle' },
whiskey_bottle = { model = 'prop_whiskey_bottle' },
luxury_whiskey = { model = 'p_whiskey_bottle_s' },
vodka = { model = 'prop_vodka_bottle' },
vodka_bottle = { model = 'prop_vodka_bottle' },
moonshine = { model = 'prop_ceramic_jug_cork' },
moonshine_pack = { model = 'sf_prop_sf_crate_jugs_01a', size = 'bulky' },
moonshine_still = { model = 'prop_still', size = 'bulky' },
-- Food
sandwich = { model = 'prop_sandwich_01' },
tosti = { model = 'prop_sandwich_01' },
toast = { model = 'prop_sandwich_01' },
burger = { model = 'prop_cs_burger_01' },
hotdog = { model = 'prop_cs_hotdog_01' },
sausage = { model = 'prop_cs_hotdog_02' },
taco = { model = 'prop_taco_01' },
donut = { model = 'prop_amb_donut' },
fries = { model = 'prop_food_bs_chips' },
chickenwrap = { model = 'prop_food_cb_bag_01' },
samosa = { model = 'prop_food_cb_bag_01' },
sel_roti = { model = 'prop_food_bs_bag_01' },
sukuti = { model = 'prop_food_bs_bag_01' },
fish_chips = { model = 'prop_food_bs_tray_02' },
chicken_meal = { model = 'prop_food_cb_tray_02' },
pizza = { model = 'prop_pizza_box_02' },
pizza_slice = { model = 'prop_cs_plate_01' },
steak = { model = 'prop_cs_steak' },
meat = { model = 'prop_cs_steak' },
chicken = { model = 'prop_cs_steak' },
fish = { model = 'prop_fish_slice_01' },
luxury_dinner = { model = 'prop_cs_plate_01' },
omelette = { model = 'prop_cs_plate_01' },
pasta_plate = { model = 'prop_cs_plate_01' },
dal_bhat = { model = 'prop_cs_plate_01' },
momo = { model = 'prop_cs_plate_01' },
chatamari = { model = 'prop_cs_plate_01' },
yomari = { model = 'prop_cs_plate_01' },
tika = { model = 'prop_cs_plate_01' },
salad = { model = 'prop_cs_bowl_01' },
thukpa = { model = 'prop_cs_bowl_01' },
jujudhau = { model = 'prop_cs_bowl_01b' },
noodles = { model = 'prop_ff_noodle_01' },
chowmein = { model = 'prop_ff_noodle_01' },
twerks_candy = { model = 'prop_choc_meto' },
snikkel_candy = { model = 'prop_choc_ego' },
laddu = { model = 'prop_candy_pqs' },
bread = { model = 'v_res_fa_bread01' },
egg = { model = 'v_ret_247_eggs' },
-- Farm produce uses lumo-farming's own streamed crop models: single
-- fruit and veg (apple 9 cm, lettuce 19 cm, watermelon 25 cm), the
-- same ones that grow on the plots. Wheat and soy only exist as
-- plants, so they use the smallest stage (a wheat sheaf, a soy plant).
-- Without lumo-farming running these report missing and use the bag.
farm_apple = { model = 'prp_farming_apple' },
farm_banana = { model = 'prp_farming_banana' },
farm_cucumber = { model = 'prp_farming_cucumber' },
farm_eggplant = { model = 'prp_farming_eggplant' },
farm_grape = { model = 'prp_farming_grape' },
farm_lettuce = { model = 'prp_farming_lettuce' },
farm_onion = { model = 'prp_farming_onion' },
farm_potato = { model = 'prp_farming_potato' },
farm_strawberry = { model = 'prp_farming_strawberry' },
farm_tomato = { model = 'prp_farming_tomato' },
farm_watermelon = { model = 'prp_farming_watermelon', size = 'heavy' },
farm_wheat = { model = 'prp_wheat_stage1' },
farm_soy = { model = 'pr_soya_stage_1' },
grape = { model = 'prp_farming_grape' },
lettuce = { model = 'prp_farming_lettuce' },
tomato = { model = 'prp_farming_tomato' },
potato = { model = 'prp_farming_potato' },
old_fruit = { model = 'prp_farming_apple' },
-- Dry groceries in a small paper bag.
flour = { model = 'prop_paper_bag_small' },
rice = { model = 'prop_paper_bag_small' },
pasta = { model = 'prop_paper_bag_small' },
spices = { model = 'prop_paper_bag_small' },
dough = { model = 'prop_paper_bag_small' },
cheese = { model = 'prop_paper_bag_small' },
tea_leaves = { model = 'prop_paper_bag_small' },
old_corn = { model = 'prop_paper_bag_small' },
-- Farming
farm_water_can = { model = 'prop_wateringcan' },
farm_fertilizer = { model = 'prop_cs_fertilizer' },
fertilizer = { model = 'prop_cs_fertilizer' },
weed_nutrition = { model = 'prop_cs_fertilizer' },
dust = { model = 'prop_cs_fertilizer' },
plant_spray = { model = 'bkr_prop_weed_spray_01a' },
farm_soil_scanner = { model = 'w_am_digiscanner' },
-- Drugs and chemicals
joint = { model = 'p_cs_joint_01' },
rolled_weed = { model = 'p_cs_joint_01' },
rolling_paper = { model = 'ng_proc_cigpak01a' },
weed_bag = { model = 'bkr_prop_weed_smallbag_01a' },
empty_weed_bag = { model = 'bkr_prop_weed_smallbag_01a' },
weed_brick = { model = 'prop_weed_block_01' },
weed_package = { model = 'prop_weed_block_01' },
packed_weed = { model = 'prop_weed_block_01' },
unpacked_weed = { model = 'bkr_prop_weed_bigbag_open_01a' },
cokebaggy = { model = 'bkr_prop_meth_smallbag_01a' },
cocaine_bag = { model = 'bkr_prop_meth_smallbag_01a' },
coke = { model = 'bkr_prop_meth_smallbag_01a' },
crack_baggy = { model = 'bkr_prop_meth_smallbag_01a' },
xtcbaggy = { model = 'bkr_prop_meth_smallbag_01a' },
meth = { model = 'bkr_prop_meth_smallbag_01a' },
meth_bag = { model = 'bkr_prop_meth_smallbag_01a' },
cutted_coke = { model = 'bkr_prop_coke_powder_01' },
unpacked_coke = { model = 'bkr_prop_coke_powder_01' },
coke_brick = { model = 'bkr_prop_coke_block_01a' },
coke_small_brick = { model = 'bkr_prop_coke_block_01a' },
coke_package = { model = 'bkr_prop_coke_block_01a' },
packed_coke = { model = 'bkr_prop_coke_block_01a' },
coca_leaf = { model = 'bkr_prop_weed_leaf_01a' },
coca_paste = { model = 'bkr_prop_coke_plasticbowl_01' },
coca_blend = { model = 'bkr_prop_coke_plasticbowl_01' },
crushed_ingredients = { model = 'bkr_prop_coke_metalbowl_02' },
blended_ingredients = { model = 'bkr_prop_coke_metalbowl_02' },
cooked_meth = { model = 'bkr_prop_meth_tray_01a' },
breaked_meth = { model = 'bkr_prop_meth_smashedtray_01' },
meth_pack = { model = 'bkr_prop_meth_bigbag_01a', size = 'heavy' },
meth_package = { model = 'bkr_prop_meth_bigbag_01a', size = 'heavy' },
packed_meth = { model = 'bkr_prop_meth_bigbag_01a', size = 'heavy' },
powdered_milk = { model = 'bkr_prop_coke_powderedmilk' },
oxy = { model = 'prop_cs_pills' },
painkillers = { model = 'prop_cs_pills' },
painkiller = { model = 'prop_cs_pills' },
kq_acetone = { model = 'bkr_prop_meth_acetone' },
kq_ammonia = { model = 'bkr_prop_meth_ammonia' },
ammonia = { model = 'bkr_prop_meth_ammonia' },
kq_lithium = { model = 'bkr_prop_meth_lithium' },
kq_meth_pills = { model = 'bkr_prop_meth_pseudoephedrine' },
kq_ethanol = { model = 'prop_drug_bottle' },
hydrochloric_acid = { model = 'bkr_prop_meth_hcacid' },
sacid = { model = 'bkr_prop_meth_sacid' },
kq_meth_lab_kit = { model = 'hei_prop_hei_drug_case', size = 'heavy' },
gasoline = { model = 'w_am_jerrycan', size = 'heavy' },
-- Money and valuables
cash = { model = 'prop_cash_pile_01', amounts = {
{ min = 1, model = 'prop_anim_cash_note' },
{ min = 100, model = 'prop_anim_cash_pile_01' },
{ min = 2500, model = 'bkr_prop_money_wrapped_01' },
{ min = 25000, model = 'prop_cash_case_02', size = 'heavy' },
} },
money = { model = 'bkr_prop_money_wrapped_01' },
markedbills = { model = 'prop_money_bag_01', size = 'heavy' },
moneybag = { model = 'prop_money_bag_01', size = 'heavy' },
money_sheet = { model = 'bkr_prop_prtmachine_moneypage' },
cutted_money = { model = 'bkr_prop_prtmachine_moneypage' },
uncutted_money = { model = 'bkr_prop_prtmachine_moneyream' },
casinochips = { model = 'vw_prop_chip_100dollar_st' },
lumo_lifted_wallet = { model = 'prop_ld_wallet_01' },
stolen_bag = { model = 'prop_ld_purse_01' },
rolex = { model = 'p_watch_01' },
gold_watch = { model = 'p_watch_01' },
goldwatch = { model = 'p_watch_01' },
luxury_watch = { model = 'p_watch_01' },
fitbit = { model = 'p_watch_02' },
diamond_ring = { model = 'v_res_jewelbox' },
gold_ring = { model = 'v_res_jewelbox' },
silver_ring = { model = 'v_res_jewelbox' },
diamond = { model = 'v_res_jewelbox' },
goldchain = { model = 'p_jewel_necklace01_s' },
tenkgoldchain = { model = 'p_jewel_necklace01_s' },
gold_chain = { model = 'p_jewel_necklace01_s' },
gold_necklace = { model = 'p_jewel_necklace01_s' },
gold_bracelet = { model = 'p_jewel_necklace02_s' },
goldbar = { model = 'hei_prop_heist_gold_bar', size = 'heavy' },
gold_bar = { model = 'hei_prop_heist_gold_bar', size = 'heavy' },
gold = { model = 'hei_prop_heist_gold_bar', size = 'heavy' },
-- Cards, keys and paperwork
id_card = { model = 'p_ld_id_card_01' },
lawyerpass = { model = 'p_ld_id_card_01' },
weaponlicense = { model = 'p_ld_id_card_01' },
mechanicworkcard = { model = 'p_ld_id_card_01' },
driver_license = { model = 'bkr_prop_fakeid_singledriverl' },
bank_card = { model = 'prop_cs_credit_card' },
blank_card = { model = 'prop_cs_credit_card' },
fake_credit_card = { model = 'prop_cs_credit_card' },
sim_card = { model = 'prop_cs_credit_card' },
security_card_01 = { model = 'prop_cs_swipe_card' },
security_card_02 = { model = 'prop_cs_swipe_card' },
stolen_tv = { model = 'prop_tv_flat_02b', size = 'bulky' },
stolen_microwave = { model = 'prop_microwave_1', size = 'bulky' },
stolen_printer = { model = 'prop_printer_01', size = 'bulky' },
housekey = { model = 'p_car_keys_01' },
labkey = { model = 'p_car_keys_01' },
printerdocument = { model = 'prop_cs_documents_01' },
certificate = { model = 'prop_cs_documents_01' },
serviceinvoice = { model = 'prop_cs_documents_01' },
order_slip = { model = 'prop_notepad_01' },
stickynote = { model = 'xs_prop_arena_stickynote_01a' },
lumo_stolen_mail = { model = 'h4_prop_h4_pile_letters_01a' },
lumo_parcel = { model = 'prop_cs_package_01' },
sagun = { model = 'prop_cs_package_01' },
marigold = { model = 'prop_single_rose' },
delivery_box = { model = 'hei_prop_heist_box', size = 'bulky' },
lumo_hotgoods = { model = 'prop_cs_cardbox_01', size = 'bulky' },
electronics = { model = 'prop_cs_cardbox_01', size = 'bulky' },
-- Phones, radios and electronics
phone = { model = 'prop_npc_phone_02', hold = { offset = vector3(0.10, 0.02, 0.0), rotation = vector3(-95.0, 0.0, 0.0) } },
iphone = { model = 'prop_npc_phone_02', hold = { offset = vector3(0.10, 0.02, 0.0), rotation = vector3(-95.0, 0.0, 0.0) } },
samsungphone = { model = 'prop_npc_phone_02', hold = { offset = vector3(0.10, 0.02, 0.0), rotation = vector3(-95.0, 0.0, 0.0) } },
smartphone = { model = 'prop_npc_phone_02', hold = { offset = vector3(0.10, 0.02, 0.0), rotation = vector3(-95.0, 0.0, 0.0) } },
radio = { model = 'prop_cs_hand_radio' },
pinger = { model = 'prop_cs_hand_radio' },
tablet = { model = 'prop_cs_tablet' },
heistpack_tablet = { model = 'prop_cs_tablet' },
illegal_tablet = { model = 'prop_cs_tablet' },
electronickit = { model = 'prop_cs_tablet' },
carplay = { model = 'prop_cs_tablet_02' },
laptop = { model = 'prop_laptop_lester2' },
tunerlaptop = { model = 'prop_laptop_lester2' },
hacking_laptop = { model = 'hei_prop_hst_laptop' },
radioscanner = { model = 'w_am_digiscanner' },
signal_scanner = { model = 'w_am_digiscanner' },
imsi_catcher = { model = 'w_am_digiscanner' },
diagnostic_scanner = { model = 'w_am_digiscanner' },
multimeter = { model = 'w_am_digiscanner' },
trojan_usb = { model = 'hei_prop_hst_usb_drive' },
cryptostick = { model = 'hei_prop_hst_usb_drive' },
decryption_key = { model = 'hei_prop_hst_usb_drive' },
card_reader = { model = 'hei_prop_heist_card_hack' },
cctv_splicer = { model = 'hei_prop_heist_card_hack' },
circuit_probe = { model = 'hei_prop_heist_card_hack' },
weapon_hackingdevice = { model = 'hei_prop_heist_card_hack' },
atm_skimmer = { model = 'hei_prop_heist_card_hack_02' },
atm_hack_device = { model = 'hei_prop_heist_card_hack_02' },
heistpack_drone = { model = 'ba_prop_battle_drone_quad' },
newscam = { model = 'prop_v_cam_01', size = 'heavy' },
newsmic = { model = 'p_ing_microphonel_01' },
newsbmic = { model = 'prop_v_bmike_01', size = 'heavy' },
binoculars = { model = 'prop_binoc_01' },
-- Tools and heist gear
lockpick = { model = 'prop_tool_screwdvr03' },
advancedlockpick = { model = 'prop_tool_screwdvr03' },
masterpick = { model = 'prop_tool_screwdvr01' },
gatecrack = { model = 'prop_tool_screwdvr02' },
screwdriverset = { model = 'prop_tool_box_04', size = 'heavy' },
precision_toolkit = { model = 'prop_tool_box_04', size = 'heavy' },
repairkit = { model = 'prop_tool_box_04', size = 'heavy' },
advancedrepairkit = { model = 'prop_tool_box_04', size = 'heavy' },
tirerepairkit = { model = 'prop_tool_box_04', size = 'heavy' },
veh_toolbox = { model = 'prop_tool_box_04', size = 'heavy' },
cleaningkit = { model = 'prop_sponge_01' },
drill = { model = 'hei_prop_heist_drill', size = 'heavy' },
heistpack_drill = { model = 'hei_prop_heist_drill', size = 'heavy' },
heistpack_grinder = { model = 'imp_prop_grinder_01a', size = 'heavy' },
thermite = { model = 'hei_prop_heist_thermite' },
thermite_charge = { model = 'hei_prop_heist_thermite' },
heistpack_anchor = { model = 'prop_rope_hook_01' },
anchor = { model = 'prop_rope_hook_01' },
heavy_rope = { model = 'prop_cs_heist_rope', size = 'heavy' },
graffiti_can = { model = 'prop_cs_spray_can' },
graffiti_remover = { model = 'ng_proc_spraycan01a' },
lighter = { model = 'p_cs_lighter_01' },
jerry_can = { model = 'w_am_jerrycan', size = 'heavy' },
petrolcan = { model = 'w_am_jerrycan', size = 'heavy' },
nitrous = { model = 'p_s_scuba_tank_s', size = 'heavy' },
glass = { model = 'prop_cs_glass_scrap' },
-- Vehicle parts. The big ones are carried in both arms.
veh_engine = { model = 'prop_car_engine_01', size = 'bulky' },
veh_transmission = { model = 'imp_prop_impexp_gearbox_01', size = 'bulky' },
veh_turbo = { model = 'imp_prop_impexp_engine_part_01a', size = 'bulky' },
veh_wheels = { model = 'prop_wheel_01', size = 'bulky' },
veh_exterior = { model = 'imp_prop_impexp_car_panel_01a', size = 'bulky' },
veh_armor = { model = 'imp_prop_impexp_car_door_01a', size = 'bulky' },
veh_interior = { model = 'prop_car_seat', size = 'bulky' },
veh_brakes = { model = 'prop_wheel_hub_01', size = 'heavy' },
veh_suspension = { model = 'prop_wheel_hub_01', size = 'heavy' },
veh_plates = { model = 'p_num_plate_01' },
-- Medical
bandage = { model = 'prop_ld_health_pack' },
firstaid = { model = 'prop_ld_health_pack' },
ifaks = { model = 'prop_ld_health_pack' },
splint = { model = 'prop_ld_health_pack' },
tourniquet = { model = 'prop_ld_health_pack' },
suturekit = { model = 'prop_ld_health_pack' },
medkit = { model = 'xm_prop_x17_bag_med_01a', size = 'heavy' },
adrenaline = { model = 'prop_syringe_01' },
walkstick = { model = 'prop_cs_walking_stick' },
-- Gear and clothing
armor = { model = 'prop_bodyarmour_03', size = 'heavy' },
heavyarmor = { model = 'prop_bodyarmour_03', size = 'heavy' },
armor_plate = { model = 'prop_armour_pickup' },
backpack_small = { model = 'prop_michael_backpack' },
backpack_medium = { model = 'p_michael_backpack_s' },
backpack_large = { model = 'bkr_prop_duffel_bag_01a', size = 'heavy' },
parachute = { model = 'p_parachute_s', size = 'heavy' },
diving_gear = { model = 'p_s_scuba_tank_s', size = 'heavy' },
diving_fill = { model = 'p_d_scuba_tank_s' },
gasmask = { model = 'p_gasmask_s' },
handcuffs = { model = 'prop_cs_cuffs_01' },
clothing_mask = { model = 'prop_michael_balaclava' },
clothing_jacket = { model = 'prop_ld_shirt_01' },
clothing_shirt = { model = 'prop_ld_tshirt_01' },
clothing_vest = { model = 'prop_ld_tshirt_02' },
clothing_pants = { model = 'prop_ld_jeans_01' },
clothing_shoes = { model = 'prop_ld_shoe_01' },
clothing_hat = { model = 'prop_proxy_hat_01' },
clothing_glasses = { model = 'prop_cs_sol_glasses' },
clothing_necklace = { model = 'p_jewel_necklace01_s' },
clothing_earrings = { model = 'p_tmom_earrings_s' },
clothing_watch = { model = 'p_watch_01' },
clothing_bracelet = { model = 'p_jewel_necklace02_s' },
clothing_bag = { model = 'prop_michael_backpack' },
-- Fireworks and diving finds
firework1 = { model = 'ind_prop_firework_01' },
firework2 = { model = 'ind_prop_firework_02' },
firework3 = { model = 'ind_prop_firework_03' },
firework4 = { model = 'ind_prop_firework_04' },
dendrogyra_coral = { model = 'prop_coral_01' },
antipatharia_coral = { model = 'prop_coral_02' },
-- Ammunition and weapon parts
pistol_ammo = { model = 'prop_ld_ammo_pack_01' },
smg_ammo = { model = 'prop_ld_ammo_pack_01' },
rifle_ammo = { model = 'prop_ld_ammo_pack_01' },
shotgun_ammo = { model = 'prop_ld_ammo_pack_01' },
weapon_ammo = { model = 'prop_box_ammo03a' },
suppressor_attachment = { model = 'w_at_ar_supp' },
flashlight_attachment = { model = 'w_at_ar_flsh' },
grip_attachment = { model = 'w_at_ar_afgrip' },
clip_attachment = { model = 'w_ar_assaultrifle_mag1' },
drum_attachment = { model = 'w_ar_assaultrifle_boxmag' },
barrel_attachment = { model = 'w_at_ar_barrel_1' },
comp_attachment = { model = 'w_at_pi_comp_1' },
smallscope_attachment = { model = 'w_at_scope_small' },
medscope_attachment = { model = 'w_at_scope_medium' },
largescope_attachment = { model = 'w_at_scope_large' },
holoscope_attachment = { model = 'w_at_scope_macro' },
advscope_attachment = { model = 'w_at_scope_max' },
nvscope_attachment = { model = 'w_at_scope_nv' },
thermalscope_attachment = { model = 'w_at_scope_max' },
},
-- Families of items, tried in order after exact names and weapons, so
-- new items in a family get a sensible prop without an entry. `match`
-- is a Lua pattern against the item name; the rest is an Items entry.
Patterns = {
{ match = '^weapontint_', model = 'prop_paint_spray01a' },
{ match = 'camo_attachment$', model = 'prop_paint_spray01a' },
{ match = '^luxuryfinish_', model = 'prop_paint_spray01a' },
{ match = 'muzzle_brake$', model = 'w_at_muzzle_1' },
{ match = '^seeds_', model = 'prop_paper_bag_small' },
{ match = '_seed$', model = 'prop_paper_bag_small' },
{ match = '^weed_', model = 'bkr_prop_weed_smallbag_01a' },
{ match = '^kq_meth_', model = 'bkr_prop_meth_smallbag_01a' },
{ match = '^clothing_', model = 'prop_ld_tshirt_01' },
{ match = '^heist_paint_', model = 'prop_cs_rolled_paper' },
{ match = '^veh_', model = 'prop_cs_cardbox_01', size = 'bulky' },
{ match = '_ammo$', model = 'prop_ld_ammo_pack_01' },
},
-- Weapon inventory names do not equal their object model names. Known
-- stock weapons use their real pickup/world model; unknown/add-on guns
-- deliberately fall back to the paper bag until configured above.
-- A value is a model name, or an Items-style entry to set a size.
Weapons = {
weapon_snspistol_mk2 = 'w_pi_sns_pistolmk2',
weapon_revolver = 'w_pi_revolver',
weapon_revolver_mk2 = 'w_pi_revolvermk2',
weapon_doubleaction = 'w_pi_wep1_gun',
weapon_navyrevolver = 'w_pi_wep2_gun',
weapon_ceramicpistol = 'w_pi_ceramic_pistol',
weapon_marksmanpistol = 'w_pi_singleshot',
weapon_gadgetpistol = 'w_pi_singleshoth4',
weapon_flaregun = 'w_pi_flaregun',
weapon_raypistol = 'w_pi_raygun',
weapon_tecpistol = 'w_pi_pistolsmg_m31',
weapon_minismg = 'w_sb_minismg',
weapon_smg_mk2 = 'w_sb_smgmk2',
weapon_specialcarbine_mk2 = 'w_ar_specialcarbinemk2',
weapon_bullpuprifle_mk2 = 'w_ar_bullpupriflemk2',
weapon_militaryrifle = 'w_ar_bullpuprifleh4',
weapon_heavyrifle = 'w_ar_heavyrifleh',
weapon_tacticalrifle = 'w_ar_carbinerifle_reh',
weapon_pumpshotgun_mk2 = 'w_sg_pumpshotgunmk2',
weapon_autoshotgun = 'w_sg_sweeper',
weapon_combatshotgun = 'w_sg_pumpshotgunh4',
weapon_heavysniper_mk2 = { model = 'w_sr_heavysnipermk2', size = 'heavy' },
weapon_marksmanrifle_mk2 = 'w_sr_marksmanriflemk2',
weapon_precisionrifle = 'w_sr_precisionrifle_reh',
weapon_combatmg_mk2 = { model = 'w_mg_combatmgmk2', size = 'heavy' },
weapon_minigun = { model = 'w_mg_minigun', size = 'heavy' },
weapon_rpg = { model = 'w_lr_rpg', size = 'heavy' },
weapon_grenadelauncher = { model = 'w_lr_grenadelauncher', size = 'heavy' },
weapon_compactlauncher = 'w_lr_compactgl',
weapon_hominglauncher = { model = 'w_lr_homing', size = 'heavy' },
weapon_firework = { model = 'w_lr_firework', size = 'heavy' },
weapon_grenade = 'w_ex_grenadefrag',
weapon_smokegrenade = 'w_ex_grenadesmoke',
weapon_bzgas = 'w_ex_grenadesmoke',
weapon_molotov = 'w_ex_molotov',
weapon_stickybomb = 'w_ex_pe',
weapon_pipebomb = 'w_ex_pipebomb',
weapon_snowball = 'w_ex_snowball',
weapon_ball = 'w_am_baseball',
weapon_flare = 'w_am_flare',
weapon_fireextinguisher = 'w_am_fire_exting',
weapon_bottle = 'w_me_bottle',
weapon_dagger = 'w_me_dagger',
weapon_knuckle = 'w_me_knuckle',
weapon_switchblade = 'w_me_switchblade',
weapon_battleaxe = 'w_me_battleaxe',
weapon_poolcue = 'w_me_poolcue',
weapon_wrench = 'w_me_wrench',
weapon_flashlight = 'w_me_flashlight',
weapon_nightstick = 'w_me_nightstick',
weapon_stone_hatchet = 'w_me_stonehatchet',
weapon_candycane = 'w_me_candy_xm3',
weapon_pistolxm3 = 'w_pi_pistol_xm3',
weapon_raycarbine = 'w_ar_srifle',
weapon_rayminigun = { model = 'w_mg_sminigun', size = 'heavy' },
weapon_railgun = { model = 'w_ar_railgun', size = 'heavy' },
weapon_railgunxm3 = { model = 'w_ar_railgun_xm3', size = 'heavy' },
weapon_remotesniper = 'w_sr_sniperrifle',
weapon_grenadelauncher_smoke = { model = 'w_lr_grenadelauncher', size = 'heavy' },
weapon_proxmine = 'w_ex_apmine',
weapon_hazardcan = { model = 'w_ch_jerrycan', size = 'heavy' },
weapon_digiscanner = 'w_am_digiscanner',
weapon_briefcase = { model = 'prop_ld_case_01', size = 'heavy' },
weapon_briefcase_02 = { model = 'prop_security_case_01', size = 'heavy' },
weapon_garbagebag = 'prop_cs_street_binbag_01',
weapon_handcuffs = 'prop_cs_cuffs_01',
weapon_bread = 'v_res_fa_bread01',
weapon_pistol = 'w_pi_pistol',
weapon_pistol_mk2 = 'w_pi_pistolmk2',
weapon_combatpistol = 'w_pi_combatpistol',
weapon_appistol = 'w_pi_appistol',
weapon_pistol50 = 'w_pi_pistol50',
weapon_heavypistol = 'w_pi_heavypistol',
weapon_snspistol = 'w_pi_sns_pistol',
weapon_vintagepistol = 'w_pi_vintage_pistol',
weapon_stungun = 'w_pi_stungun',
weapon_microsmg = 'w_sb_microsmg',
weapon_smg = 'w_sb_smg',
weapon_assaultsmg = 'w_sb_assaultsmg',
weapon_combatpdw = 'w_sb_pdw',
weapon_machinepistol = 'w_sb_compactsmg',
weapon_assaultrifle = 'w_ar_assaultrifle',
weapon_assaultrifle_mk2 = 'w_ar_assaultriflemk2',
weapon_carbinerifle = 'w_ar_carbinerifle',
weapon_carbinerifle_mk2 = 'w_ar_carbineriflemk2',
weapon_advancedrifle = 'w_ar_advancedrifle',
weapon_specialcarbine = 'w_ar_specialcarbine',
weapon_bullpuprifle = 'w_ar_bullpuprifle',
weapon_musket = 'w_ar_musket',
weapon_compactrifle = 'w_ar_assaultrifle_smg',
weapon_pumpshotgun = 'w_sg_pumpshotgun',
weapon_sawnoffshotgun = 'w_sg_sawnoff',
weapon_assaultshotgun = 'w_sg_assaultshotgun',
weapon_bullpupshotgun = 'w_sg_bullpupshotgun',
weapon_heavyshotgun = 'w_sg_heavyshotgun',
weapon_dbshotgun = 'w_sg_doublebarrel',
weapon_sniperrifle = 'w_sr_sniperrifle',
weapon_heavysniper = 'w_sr_heavysniper',
weapon_marksmanrifle = 'w_sr_marksmanrifle',
weapon_mg = { model = 'w_mg_mg', size = 'heavy' },
weapon_combatmg = { model = 'w_mg_combatmg', size = 'heavy' },
weapon_gusenberg = 'w_sb_gusenberg',
weapon_bat = 'w_me_bat',
weapon_crowbar = 'w_me_crowbar',
weapon_golfclub = 'w_me_gclub',
weapon_hammer = 'w_me_hammer',
weapon_hatchet = 'w_me_hatchet',
weapon_knife = 'w_me_knife_01',
weapon_machete = 'w_me_machette_lr',
weapon_petrolcan = 'w_am_jerrycan',
},
},
VendingObjects = {
'prop_vend_soda_01',
'prop_vend_soda_02',
'prop_vend_water_01',
'prop_vend_coffe_01',
},
VendingItems = {
{ name = 'kurkakola', price = 4, amount = 50 },
{ name = 'water_bottle', price = 4, amount = 50 },
},
}config/shops.lua
lua
--- World shops: 24/7, liquor stores, LTD and Ammu-Nation, opened in this
--- inventory's own shop screen (buy by dragging into your pockets).
---
--- On QBCore, qb-shops places shops and opens them here already, so this is
--- for ESX and standalone servers. On ESX it can stand in for esx_shops and
--- esx_weaponshop, or leave them to run as they are.
Config.Shops = {
-- 'auto' ESX / standalone: our shops wherever the resource a group
-- replaces (esx_shops, esx_weaponshop) is not running. Stop
-- that resource (remove its `ensure`) and ours take over; start
-- it again and they step aside. QBCore / Qbox: off.
-- 'lumo' always ours. Also stop esx_shops / esx_weaponshop, or both
-- open at the same counter.
-- 'esx' never ours: esx_shops / esx_weaponshop do the selling.
Mode = 'auto',
-- When the resource a group replaces is installed (even stopped), take
-- its items, prices and positions from its own config files, so you keep
-- one shop list. false: always use the Groups below.
UseESXConfig = true,
-- Shops whose esx_weaponshop zone is `Legal = true` need this licence
-- (esx_license). nil: no licence check. ESX's own default is off.
WeaponLicence = nil,
-- Sold at every weapon shop on top of its weapons: ammo, the attachment
-- parts the Attachments screen fits (ESX component names: one `suppressor`
-- fits every weapon that takes one) and tint kits.
WeaponExtras = {
{ name = 'pistol_ammo', price = 50 },
{ name = 'smg_ammo', price = 75 },
{ name = 'shotgun_ammo', price = 75 },
{ name = 'rifle_ammo', price = 100 },
{ name = 'snp_ammo', price = 150 },
{ name = 'clip_extended', price = 650 },
{ name = 'flashlight', price = 250 },
{ name = 'suppressor', price = 1250 },
{ name = 'grip', price = 900 },
{ name = 'scope', price = 1500 },
{ name = 'scope_holo', price = 1250 },
{ name = 'scope_small', price = 1450 },
{ name = 'scope_medium', price = 1800 },
{ name = 'weapontint_1', price = 500 },
{ name = 'weapontint_2', price = 2500 },
{ name = 'weapontint_3', price = 500 },
{ name = 'weapontint_4', price = 500 },
{ name = 'weapontint_5', price = 750 },
{ name = 'weapontint_6', price = 500 },
{ name = 'weapontint_7', price = 1500 },
},
-- Stock per item in each shop (refills on restart).
Stock = 100,
Marker = { type = 2, size = 0.35, color = { 163, 230, 53, 160 }, drawDistance = 12.0, interactDistance = 1.6 },
-- Used when UseESXConfig finds nothing. `replaces`: the ESX resource this
-- group stands in for. `weapons`: also sells WeaponExtras.
Groups = {
TwentyFourSeven = {
label = '24/7', replaces = 'esx_shops',
blip = { sprite = 59, color = 25, scale = 0.7 },
items = {
{ name = 'burger', price = 15 }, { name = 'water', price = 10 }, { name = 'pizza_ham', price = 25 },
{ name = 'sprunk', price = 12 }, { name = 'phone', price = 250 }, { name = 'lockpick', price = 150 },
},
locations = {
vector3(373.8, 325.8, 103.5), vector3(2557.4, 382.2, 108.6), vector3(-3038.9, 585.9, 7.9),
vector3(-3241.9, 1001.4, 12.8), vector3(547.4, 2671.7, 42.1), vector3(1961.4, 3740.6, 32.3),
vector3(2678.9, 3280.6, 55.2), vector3(1729.2, 6414.1, 35.0),
},
},
RobsLiquor = {
label = "Rob's Liquor", replaces = 'esx_shops',
blip = { sprite = 93, color = 25, scale = 0.7 },
items = {
{ name = 'burger', price = 15 }, { name = 'water', price = 10 }, { name = 'wine', price = 35 },
{ name = 'beer', price = 50 }, { name = 'blackberry_ale', price = 65 },
},
locations = {
vector3(1135.8, -982.2, 46.4), vector3(-1222.9, -906.9, 12.3), vector3(-1487.5, -379.1, 40.1),
vector3(-2968.2, 390.9, 15.0), vector3(1166.0, 2708.9, 38.1), vector3(1392.5, 3604.6, 34.9),
vector3(127.8, -1284.7, 29.2), vector3(-1393.4, -606.6, 30.3), vector3(-559.9, 287.0, 82.1),
},
},
LTDgasoline = {
label = 'LTD Gasoline', replaces = 'esx_shops',
blip = { sprite = 59, color = 25, scale = 0.7 },
items = {
{ name = 'taco_chicken', price = 15 }, { name = 'water', price = 10 }, { name = 'sandwich', price = 20 },
{ name = 'coffee', price = 8 }, { name = 'repairkit', price = 350 }, { name = 'bandage', price = 45 },
},
locations = {
vector3(-48.5, -1757.5, 29.4), vector3(1163.3, -323.8, 69.2), vector3(-707.5, -914.2, 19.2),
vector3(-1820.5, 792.5, 138.1), vector3(1698.3, 4924.4, 42.0),
},
},
GunShop = {
label = 'Ammu-Nation', replaces = 'esx_weaponshop', weapons = true, legal = true,
blip = { sprite = 110, color = 81, scale = 0.7 },
items = {
{ name = 'weapon_pistol', price = 500 }, { name = 'weapon_flashlight', price = 70 },
{ name = 'weapon_machete', price = 110 }, { name = 'weapon_nightstick', price = 150 },
{ name = 'weapon_bat', price = 50 }, { name = 'weapon_stungun', price = 60 },
{ name = 'weapon_microsmg', price = 1700 }, { name = 'weapon_assaultrifle', price = 11000 },
{ name = 'weapon_specialcarbine', price = 15000 }, { name = 'weapon_sniperrifle', price = 24000 },
{ name = 'weapon_grenade', price = 700 }, { name = 'weapon_bzgas', price = 200 },
{ name = 'weapon_fireextinguisher', price = 100 }, { name = 'weapon_ball', price = 30 },
{ name = 'weapon_smokegrenade', price = 100 },
},
locations = {
vector3(-662.1, -935.3, 20.8), vector3(810.2, -2157.3, 28.6), vector3(1693.4, 3759.5, 33.7),
vector3(-330.2, 6083.8, 30.4), vector3(252.3, -50.0, 68.9), vector3(22.0, -1107.2, 28.8),
vector3(2567.6, 294.3, 107.7), vector3(-1117.5, 2698.6, 17.5), vector3(842.4, -1033.4, 27.1),
},
},
},
}config/vehicles.lua
lua
VehicleStorage = {
default = {
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 35,
trunkWeight = 60000
},
[0] = { -- Compacts
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 30,
trunkWeight = 38000
},
[1] = { -- Sedans
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 40,
trunkWeight = 50000
},
[2] = { -- SUVs
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 50,
trunkWeight = 75000
},
[3] = { -- Coupes
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 35,
trunkWeight = 42000
},
[4] = { -- Muscle
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 30,
trunkWeight = 38000
},
[5] = { -- Sports Classics
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 25,
trunkWeight = 30000
},
[6] = { -- Sports
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 25,
trunkWeight = 30000
},
[7] = { -- Super
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 25,
trunkWeight = 30000
},
[8] = { -- Motorcycles
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 15,
trunkWeight = 15000
},
[9] = { -- Off-road
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 35,
trunkWeight = 60000
},
[12] = { -- Vans
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 35,
trunkWeight = 120000
},
[13] = { -- Cycles
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 0,
trunkWeight = 0
},
[14] = { -- Boats
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 50,
trunkWeight = 120000
},
[15] = { -- Helicopters
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 50,
trunkWeight = 120000
},
[16] = { -- Planes
gloveboxSlots = 5,
gloveboxWeight = 10000,
trunkSlots = 50,
trunkWeight = 120000
},
[17] = { -- service
gloveboxSlots = 0,
gloveboxWeight = 0,
trunkSlots = 0,
trunkWeight = 0
},
[18] = { -- Emergency
gloveboxSlots = 4,
gloveboxWeight = 10000,
trunkSlots = 12,
trunkWeight = 150000
},
[19] = { -- Military
gloveboxSlots = 0,
gloveboxWeight = 0,
trunkSlots = 0,
trunkWeight = 0
},
[20] = { -- Commercial
gloveboxSlots = 0,
gloveboxWeight = 0,
trunkSlots = 0,
trunkWeight = 0
},
[21] = { -- trains
gloveboxSlots = 0,
gloveboxWeight = 0,
trunkSlots = 0,
trunkWeight = 0
},
[22] = { -- Commercial
gloveboxSlots = 0,
gloveboxWeight = 0,
trunkSlots = 0,
trunkWeight = 0
},
}
BackEngineVehicles = {
[`ninef`] = true,
[`adder`] = true,
[`vagner`] = true,
[`t20`] = true,
[`infernus`] = true,
[`zentorno`] = true,
[`reaper`] = true,
[`comet2`] = true,
[`comet3`] = true,
[`jester`] = true,
[`jester2`] = true,
[`cheetah`] = true,
[`cheetah2`] = true,
[`prototipo`] = true,
[`turismor`] = true,
[`pfister811`] = true,
[`ardent`] = true,
[`nero`] = true,
[`nero2`] = true,
[`tempesta`] = true,
[`vacca`] = true,
[`bullet`] = true,
[`osiris`] = true,
[`entityxf`] = true,
[`turismo2`] = true,
[`fmj`] = true,
[`re7b`] = true,
[`tyrus`] = true,
[`italigtb`] = true,
[`italirsx`] = true,
[`penetrator`] = true,
[`monroe`] = true,
[`ninef2`] = true,
[`stingergt`] = true,
[`surfer`] = true,
[`surfer2`] = true,
[`gp1`] = true,
[`autarch`] = true,
[`tyrant`] = true
}bridge/config.lua
lua
--- lumo-inventory — framework settings
---
--- QBCore, Qbox and ESX are detected automatically; with none of them running
--- the inventory runs standalone. Most servers never touch this file. The
--- inventory's own settings live in config/config.lua.
---
--- This folder (bridge/) is the script's built-in framework layer. You do NOT
--- need the separate lumo-bridge resource.
LumoBridgeConfig = {
--- 'auto' | 'qb' | 'qbx' | 'esx' | 'standalone' | 'custom'
--- auto — Qbox (qbx_core) > QBCore (qb-core) > ESX (es_extended) > Fallback
Framework = 'auto',
--- Used by 'auto' when no core is running. 'standalone' = no framework.
--- Set 'custom' only if you wire your own core in Custom below.
Fallback = 'standalone',
--- Print the detected framework and every unresolved call to the console.
Debug = false,
--- Resource names, in case yours are renamed.
Resources = {
qb = 'qb-core',
qbx = 'qbx_core',
esx = 'es_extended',
oxlib = 'ox_lib',
},
--- How long a server callback waits for its answer before giving up (ms).
CallbackTimeout = 15000,
--- Leave 'auto': this resource is the inventory.
Inventory = 'auto',
--- Targeting for item drops and vending machines. 'auto' probes: ox_target,
--- qb-target, qtarget. Without one, drops are picked up with an [E] prompt.
Target = 'auto',
ESX = {
--- How ESX multichar identifiers look. %s = slot, %l = licence hex.
IdentifierFormat = 'char%s:%l',
--- true only for an ESX build without per-slot identifiers.
SingleCharacter = false,
--- This script is not a character selector; leave false.
VerifyMulticharAtBoot = false,
},
--- Standalone (no framework). A character script that owns characters
--- (lumo-multicharacter) is used when it runs; without one every player is
--- one character keyed by their Rockstar licence.
Standalone = {
OwnsCharacters = false, -- keep false in this script
CharacterResource = 'lumo-multicharacter',
RememberPosition = false, -- positions are a spawn script's job
SetPedModel = false,
--- With neither a character script nor lumo-spawn, load the inventory
--- when FiveM's spawnmanager spawns the player.
AnnounceOnSpawn = true,
--- There is no money in standalone. With FreeShopping on, inventory
--- shops and vending machines cost nothing. To charge, plug your
--- economy in:
--- GetMoney = function(source, account) return number end,
--- RemoveMoney = function(source, account, amount, reason) return true/false end,
--- AddMoney = function(source, account, amount, reason) return true/false end,
--- account is 'cash' or 'bank'. Any hook set here wins over FreeShopping.
FreeShopping = true,
Money = {},
--- Job stashes and job shops need a job. Return
--- { name = 'police', grade = { level = 2 }, onduty = true } from here
--- if your server tracks jobs, or leave nil (everyone is a civilian).
GetJob = nil,
},
--- Only for Framework = 'custom'. See docs/CUSTOM-FRAMEWORKS.md.
Custom = {
client = {},
server = {},
inventory = {},
},
}