NX CreativeNX CreativeDocs
Scriptsnx_hud

Exports

The nx_hud API for other resources. HUD visibility, status, fuel, seatbelt and ammo readers, player settings, inventory gates and item effects, worn gear, payment methods, shop prices, crafting benches, combine recipes and the new hook events.

nx_hud answers for ox_lib, ox_inventory and ox_target, so the existing APIs of those resources work as documented by Overextended: ox_lib, ox_inventory and ox_target. Keep calling them by their usual names, for example exports.ox_inventory:AddItem(...).

This page documents what nx_hud adds. These exports live under nx_hud's own name: call them as exports.nx_hud:fn(...), never through exports.ox_inventory or exports.ox_lib.

A few rules apply to all of them:

  • Every registration (a hide, a status override, a reader, a gate, an item effect, a payment method, a resolver, a price modifier, a search check, a crafting bench, a combine recipe) belongs to the resource that made it, and is released when that resource stops.
  • The functions you pass run inside a protected call. An error is logged to the console and the safe default applies, so a broken callback does not take the HUD or the inventory down with it.
  • None of these exports yields, except showItem, which waits for the server's answer. Your callbacks should not yield either.

HUD (client)

Visibility

Hiding the HUD removes the gauges, the street line, the vehicle cluster, the radar, the windscreen HUD and the hotbar, and the hotbar keys rest. Notifications, progress bars, menus, dialogs, the radial menu, targeting and the inventory keep working. The island moves down into the radar's place and appears only when one of them needs it. Each resource holds its own hide, so the HUD shows again only when no resource hides it. The pause menu also hides the HUD while it is open.

exports.nx_hud:hideHudclient

Hide the HUD for your resource. Returns whether the HUD is visible now.

Returns

boolean
exports.nx_hud:hideHud()   -- for a cutscene
-- later
exports.nx_hud:showHud()
exports.nx_hud:showHudclient

Release your resource's hide. Returns whether the HUD is visible now: false while another resource still hides it.

Returns

boolean
exports.nx_hud:toggleHudclient

Flip your resource's own hide. Returns whether the HUD is visible now.

Returns

boolean
exports.nx_hud:setHudVisibleclient

Set your resource's hide directly. Returns whether the HUD is visible now.

Parameters

  • visibleboolean— false hides the HUD for your resource. true or nil releases your hide.

Returns

boolean
exports.nx_hud:setHudVisible(not inCamera)
exports.nx_hud:isHudVisibleclient

Whether the HUD is visible, that is, no resource hides it.

Returns

boolean

Strict hide

The strict hide removes everything nx_hud draws except what the player must answer: the HUD, the island, notifications, progress bars and the inventory go, and the inventory cannot be opened. Use it for a death screen, a camera viewfinder or a cutscene. Notifications sent meanwhile wait and show in order once the last reason ends (an identical one once, at most 20). Progress bars keep running unseen. A dialog, context or list menu, radial menu, skill check, text prompt or the target (while the player aims) is shown on its own, so a death screen's prompt and its confirm dialog keep working. isHudVisible still answers the normal hide only.

nx_hud also strict-hides itself while the player is dead or in last stand (Config.strictHide in config/hud.lua).

exports.nx_hud:SetStrictHiddenclient

Turn one of your resource's reasons on or off. Returns whether nx_hud is strict hidden now. Your reasons go when your resource stops.

Parameters

  • reasonstring— Your own name for this hide. Any reason that is on hides nx_hud.
  • onboolean— true hides, false releases this reason.

Returns

boolean
exports.nx_hud:SetStrictHidden('deathscreen', true)
-- later
exports.nx_hud:SetStrictHidden('deathscreen', false)
exports.nx_hud:IsStrictHiddenclient

Whether any resource strict-hides nx_hud now. The client event nx_hud:strictHidden (hidden) fires on every change.

Returns

boolean

Seatbelt

exports.nx_hud:isSeatbeltOnclient

Whether the belt the HUD shows is buckled: nx_hud's own belt, or the seatbelt script it follows. false outside a vehicle and in vehicles without belts.

Returns

boolean
if not exports.nx_hud:isSeatbeltOn() then
    -- apply your own crash damage
end
exports.nx_hud:getSeatbeltclient

The same as isSeatbeltOn, under the name some scripts expect.

Returns

boolean
exports.nx_hud:registerSeatbeltReaderclient

Make the HUD show your seatbelt script's belt. A registered reader wins over every built-in adapter and over nx_hud's own belt, whatever Config.seatbelt says, and nx_hud's belt key and ejection stay off while it is registered. The latest registration wins. An error reads as unbuckled. Returns false when fn is not a function.

