Exports
Server-side exports for Possible Gang Levels.
The resource folder on your server must be named exactly possible-gang-levels. Do not rename it. Gang MDT and other Possible Scripts look for that name.
AddGangXPForPlayer
Add XP to a gang and credit a player's contribution.
exports['possible-gang-levels']:AddGangXPForPlayer(source, gangName, xp, playerName)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
source | number | ✅ | Player server id (notified of the XP gain) |
gangName | string | ✅ | Gang name (e.g. "ballas") |
xp | number | ✅ | XP to add |
playerName | string | ✅ | Character name for contribution tracking |
Example
local Player = exports.qbx_core:GetPlayer(source)local gangName = Player.PlayerData.gang.namelocal playerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
if gangName ~= 'none' then exports['possible-gang-levels']:AddGangXPForPlayer(source, gangName, 5, playerName)endlocal QBCore = exports['qb-core']:GetCoreObject()local Player = QBCore.Functions.GetPlayer(source)local gangName = Player.PlayerData.gang.namelocal playerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
if gangName ~= 'none' then exports['possible-gang-levels']:AddGangXPForPlayer(source, gangName, 5, playerName)endlocal xPlayer = ESX.GetPlayerFromId(source)local gangName = xPlayer.getJob().namelocal playerName = xPlayer.getName()
if gangName ~= 'unemployed' then exports['possible-gang-levels']:AddGangXPForPlayer(source, gangName, 5, playerName)endRemoveGangXPForPlayer
Remove XP from a gang. Optionally reduce that player's contribution too.
exports['possible-gang-levels']:RemoveGangXPForPlayer(targetPlayer, gangName, xp, playerName)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
targetPlayer | number | ✅ | Player server id to notify |
gangName | string | ✅ | Gang name |
xp | number | ✅ | XP to remove |
playerName | string | ❌ | If set, also reduces that member's contribution |
Example
local Player = exports.qbx_core:GetPlayer(source)local gangName = Player.PlayerData.gang.namelocal playerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
if gangName ~= 'none' then exports['possible-gang-levels']:RemoveGangXPForPlayer(source, gangName, 5, playerName)endlocal QBCore = exports['qb-core']:GetCoreObject()local Player = QBCore.Functions.GetPlayer(source)local gangName = Player.PlayerData.gang.namelocal playerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
if gangName ~= 'none' then exports['possible-gang-levels']:RemoveGangXPForPlayer(source, gangName, 5, playerName)endlocal xPlayer = ESX.GetPlayerFromId(source)local gangName = xPlayer.getJob().namelocal playerName = xPlayer.getName()
if gangName ~= 'unemployed' then exports['possible-gang-levels']:RemoveGangXPForPlayer(source, gangName, 5, playerName)endGetGangLevel
Async — callback only (does not return a level synchronously).
exports['possible-gang-levels']:GetGangLevel(gangName, callback)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
gangName | string | ✅ | Gang name |
callback | function | ✅ | Called with gangLevel (number) or nil if not found |
Example
local Player = exports.qbx_core:GetPlayer(source)local gangName = Player.PlayerData.gang.name
if gangName ~= 'none' then exports['possible-gang-levels']:GetGangLevel(gangName, function(gangLevel) if gangLevel and gangLevel >= 3 then print(gangName .. ' is level ' .. gangLevel) end end)endlocal QBCore = exports['qb-core']:GetCoreObject()local Player = QBCore.Functions.GetPlayer(source)local gangName = Player.PlayerData.gang.name
if gangName ~= 'none' then exports['possible-gang-levels']:GetGangLevel(gangName, function(gangLevel) if gangLevel and gangLevel >= 3 then print(gangName .. ' is level ' .. gangLevel) end end)endlocal xPlayer = ESX.GetPlayerFromId(source)local gangName = xPlayer.getJob().name
if gangName ~= 'unemployed' then exports['possible-gang-levels']:GetGangLevel(gangName, function(gangLevel) if gangLevel and gangLevel >= 3 then print(gangName .. ' is level ' .. gangLevel) end end)endGetXPRequiredForLevel
exports['possible-gang-levels']:GetXPRequiredForLevel(level)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
level | number | ✅ | Level from config.LevelRanges |
Returns
| Type | Description |
|---|---|
number|nil | XP threshold for that level |
GetXPForNextLevel
exports['possible-gang-levels']:GetXPForNextLevel(currentLevel)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
currentLevel | number | ✅ | Current gang level |
Returns
| Type | Description |
|---|---|
number|nil | XP needed for the next level, or nil at max level |
CalculateGangLevel
exports['possible-gang-levels']:CalculateGangLevel(xp)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
xp | number | ✅ | Total gang XP |
Returns
| Type | Description |
|---|---|
number | Level for that XP amount |
Shop management (MDT)
Needs ShopManagement.Mode = 'database' and ShopManagement.AllowMdtManagement = true.
After the first seed from config.Shops / config.ShopItems, set ShopManagement.SeedFromConfig = false so in-game / MDT changes are not overwritten on restart.
IsShopManagementEnabled
exports['possible-gang-levels']:IsShopManagementEnabled() -- booleanGetAllGangShopLocations / GetGangShopLocation
local locations = exports['possible-gang-levels']:GetAllGangShopLocations()local location = exports['possible-gang-levels']:GetGangShopLocation('ballas')Optional callback as last arg. Each location: gang_name, coord_x, coord_y, coord_z, radius, enabled.
UpdateGangShopLocation
local ok, err = exports['possible-gang-levels']:UpdateGangShopLocation('ballas', { coord_x = x, coord_y = y, coord_z = z, radius = 3.0, enabled = true,}, updatedBy)| Name | Type | Required | Description |
|---|---|---|---|
gangName | string | ✅ | Gang name |
data | table | ✅ | Coords required (coord_x/y/z or coords.x/y/z). Optional radius, enabled |
updatedBy | string | ❌ | Who changed it (logging) |
cb | function | ❌ | Optional (success, errorMessage) |
GetAllShopItems / AddShopItem / UpdateShopItem / RemoveShopItem
local items = exports['possible-gang-levels']:GetAllShopItems()
exports['possible-gang-levels']:AddShopItem({ item_spawn_name = 'lockpick', item_label = 'Lockpick', price = 100, required_gang_level = 1,}, updatedBy)
exports['possible-gang-levels']:UpdateShopItem('lockpick', { price = 150 }, updatedBy)exports['possible-gang-levels']:RemoveShopItem('lockpick', updatedBy, nil, false) -- soft disable; hardDelete = true to deleteItem fields accept snake_case or camelCase (itemSpawnName, requiredGangLevel, etc.).
Stash management (MDT)
Needs StashLocations.Mode = 'database' and StashLocations.AllowMdtManagement = true.
After seeding, set StashLocations.SeedFromConfig = false so MDT moves are not overwritten on restart.
IsStashManagementEnabled
exports['possible-gang-levels']:IsStashManagementEnabled() -- booleanGetAllGangStashLocations / GetGangStashLocation
local locations = exports['possible-gang-levels']:GetAllGangStashLocations()local location = exports['possible-gang-levels']:GetGangStashLocation('ballas')Each location: gang_name, stash_id, label, coord_x, coord_y, coord_z, radius, enabled.
UpdateGangStashLocation
local ok, err = exports['possible-gang-levels']:UpdateGangStashLocation('ballas', { coord_x = x, coord_y = y, coord_z = z, radius = 2.0, label = 'Ballas Stash', enabled = true,}, updatedBy)| Name | Type | Required | Description |
|---|---|---|---|
gangName | string | ✅ | Gang name |
data | table | ✅ | Coords required. Optional radius, label, enabled. stash_id cannot change |
updatedBy | string | ❌ | Who changed it |
cb | function | ❌ | Optional (success, errorMessage) |
State bags
Gang Levels does not set its own state bags. See State Bags.
