NPC Interaction

The NPC Interaction module provides a highly immersive, cinematic dialogue system for your server. When a player interacts with an NPC, the script automatically aligns the player, creates a cinematic camera angle focusing on the NPC, and displays a sleek UI for dialogues and options. It fully supports nested submenus, conditional options, and event triggering.
📚 Available Exports
RegisterNpcInteract
Registers an interaction menu to a specific NPC entity. This must be called before attempting to show the menu.
Syntax:
exports['ak47_lib']:RegisterNpcInteract(entity, data)Parameters:
| Parameter | Type | Description |
|---|---|---|
entity |
integer |
The network ID or handle of the ped/entity. |
data |
table |
The configuration object containing dialogues, styling, and options. |
ShowNpcInteract
Opens a previously registered NPC interaction menu.
Syntax:
exports['ak47_lib']:ShowNpcInteract(id, focusIndex)Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
The unique ID defined in your RegisterNpcInteract data table. |
focusIndex |
integer (Optional) |
The index of the option you want to be pre-selected/focused. |
HideNpcInteract
Forcefully closes the currently open NPC interaction menu.
Syntax:
exports['ak47_lib']:HideNpcInteract(runOnExit)Parameters:
| Parameter | Type | Description |
|---|---|---|
runOnExit |
boolean |
If true, triggers the onExit callback defined in the NPC's data table. |
⚙️ Configuration Objects
The data Table
This table configures the overarching menu for the NPC.
| Property | Type | Description |
|---|---|---|
id |
string |
Required. A unique identifier for this interaction menu. |
colors |
table |
Optional. Override default UI colors (colorPrimary, colorSecondary, colorText). |
dialogues |
table |
An array of strings. The menu will pick one at random to display as a greeting. |
menu |
string |
Optional. The id of a parent menu. Enables native "Back" button functionality. |
onExit |
function |
Optional. A callback triggered when the menu is closed. |
options |
table |
Required. An array of Option objects. |
The Option Object
Each item inside the options array represents a clickable button.
| Property | Type | Description |
|---|---|---|
label |
string |
Required. The text displayed on the button. |
icon |
string |
FontAwesome icon name (e.g., car, comments, person-walking-arrow-right). |
iconColor |
string |
Hex code to color the icon (e.g., #3498db). |
isVisible |
function |
Returns a boolean. If false, the option is completely hidden. |
disabled |
boolean |
If true, the option is shown but grayed out/unclickable. |
canInteract |
function |
Returns a boolean. Overrides disabled dynamically based on logic. |
onSelect |
function |
Callback triggered when the player clicks this option. |
event |
string |
A Client event to trigger when clicked. |
serverEvent |
string |
A Server event to trigger when clicked. |
menu |
string |
Automatically opens another registered NPC menu id (acts as a submenu). |
Note on Navigation: You can navigate to a submenu using the
menu = 'target_id'property inside an option, or manually inside theonSelectfunction by callingexports['ak47_lib']:ShowNpcInteract('target_id').
💡 Examples
Example 1: Basic Shop Ped
A simple interaction with a single ped offering basic choices.
local shopPedId = 0 -- Assuming you have already spawned your ped here
exports['ak47_lib']:RegisterNpcInteract(shopPedId, {
id = 'hardware_store_main',
colors = {
colorPrimary = "rgba(20, 20, 20, 0.95)",
colorSecondary = "#ffaa00",
colorText = "#ffffff",
},
dialogues = {
"Need some tools?",
"Welcome to the hardware store. What can I get ya?",
"Make it quick, I'm busy."
},
onExit = function()
print("Player walked away from the hardware store.")
end,
options = {
{
label = 'Open Shop',
icon = 'basket-shopping',
iconColor = '#ffaa00',
onSelect = function()
-- Put your shop opening logic here
TriggerEvent('inventory:client:openShop', 'hardware')
end
},
{
label = 'Leave',
icon = 'person-walking-arrow-right',
iconColor = '#e74c3c'
}
}
})
-- To open it (usually triggered via target system like qb-target or ox_target):
-- exports['ak47_lib']:ShowNpcInteract('hardware_store_main')Example 2: Dialogue Trees (Submenus & Back Buttons)
This example demonstrates how to create a conversation tree where the player can ask questions, go into a submenu, and hit a "Back" button to return to the main choices.
local guidePedId = 0 -- Assuming spawned ped
-- 1. Register the Main Menu
exports['ak47_lib']:RegisterNpcInteract(guidePedId, {
id = 'tour_guide_main',
dialogues = {
"Hello traveler! Want to know more about the city?"
},
options = {
{
label = 'Ask about the City',
icon = 'city',
iconColor = '#3498db',
-- Use the `menu` parameter to automatically link a submenu!
menu = 'tour_guide_city_info'
},
{
label = 'Goodbye',
icon = 'hand-wave',
iconColor = '#e74c3c'
}
}
})
-- 2. Register the Submenu
exports['ak47_lib']:RegisterNpcInteract(guidePedId, {
id = 'tour_guide_city_info',
menu = 'tour_guide_main', -- Defining this parent menu enables the native "Back" button
dialogues = {
"The city was founded in 1904. We have a rich history!"
},
options = {
{
label = 'Ask about the Mayor',
icon = 'user-tie',
iconColor = '#9b59b6',
onSelect = function()
print("The mayor is currently out of town.")
end
},
{
label = 'Ask about local gangs',
icon = 'skull',
iconColor = '#e67e22',
onSelect = function()
print("We don't talk about them around here...")
end
}
}
})Example 3: Conditional & Restricted Options
Sometimes you only want specific players (like police) to see an option, or you want to show an option but disable it if they don't have enough money.
local shadyPedId = 0
exports['ak47_lib']:RegisterNpcInteract(shadyPedId, {
id = 'shady_dealer',
dialogues = {
"You got the cash or what?"
},
options = {
{
label = 'Buy Lockpick ($500)',
icon = 'key',
iconColor = '#f1c40f',
-- Option is visible, but might be disabled
canInteract = function()
local hasEnoughMoney = true -- Replace with actual framework money check
return hasEnoughMoney
end,
onSelect = function()
TriggerServerEvent('shadydealer:buyLockpick')
end
},
{
label = '(Police) Confiscate Goods',
icon = 'shield-halved',
iconColor = '#3498db',
-- This completely hides the option if they aren't a cop
isVisible = function()
local isCop = false -- Replace with actual framework job check
return isCop
end,
onSelect = function()
TriggerServerEvent('police:confiscateNPC')
end
},
{
label = 'Walk away',
icon = 'person-walking-arrow-right',
iconColor = '#e74c3c'
}
}
})