Parameters

  • fnfunction | nil— fn() returning true (or 1) when buckled. nil removes your reader.

Returns

boolean
exports.nx_hud:registerSeatbeltReader(function()
    return beltOn
end)

Status and money

Values cross this API in 0 to 100, as frameworks use them.

exports.nx_hud:setStatusclient

Override a status gauge. The most recent setter wins. Config.stress = false still hides stress. Returns false for an unknown key or a value that is not a number.

Parameters

  • keystring— 'hunger', 'thirst' or 'stress'.
  • valuenumber | nil— 0 to 100, shown instead of the framework value while set. nil releases your override.

Returns

boolean
exports.nx_hud:setStatus('stress', 45)
-- give the gauge back to the framework
exports.nx_hud:setStatus('stress', nil)
exports.nx_hud:getStatusclient

What the gauge shows now, 0 to 100, or nil when nothing provides that status.

Parameters

  • keystring— 'hunger', 'thirst' or 'stress'.

Returns

number | nil
exports.nx_hud:moneyPopclient

Show a money change on the island, also for accounts that Config.money leaves out. Returns false for a missing account or an amount that is not a number.

Parameters

  • accountstring— Any account name: 'cash', 'bank', 'black_money' or your own.
  • amountnumber— The change. Negative for money spent.
  • balance?number— The new total shown on the island. Defaults to the last known total of that account.

Returns

boolean
exports.nx_hud:moneyPop('crypto', -250, 1750)

Fuel

exports.nx_hud:registerFuelReaderclient

Feed the fuel gauge from your own fuel script. Asked before the built-in adapters while registered. The latest registration wins. An error counts as nil and is logged once. Returns false when fn is not a function.

Parameters

  • fnfunction | nil— fn(vehicle) returning the fuel level 0 to 100, or nil to let the built-in adapters answer. nil removes your reader.

Returns

boolean
exports.nx_hud:registerFuelReader(function(vehicle)
    return exports.my_fuel:GetFuel(vehicle)
end)

Weapon pill

The weapon pill shows the rounds in the magazine and the spare rounds after the slash. A weapon that a script gives infinite ammo shows its name instead of a number. A script that keeps its own count, such as a taser's cartridges or a battery, can show that count with a reader.

exports.nx_hud:registerAmmoReaderclient

Feed the weapon pill for one weapon from your own script. Asked every 100 ms while that weapon is in the player's hands. One reader per weapon: the latest registration wins. An error counts as nil and is logged once. Returns false when weapon is not a name or fn is not a function.

Parameters

  • weaponstring— The weapon's item name, for example 'WEAPON_STUNGUN'. Not case-sensitive.
  • fnfunction | nil— fn(ped, weapon) returning loaded, capacity, spare. nil removes your reader for that weapon.

Returns

boolean

What the reader returns:

ValueMeaning
loadedThe number in the magazine part of the pill. nil lets nx_hud read the weapon as usual.
capacityOptional. A full load, used for the low and empty colours.
spareOptional. The number after the slash. Left out, it is the weapon's ammo item in the player's pockets.
exports.nx_hud:registerAmmoReader('WEAPON_STUNGUN', function(ped, weapon)
    return cartridgesLoaded, 2, cartridgesInPocket
end)

Damage

exports.nx_hud:pushHitclient

Flash the damage indicator, for damage the game does not report: melee scripts, custom explosions, scripted damage. Real damage from players and NPCs already shows. Returns false while the HUD is not loaded.

Parameters

  • wherenumber | vector3 | nil— The direction of the hit in radians from the camera (0 ahead, positive to the right), or the attacker coords, from which the direction is worked out. nil uses the default direction.

Returns

boolean
exports.nx_hud:pushHit(GetEntityCoords(attackerPed))

Player settings

Each player's F7 settings are saved on their own PC. The server sets the defaults they start with in config/settings.lua (see Configuration). These exports read the settings in force for a player, under the names config/settings.lua uses: vehicle, face, glass, units, radar, radarZoom, zoomMode, prompts, radial, sounds, volume, inventory and targeting. Newer F7 rows can appear under their own names.

changed lists what the player set themselves, as { [name] = true }. Every other setting is the server's default.

exports.nx_hud:getSettingsclient

The local player's settings. Returns false, 'not_ready' until the HUD has loaded them, shortly after the player joins. The tables are copies: changing them changes nothing.

Returns

settings, changed | false, 'not_ready'
local settings, changed = exports.nx_hud:getSettings()
if settings and settings.units == 'kmh' then
    -- show your own speeds in km/h
