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:hideHudclientHide the HUD for your resource. Returns whether the HUD is visible now.
Returns
booleanexports.nx_hud:hideHud() -- for a cutscene
-- later
exports.nx_hud:showHud()exports.nx_hud:showHudclientRelease your resource's hide. Returns whether the HUD is visible now: false while another resource still hides it.
Returns
booleanexports.nx_hud:toggleHudclientFlip your resource's own hide. Returns whether the HUD is visible now.
Returns
booleanexports.nx_hud:setHudVisibleclientSet 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
booleanexports.nx_hud:setHudVisible(not inCamera)exports.nx_hud:isHudVisibleclientWhether the HUD is visible, that is, no resource hides it.
Returns
booleanStrict 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).
Seatbelt
exports.nx_hud:isSeatbeltOnclientWhether 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
booleanif not exports.nx_hud:isSeatbeltOn() then
-- apply your own crash damage
endexports.nx_hud:getSeatbeltclientThe same as isSeatbeltOn, under the name some scripts expect.
Returns
booleanexports.nx_hud:registerSeatbeltReaderclientMake 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
booleanexports.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:setStatusclientOverride 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
booleanexports.nx_hud:setStatus('stress', 45)
-- give the gauge back to the framework
exports.nx_hud:setStatus('stress', nil)exports.nx_hud:getStatusclientWhat the gauge shows now, 0 to 100, or nil when nothing provides that status.
Parameters
keystring— 'hunger', 'thirst' or 'stress'.
Returns
number | nilexports.nx_hud:moneyPopclientShow 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
booleanexports.nx_hud:moneyPop('crypto', -250, 1750)Fuel
exports.nx_hud:registerFuelReaderclientFeed 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
booleanexports.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:registerAmmoReaderclientFeed 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
booleanWhat the reader returns:
| Value | Meaning |
|---|---|
loaded | The number in the magazine part of the pill. nil lets nx_hud read the weapon as usual. |
capacity | Optional. A full load, used for the low and empty colours. |
spare | Optional. 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:pushHitclientFlash 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
booleanexports.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:getSettingsclientThe 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
endTo follow changes, listen for
nx_hud:settingsChanged.
exports.nx_hud:getSettingsserverA 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, reasonlocal 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
endexports.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
tableInventory (client)
The defaults these sit on are in inventory/custom/client.lua, which you
can edit directly. See
Customization.
exports.nx_hud:addOpenGateclientDecide 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 | nilctx.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:addUseGateclientDecide 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 | nilexports.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:removeGateclientRemove 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
booleanexports.nx_hud:registerItemEffectclientSet 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
booleanexports.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:removeItemEffectclientRemove 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
booleanexports.nx_hud:setStealCheckclientDecide 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
booleanWhen 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:showItemclientShow 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
tableThe answer is one of:
| Answer | Meaning |
|---|---|
{ 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:isCarryingclientWhether 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 | nillocal carrying, item = exports.nx_hud:isCarrying()
if carrying then
return false, ('Put the %s down first'):format(item)
endInventory (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 readsesx_addonaccount'ssociety_<name>. Qbox reads Renewed-Banking.
How a purchase is charged:
canAffordis checked before thebuyItemhook and again after it.- An item currency is taken right after the goods are placed, as ox_inventory does.
- Any other method is charged before the goods are placed, and refunded
with
refundif 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:
| Field | Meaning |
|---|---|
kind | 'shop' or 'license'. |
currency | What the data names. |
method | The name actually paid with. |
account | The part after the colon for a 'prefix:*' method, for example 'police'. |
player | The buyer's server id. |
inventory | The buyer's inventory id. |
price, count, total | The unit price, the count and the amount charged. |
reason | A short text for money logs. |
shopType, shopId, itemName | Shops only. |
requested | Shops only: the method the player picked on the till, or nil when none was sent. |
license, licenseIndex | Licences only. |
exports.nx_hud:registerPaymentMethodserverAdd 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, reasonexports.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:removePaymentMethodserverRemove a payment method your resource registered. Returns false for an unknown name or another resource's method.
Parameters
namestring— The method name.
Returns
booleanexports.nx_hud:setPaymentResolverserverChoose 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:setShopPriceModifierserverChange 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, reasonctx 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:setLicencePriceModifierserverChange 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, reasonctx 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:setSearchCheckserverDecide 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, reasonWhile 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:getCarryserverWhat 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 | nilThe 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'
endWorn 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,HasItemand the other ox_inventory exports find it.RemoveItemtakes 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:getWornAccessoriesclientWhat 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
tablelocal worn = exports.nx_hud:getWornAccessories()
if worn.watch then
print(('wearing %s on the left wrist'):format(worn.watch.label))
endexports.nx_hud:getWornclientThe 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
tableServer
exports.nx_hud:getWornAccessoriesserverWhat 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
tablelocal 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 52exports.nx_hud:getWornserverThe slot of each worn item, as { [socket] = slot }. An empty table when nothing is worn.
Parameters
sourcenumber— The player's server id.
Returns
tableexports.nx_hud:setWornserverPut 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, reasonHow 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:
| Reason | Meaning |
|---|---|
'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) endexports.nx_hud:getWornBagserverThe 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 | falselocal bag = exports.nx_hud:getWornBag(source)
if bag then
print(('%s: %d of %d g'):format(bag.name, bag.weight, bag.maxWeight))
endexports.nx_hud:getPlatesserverThe 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 | falselocal 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
endCrafting (server)
exports.nx_hud:registerCraftingBenchserverAdd 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, reasonexports.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:removeCraftingBenchserverRemove a bench your resource registered. Returns false for an unknown id or another resource's bench.
Parameters
idstring | number— The bench id.
Returns
booleanRecipe 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.
| Field | Meaning |
|---|---|
chance | 0 to 1, default 1. The roll happens after the progress bar. |
hideChance | true keeps the chance secret. The roll still happens, but the bench doesn't show the percentage. |
failResult | What 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. |
resultMetadata | A 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 = trueto 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.itemsshows 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).
| Field | Meaning |
|---|---|
items | The two items, { 'a', 'b' }, in either order. They must be different items. |
consume | How 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. |
result | What is made: { { 'name', count, metadata? }, ... }. A single 'name' or { 'name', count } works too. |
duration | The progress in milliseconds. Default 1500, at most 4500. |
label | The progress text. Default "Making" and the result's label. |
anim | A progress animation, { dict, clip } or { scenario }. |
chance, failResult, requires | As 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:registerCombineserverAdd 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, reasonexports.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:removeCombineserverRemove a combine recipe your resource registered. Returns false for an unknown id or another resource's recipe.
Parameters
idstring | number— The recipe id.
Returns
booleanHook 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.
Customization
The files of nx_hud you can read and edit. Configs, data, inventory gameplay, payment methods, framework bridges, the HUD's data adapters and translations, with a worked example of a custom payment method.
Commands
Keybinds, player commands, HUD placement commands, and the admin commands for the inventory, targeting and zones in nx_hud.