end

To follow changes, listen for nx_hud:settingsChanged.

exports.nx_hud:getSettingsserver

A player's settings, as their client last reported them. The report reaches the server within about a second of a change. Returns false, 'no_player' for an id that is not connected, and false, 'not_reported' while the player's HUD has not loaded yet.

Parameters

  • sourcenumber— The player's server id.

Returns

settings, changed | false, reason
local settings, err = exports.nx_hud:getSettings(source)
if not settings then
    print(('settings not available: %s'):format(err))
elseif settings.glass == 'off' then
    -- this player runs the lightest glass
end
exports.nx_hud:getAllSettingsserver

{ [source] = settings } for every connected player whose HUD has reported. Players who have not are left out. The changed lists are not included: ask getSettings for one player.

Returns

table

Inventory (client)

The defaults these sit on are in inventory/custom/client.lua, which you can edit directly. See Customization.

exports.nx_hud:addOpenGateclient

Decide whether the player may open an inventory. Asked before one shows (ctx.phase = 'open') and every 100 ms while one is open (ctx.phase = 'stay'). A false answer stops the open, so nothing appears, or closes the open inventory, and shows the reason. An error allows. Returns the gate id, or nil when fn is not a function.

Parameters

  • fnfunction— fn(ctx) returning false, and an optional reason string, to refuse. Anything else allows.

Returns

number | nil

ctx.invType is nil for the player's own pockets, otherwise 'player', 'stash', 'drop', 'trunk', 'glovebox', 'shop', 'crafting' and so on. ctx.data is what was passed to openInventory.

Inventories opened by the server are asked too, before they show: ctx.forced is true for one a server script opens with forceOpenInventory, and ctx.inspect for one an admin views with /viewinv, in both phases (ctx.data is nil for these). Return false for them and the player never sees them open. To let server-opened inventories through, allow whenever ctx.forced or ctx.inspect is true.

local gate = exports.nx_hud:addOpenGate(function(ctx)
    if ctx.invType == 'trunk' and LocalPlayer.state.isCuffed then
        return false, 'Not with your hands cuffed'
    end
end)
exports.nx_hud:addUseGateclient

Decide whether the player may use an item. It can be asked more than once for one use (the hotbar preview, the use, and again as the item is consumed), so keep it free of side effects. An error allows. Returns the gate id, or nil when fn is not a function.

Parameters

  • fnfunction— fn(item, slot) returning false, and an optional reason, to refuse. item is the slot table: name, count, metadata, slot.

Returns

number | nil
exports.nx_hud:addUseGate(function(item)
    if item.name == 'lockpick' and IsPedInAnyVehicle(PlayerPedId(), false) then
        return false, 'Get out of the vehicle first'
    end
end)
exports.nx_hud:removeGateclient

Remove one of your resource's gates. Returns false for an unknown id or another resource's gate.

Parameters

  • idnumber— The id addOpenGate or addUseGate returned.

Returns

boolean
exports.nx_hud:registerItemEffectclient

Set what using an item does, for items that have no client.export or client.event of their own. It replaces the built-in effect of that name in inventory/custom/client.lua, or adds a new one. The function gets copies of the definition and the item. To use the item up, call exports.ox_inventory:useItem from it, as an item export would. An error falls back to the built-in effect.

Parameters

  • itemNamestring— The item name.
  • fnfunction | nil— fn(itemDef, item, slot). nil removes your effect.

Returns

boolean
exports.nx_hud:registerItemEffect('bandage', function(itemDef, item, slot)
    exports.ox_inventory:useItem(itemDef, function(data)
        if data then TriggerEvent('my_medical:bandaged') end
    end)
end)
exports.nx_hud:removeItemEffectclient

Remove your resource's effect for that item, so the built-in one applies again. Returns false when your resource has none.

Parameters

  • itemNamestring— The item name.

Returns

boolean
exports.nx_hud:setStealCheckclient

Decide whether other players can search this player. It runs on the searched player's own client about five times a second, with that player's own ped and server id. nil, or an error, falls back to canBeSearched in inventory/custom/client.lua. Police can search anyone either way. One check at a time: the latest wins.

Parameters

  • fnfunction | nil— fn(ped, serverId) returning true, false, or nil for the default rule. nil removes your check.

Returns

boolean

When a server resource has registered a setSearchCheck, that check is asked first: its true or false decides, police included, and this check only counts when the server check returns nil. When this check stops allowing an open search, the search closes, unless a server check still answers true.

exports.nx_hud:setStealCheck(function(ped, serverId)
    if LocalPlayer.state.isTiedUp then return true end
end)
exports.nx_hud:showItemclient

Show an item to the players around, as the item menu's Show does. The inventory closes, the character holds the item out, and nearby players see its card. Calling it again for the same slot while it shows puts the item away. It waits for the server's answer, so call it from a thread.

Parameters

  • slotnumber— The slot of the item in the player's pockets.

Returns

table

The answer is one of:

AnswerMeaning
{ viewers = n }Shown to n players.
{ stopped = true }That slot was already showing, and now stops.
{ err = key, errText = text }Not shown. key is 'invalid_slot', 'show_disabled' (NxInventory.show.enabled = false), 'busy' (dead, downed, cuffed, in a vehicle or busy), 'show_wait' (the cooldown), 'nobody_nearby', 'timeout', 'off' (the inventory is off) or 'error'. errText is the translated message, which the player has already seen as a notification.

The range, the duration, the cooldown, the animation and a prop per item are set in NxInventory.show (see Configuration).

CreateThread(function()
    local res = exports.nx_hud:showItem(slot)
    if res.viewers then print(('shown to %d players'):format(res.viewers)) end
end)
exports.nx_hud:isCarryingclient

Whether the local player carries an item in their hands, and that item's name. An item with a carry field in data/items.lua is carried while it is in the player's pockets. See Carrying items in Configuration.

Returns

boolean, string | nil
local carrying, item = exports.nx_hud:isCarrying()
if carrying then
    return false, ('Put the %s down first'):format(item)
end

Inventory (server)

Payments

A shop item's currency, a shop's payment field, or a licence's currency names what a purchase is paid with: an item ('money', 'black_money', any item) or a payment method. A shop's payment can also be a list, and the player picks from it in the shop. Shops without one use payments.choices in config/inventory.lua. With nothing set anywhere, the player pays with the money item, as in ox_inventory. Two methods ship in inventory/custom/server.lua:

  • 'bank': paying by card from the player's bank account (ESX account, Qbox money type).
  • 'society:<name>', for example 'society:police': that society's account, for members of that job only. ESX reads esx_addonaccount's society_<name>. Qbox reads Renewed-Banking.

How a purchase is charged:

  1. canAfford is checked before the buyItem hook and again after it.
  2. An item currency is taken right after the goods are placed, as ox_inventory does.
  3. Any other method is charged before the goods are placed, and refunded with refund if they cannot be placed. A refused charge rolls the stock back and hands out nothing.

Every method function receives (src, amount, ctx), where ctx is a fresh copy for each call:

FieldMeaning
kind'shop' or 'license'.
currencyWhat the data names.
methodThe name actually paid with.
accountThe part after the colon for a 'prefix:*' method, for example 'police'.
playerThe buyer's server id.
inventoryThe buyer's inventory id.
price, count, totalThe unit price, the count and the amount charged.
reasonA short text for money logs.
shopType, shopId, itemNameShops only.
requestedShops only: the method the player picked on the till, or nil when none was sent.
license, licenseIndexLicences only.
exports.nx_hud:registerPaymentMethodserver

Add a payment method, or replace one with the same name. A method named like an item ('money') replaces paying with that item. The shop shows the label and, with balance, what the player has, and limits the amount by it. allowed returning false keeps the method from that player. prefix and suffix set how amounts read in the shop and in purchase messages, for example $1,000 (Card) or 1,000 tokens (Casino tokens). Without refund, a charged purchase that cannot complete is logged for a manual refund.

Parameters

  • namestring— The method name used in currency and payment fields. A name ending in ':*' (for example 'society:*') answers every '<prefix>:<account>' name, with ctx.account set to the account.
  • deftable— { label?, canAfford = fn(src, amount, ctx) -> boolean, charge = fn(src, amount, ctx) -> boolean, reason?, refund? = fn(src, amount, ctx), balance? = fn(src, ctx) -> number, allowed? = fn(src, ctx) -> boolean, reason?, prefix? = '$', suffix? = '' }

Returns

true | false, reason
exports.nx_hud:registerPaymentMethod('tokens', {
    label = 'Casino tokens',
    prefix = '', suffix = ' tokens',
    balance = function(src) return exports.my_casino:getTokens(src) end,
    canAfford = function(src, amount) return exports.my_casino:getTokens(src) >= amount end,
    charge = function(src, amount, ctx) return exports.my_casino:takeTokens(src, amount, ctx.reason) end,
    refund = function(src, amount, ctx) return exports.my_casino:giveTokens(src, amount, ctx.reason) end,
})
-- data/shops.lua: a shop item paid with it
{ name = 'scratchcard', price = 5, currency = 'tokens' },
-- or a shop where the player picks cash, card or tokens
payment = { 'money', 'bank', 'tokens' },
exports.nx_hud:removePaymentMethodserver

Remove a payment method your resource registered. Returns false for an unknown name or another resource's method.

Parameters

  • namestring— The method name.

Returns

boolean
exports.nx_hud:setPaymentResolverserver

Choose the payment per purchase. One resolver per resource, asked in registration order. The first name returned wins. After them, resolvePayment in inventory/custom/server.lua is asked. ctx.currency is what the player picked in the shop (or what the item names). While a resolver is registered the shop does not refuse on a balance, because the resolver may pay with something else; the purchase decides.

Parameters

  • fnfunction | nil— fn(src, ctx) returning a method or item name, or nil for what the shop names. nil removes your resolver.

Returns

true | false, reason
-- cash first, the bank when the cash is short
exports.nx_hud:setPaymentResolver(function(src, ctx)
    if ctx.currency == 'money' and exports.ox_inventory:GetItemCount(src, 'money') < ctx.total then
        return 'bank'
    end
end)

Prices

exports.nx_hud:setShopPriceModifierserver

Change what a shop item costs for this player. One modifier per resource, chained in registration order: ctx.price is the price so far and ctx.basePrice the shop's own. A number below 0, or anything that is not a number, keeps the price. A changed price is rounded to a whole number. It applies both to the prices the open shop shows and to the purchase.

Parameters

  • fnfunction | nil— fn(src, ctx) returning the unit price, or nil to keep it. nil removes your modifier.

Returns

true | false, reason

ctx carries shopType, shopId, itemName, count, currency, inventoryId, purpose ('open' or 'buy'), price and basePrice. Return a unit price that does not depend on count: the shop quotes the amount times the one-item price, so a bulk discount would charge less than the shop showed.

-- 10 % off for players with the vip state
exports.nx_hud:setShopPriceModifier(function(src, ctx)
    if Player(src).state.vip then return ctx.price * 0.9 end
end)
exports.nx_hud:setLicencePriceModifierserver

Change what a licence costs for this player. Works like setShopPriceModifier, but for licences only: shop modifiers never touch licence prices. One modifier per resource, chained in registration order. A number below 0, or anything that is not a number, keeps the price. A changed price is rounded to a whole number. The price the player confirms is the price they are charged.

Parameters

  • fnfunction | nil— fn(src, ctx) returning the licence price, or nil to keep it. nil removes your modifier.

Returns

true | false, reason

ctx carries kind ('license'), license (the name in data/licenses.lua), licenseIndex, currency, inventoryId, purpose ('quote' for the confirmation, 'buy' for the purchase), price and basePrice. Return the same price for both purposes, or the player is charged something other than what they agreed to.

-- half price on the hunting licence for players with the veteran state
exports.nx_hud:setLicencePriceModifier(function(src, ctx)
    if ctx.license == 'hunting' and Player(src).state.veteran then
        return ctx.price * 0.5
    end
end)

Searching players

exports.nx_hud:setSearchCheckserver

Decide whether src may search target. One check per resource, asked in registration order before the default rule (police, or a target who can be searched). The first true or false decides; nil leaves it to the default rule. The reach in NxInventory.rules.searchReach still applies.

Parameters

  • fnfunction | nil— fn(src, target) returning true to allow, false to refuse, or nil to leave it to the default rule. nil removes your check.

Returns

true | false, reason

While any resource has a check registered, the server makes the whole decision. A true opens the search even when the target's own client would not count them as searchable (see setStealCheck), so state you keep only on the server, such as zip-ties, is enough. The check is asked again several times a second while the search is open: when it answers false, or nil and the default rule no longer allows it, the search closes and the searcher is told why. The searcher must still stay next to the target. Keep the function quick and free of side effects. A refused search shows the player the usual "cannot open" notice.

local ZipTied = {}   -- [serverId] = true, set by your zip-tie item on the server

exports.nx_hud:setSearchCheck(function(src, target)
    if Player(target).state.inSafeZone then return false end
    if ZipTied[target] then return true end
end)

Carrying

exports.nx_hud:getCarryserver

What the player carries in their hands, or nil when they carry nothing. When several carry items are in the pockets, the heaviest is carried.

Parameters

  • sourcenumber— The player's server id.

Returns

table | nil

The table holds item (the item name), preset, model, bone, pos and rot ({ x, y, z }), dict, clip and flag (the animation), and what the carrier may do: sprint, jump, vehicle, weapon and walk, plus onDeath. The fields are described under Carrying items.

local carry = exports.nx_hud:getCarry(source)
if carry and carry.vehicle == false then
    return false, 'You cannot drive while carrying that'
end

Worn gear

A bag, a vest, a watch or a bracelet the player wears sits in its own gear slot, next to the pockets, and no longer takes a pocket slot. It still belongs to the player's inventory:

  • It counts towards the player's weight and is saved with them.
  • Search, GetItemCount, GetSlotWithItem, HasItem and the other ox_inventory exports find it. RemoveItem takes it like any other item.
  • Taking it off needs a free pocket slot. With the pockets full it stays on, and the player is told why.
  • A player who searches or robs another sees the other player's worn items in a strip on their side, and can drag one into their own pockets.
  • An item that leaves the player's inventory, by a give, a drop, a stash or a search, is no longer worn.

Which items can be worn, and on which socket, is set on the item in data/items.lua (see Wearable items). The sockets are in NxInventory.accessories (see Configuration). When the worn gear changes, the server raises nx_hud:wornChanged.

Client

exports.nx_hud:getWornAccessoriesclient

What the local player wears, as { [socket] = { name, slot, label, metadata } }. The same shape as the server export. An empty table when nothing is worn or worn gear is turned off.

Returns

table
local worn = exports.nx_hud:getWornAccessories()
if worn.watch then
    print(('wearing %s on the left wrist'):format(worn.watch.label))
end
exports.nx_hud:getWornclient

The worn items the local player's ped shows, as { [socket] = { slot, name, label, drawable, texture } }, with the clothing numbers in use. An item whose look has nothing for the ped's model is left out; getWornAccessories lists it.

Returns

table

Server

exports.nx_hud:getWornAccessoriesserver

What the player wears, as { [socket] = { name, slot, label, metadata } }. slot is the item's gear slot, label the item's metadata label or its item label. An empty table when the player wears nothing, has no inventory loaded, or worn gear is turned off.

Parameters

  • sourcenumber— The player's server id.

Returns

table
local worn = exports.nx_hud:getWornAccessories(source)
for socket, item in pairs(worn) do
    print(socket, item.name, item.slot)
end
-- watch    watch_classic    51
-- back     backpack         52
exports.nx_hud:getWornserver

The slot of each worn item, as { [socket] = slot }. An empty table when nothing is worn.

Parameters

  • sourcenumber— The player's server id.

Returns

table
exports.nx_hud:setWornserver

Put an item on or take it off, as the player would. It counts towards the player's swap rate limit.

Parameters

  • sourcenumber— The player's server id.
  • slotnumber— The item's slot: a pocket slot to put it on, or its gear slot (from getWorn) to take it off.
  • socketstring | boolean— A socket name the item fits, true for the first free socket, or false to take it off.

Returns

true | false, reason

How socket is read:

  • A socket name, for example 'bracelet': the item goes on that socket. Whatever was worn there comes off into the pocket slot this item leaves.
  • true: an item already worn stays where it is. Otherwise it takes the first free socket in its order (see Wearable items). When every socket it fits is taken, it goes on the first one and that socket's item comes off.
  • false: the item comes off into the first free pocket slot.

The reasons it returns:

ReasonMeaning
'accessory_no_item'No item in that slot.
'accessory_not_wearable'The item has no socket configured on this server.
'accessory_wrong_socket'The item does not fit that socket.
'accessory_no_room'No free pocket slot for the item that comes off.
'gear_overweight'Taking the bag off would leave the pockets over their weight limit.
'accessory_busy'The player is over their swap rate limit. Try again a moment later.
'accessory_disabled'NxInventory.accessories.enabled is false.
'invalid_inventory'The player has no inventory loaded.
'error'Something failed. The console has the details.
-- put a bracelet on whichever wrist is free
local ok, err = exports.nx_hud:setWorn(source, slot, true)
if not ok then print('could not put it on: ' .. err) end

-- take the watch off
local worn = exports.nx_hud:getWorn(source)
if worn.watch then exports.nx_hud:setWorn(source, worn.watch, false) end
exports.nx_hud:getWornBagserver

The bag the player wears, or false when they wear none. The table holds slot, name, id (the bag's own inventory id), slots, weight, maxWeight and bonus (what the bag adds to the pockets' weight limit).

Parameters

  • sourcenumber— The player's server id.

Returns

table | false
local bag = exports.nx_hud:getWornBag(source)
if bag then
    print(('%s: %d of %d g'):format(bag.name, bag.weight, bag.maxWeight))
end
exports.nx_hud:getPlatesserver

The plates in the player's worn vest, or false when they wear no vest. The table holds slot, name and plates, a list with one entry per plate pocket, front first: { name, hp, max } for a plate, false for an empty pocket. The player's armour is the plates' hp added up, at most 100.

Parameters

  • sourcenumber— The player's server id.

Returns

table | false
local vest = exports.nx_hud:getPlates(source)
if vest then
    for i, plate in ipairs(vest.plates) do
        print(i, plate and ('%s %d/%d'):format(plate.name, plate.hp, plate.max) or 'empty')
    end
end

Crafting (server)

exports.nx_hud:registerCraftingBenchserver

Add a crafting bench at runtime. Registering the same id again replaces it, and it wins over a data/crafting.lua bench with the same id. Players get it without a restart. Functions in a recipe's resultMetadata stay on the server.

Parameters

  • idstring | number— The bench id. It takes the place of name in a data/crafting.lua entry.
  • benchtable— A bench in the shape of a data/crafting.lua entry: label, groups, blip, points, zones and items (the recipes).

Returns

true | false, reason
exports.nx_hud:registerCraftingBench('gang_bench', {
    label = 'Workbench',
    groups = { ballas = 0 },
    zones = { { coords = vec3(-1.6, -1812.9, 29.1), size = vec3(1.6, 0.8, 1.2), rotation = 50.0, distance = 1.8 } },
    points = { vec3(-1.6, -1812.9, 29.1) },
    items = {
        { name = 'lockpick', ingredients = { metal_scrap = 2 }, duration = 4000, chance = 0.8, failResult = 'keep' },
    },
})
exports.nx_hud:removeCraftingBenchserver

Remove a bench your resource registered. Returns false for an unknown id or another resource's bench.

Parameters

  • idstring | number— The bench id.

Returns

boolean

Recipe fields

A recipe in data/crafting.lua, or in a bench you register, takes these fields on top of ox_inventory's. A recipe without them crafts as before.

FieldMeaning
chance0 to 1, default 1. The roll happens after the progress bar.
hideChancetrue keeps the chance secret. The roll still happens, but the bench doesn't show the percentage.
failResultWhat a failed roll costs. 'consume' (default) uses the ingredients and makes nothing. 'keep' takes nothing.
requires{ groups = { name = grade } or 'job', license = 'name', items = { tool = count } }. Checked before anything is taken. The items are held, never used up.
resultMetadataA table merged over the recipe's metadata, or function(src, recipe) returning one.

What players see at the bench:

  • Chance. A recipe with a chance below 1 shows it next to the craft time, for example "72% chance". The recipe's details also say whether a miss uses the parts. Set hideChance = true to leave it out.
  • Requirements. A recipe the player can't make yet is greyed out and says why: "Needs the mechanic job", "Needs the police job, grade 2", "Needs a licence: weapon" or "Needs a wrench". Each tool in requires.items shows next to the ingredients, and it turns ready as soon as the player picks one up. If a player tries anyway, the notice names the missing piece.
  • Failed rolls. The craft queue shows how each craft ended. A failed roll reads "Failed, parts used" (failResult = 'consume') or "Failed, nothing used" ('keep'), and the player gets a notice that says the same.
{
    name = 'WEAPON_PISTOL',
    ingredients = { gun_parts = 4, metal_scrap = 10 },
    duration = 12000,
    chance = 0.6,
    requires = { license = 'weapon', items = { gun_toolkit = 1 } },
    resultMetadata = { registered = false },
},

Combine recipes

A player drags one item onto another in their own pockets. When a recipe names that pair, a short progress bar runs and the two become something else. The recipes that ship are in NxInventory.combine in config/inventory.lua (see Configuration).

FieldMeaning
itemsThe two items, { 'a', 'b' }, in either order. They must be different items.
consumeHow many of each are used, { a = 1, b = 0 }. 0 is a tool that is kept. An item left out uses 1. The amount must be in the slot that was dragged.
resultWhat is made: { { 'name', count, metadata? }, ... }. A single 'name' or { 'name', count } works too.
durationThe progress in milliseconds. Default 1500, at most 4500.
labelThe progress text. Default "Making" and the result's label.
animA progress animation, { dict, clip } or { scenario }.
chance, failResult, requiresAs for a bench recipe, see Recipe fields.

The craftResult hook runs for combines too, with payload.combine set to the recipe id and no benchId.

exports.nx_hud:registerCombineserver

Add a combine recipe at runtime. Registering the same id again replaces it, also a recipe from config/inventory.lua (those are 'cfg:1', 'cfg:2' and so on, unless they set an id). A registered recipe wins over a config recipe for the same pair. Players get it without a restart. Returns false and a reason that says which field is wrong.

Parameters

  • idstring | number— The recipe id.
  • recipetable— A recipe with the fields above.

Returns

true | false, reason
exports.nx_hud:registerCombine('my_pipebomb', {
    items = { 'pipe', 'gunpowder' },
    consume = { pipe = 1, gunpowder = 2 },
    result = { { 'pipebomb', 1 } },
    duration = 4000,
    chance = 0.9,
    requires = { items = { screwdriver = 1 } },
})
exports.nx_hud:removeCombineserver

Remove a combine recipe your resource registered. Returns false for an unknown id or another resource's recipe.

Parameters

  • idstring | number— The recipe id.

Returns

boolean

Hook events

nx_hud adds five events to ox_inventory's registerHook, and extends two of ox's own (openInventory and buyItem). Register them with exports.ox_inventory:registerHook, the same way as ox's own events.

shopPrice

Asked for each shop slot when a shop opens, and again at the purchase. Return a number of 0 or more to replace the price. It runs after the price modifiers, and each hook sees the price the hooks before it set. It is a query, so it fires no post-hook events.

Payload: source, shopType, shopId, itemName, count, price, basePrice, currency, inventoryId, purpose ('open' or 'buy').

exports.ox_inventory:registerHook('shopPrice', function(payload)
    if payload.shopType == 'ammunation' and isHappyHour() then
        return payload.price * 0.5
    end
end)

licencePrice

Asked when a player is shown a licence's price, and again at the purchase. Return a number of 0 or more to replace the price. It runs after the licence price modifiers, and each hook sees the price the hooks before it set. It is a query, so it fires no post-hook events.

Payload: source, licenseName, licenseIndex, price, basePrice, currency, purpose ('quote' or 'buy').

exports.ox_inventory:registerHook('licencePrice', function(payload)
    if payload.licenseName == 'fishing' and isFishingWeek() then
        return 0
    end
end)

buyLicense

Fires before a licence is bought, and before the framework checks whether the player already has it. Return false to refuse. The player is told they can't buy the licence right now.

Payload: source, licenseName, licenseIndex, price (after the licence price modifiers and licencePrice hooks), basePrice (the price in data/licenses.lua), currency.

exports.ox_inventory:registerHook('buyLicense', function(payload)
    if payload.licenseName == 'weapon' and hasRecord(payload.source) then
        return false
    end
end)

craftResult

Fires after the progress bar and the chance roll, before anything is taken. Return false to cancel the craft: nothing is used up and nothing is made. Return a table to replace the result's metadata.

Payload: source, benchId, benchIndex, recipe, toInventory, toSlot, success (the roll), count, metadata. For a combine, combine is the recipe id and benchId is nil.

exports.ox_inventory:registerHook('craftResult', function(payload)
    if payload.success then
        local meta = payload.metadata or {}
        meta.crafter = GetPlayerName(payload.source)
        return meta
    end
end)

openLockedVehicle

Asked when a player opens the trunk of a locked vehicle, so a vehicle keys script can let them in: with a crowbar, as on-duty police, or for the key holder. Return true to open it. Return false to refuse, with an optional text as the second value that the player sees instead of the usual "locked" notice, or false, false to show nothing (your script told the player itself). Any other answer, and no hook at all, keeps the trunk locked.

Only an explicit true opens it. A hook on openInventory that allows every open does not unlock cars. After a true, the openInventory hooks still run, with locked = true in their payload.

Payload: source, inventoryId, inventoryType ('trunk'), netId, plate, lockStatus (the game's door lock status). registerHook's filters, such as inventoryFilter, apply.

exports.ox_inventory:registerHook('openLockedVehicle', function(payload)
    if exports.my_keys:hasKey(payload.source, payload.plate) then
        return true
    end
    if Player(payload.source).state.crowbar then
        return true
    end
    return false, 'You need the keys or a crowbar'
end)

openInventory

ox_inventory's openInventory hook can say why it refuses. Return false, 'text' and the player sees that text (or its translation, when it is a key from inventory/locales/) instead of the usual "cannot open" notice. Return false, false to show nothing. A plain false shows the usual notice, as in ox_inventory. The payload gains locked = true for a locked trunk that an openLockedVehicle hook opened.

exports.ox_inventory:registerHook('openInventory', function(payload)
    if payload.inventoryType == 'stash' and isRaidActive() then
        return false, 'The stash is sealed during a raid'
    end
end)

buyItem

ox_inventory's buyItem payload gains a payment field: the payment method's name when the purchase is paid with a method, and nil when it is paid with an item.

NX Docs