2025-04-07 01:41:12 +00:00

268 lines
9.5 KiB
Lua

local config = require 'config.client'
local JOBS = exports.qbx_core:GetJobs()
local GANGS = exports.qbx_core:GetGangs()
local isLoggedIn = LocalPlayer.state.isLoggedIn
local dynamicMenuItems = {}
-- Adds item to the boss/gang menu.
---@param menuItem ContextMenuItem Requires args.type to be set to know which menu to place in.
---@return number? menuId ID of the menu item added
local function addMenuItem(menuItem)
local menuId = #dynamicMenuItems + 1
if not menuItem.args.type then return end
dynamicMenuItems[menuId] = lib.table.deepclone(menuItem)
return menuId
end
exports('AddBossMenuItem', addMenuItem)
exports('AddGangMenuItem', addMenuItem)
-- Remove menu item at particular id
---@param id number Menu ID to remove
local function removeMenuItem(id)
dynamicMenuItems[id] = nil
end
exports('RemoveBossMenuItem', removeMenuItem)
exports('RemoveGangMenuItem', removeMenuItem)
-- Finds nearby players and returns a table of server ids
---@return table
local function findPlayers()
local coords = GetEntityCoords(cache.ped)
local closePlayers = lib.getNearbyPlayers(coords, 10, false)
for _, v in pairs(closePlayers) do
v.id = GetPlayerServerId(v.id)
end
return lib.callback.await('qbx_management:server:getPlayers', false, closePlayers)
end
-- Presents a menu to manage a specific employee including changing grade or firing them
---@param player table Player data for managing a specific employee
---@param groupName string Name of job/gang of employee being managed
---@param groupType GroupType
local function manageEmployee(player, groupName, groupType)
local employeeMenu = {}
local employeeLoop = groupType == 'gang' and GANGS[groupName].grades or JOBS[groupName].grades
for groupGrade, gradeTitle in pairs(employeeLoop) do
employeeMenu[#employeeMenu + 1] = {
title = gradeTitle.name,
description = locale('menu.grade')..groupGrade,
onSelect = function()
lib.callback.await('qbx_management:server:updateGrade', false, player.cid, player.grade, tonumber(groupGrade), groupType)
OpenBossMenu(groupType)
end,
}
end
table.sort(employeeMenu, function(a, b)
return a.description < b.description
end)
employeeMenu[#employeeMenu + 1] = {
title = groupType == 'gang' and locale('menu.expel_gang') or locale('menu.fire_employee'),
icon = 'user-large-slash',
onSelect = function()
lib.callback.await('qbx_management:server:fireEmployee', false, player.cid, groupType)
OpenBossMenu(groupType)
end,
}
lib.registerContext({
id = 'memberMenu',
title = player.name,
menu = 'memberListMenu',
options = employeeMenu,
})
lib.showContext('memberMenu')
end
-- Presents a menu of employees the work for a job or gang.
-- Allows selection of an employee to perform further actions
---@param groupType GroupType
local function employeeList(groupType)
local employeesMenu = {}
local groupName = QBX.PlayerData[groupType].name
local employees = lib.callback.await('qbx_management:server:getEmployees', false, groupName, groupType)
for _, employee in pairs(employees) do
local employeesData = {
title = employee.name,
description = groupType == 'job' and JOBS[groupName].grades[employee.grade].name or GANGS[groupName].grades[employee.grade].name,
onSelect = function()
manageEmployee(employee, groupName, groupType)
end,
}
if employee.hours and employee.last_checkin then
employeesData.metadata = {
{ label = locale('menu.employee_status'), value = employee.onduty and locale('menu.on_duty') or locale('menu.off_duty') },
{ label = locale('menu.hours_in_days'), value = employee.hours },
{ label = locale('menu.last_checkin'), value = employee.last_checkin },
}
end
employeesMenu[#employeesMenu + 1] = employeesData
end
lib.registerContext({
id = 'memberListMenu',
title = groupType == 'gang' and locale('menu.manage_gang') or locale('menu.manage_employees'),
menu = 'openBossMenu',
options = employeesMenu,
})
lib.showContext('memberListMenu')
end
-- Presents a list of possible employees to hire for a job or gang.
---@param groupType GroupType
local function showHireMenu(groupType)
local hireMenu = {}
local players = findPlayers()
local hireName = QBX.PlayerData[groupType].name
for _, player in pairs(players) do
if player[groupType].name ~= hireName then
hireMenu[#hireMenu + 1] = {
title = player.name,
description = locale('menu.citizen_id')..player.citizenid..' - '..locale('menu.id')..player.source,
onSelect = function()
lib.callback.await('qbx_management:server:hireEmployee', false, player.source, groupType)
OpenBossMenu(groupType)
end,
}
end
end
lib.registerContext({
id = 'hireMenu',
title = groupType == 'gang' and locale('menu.hire_gang') or locale('menu.hire_civilians'),
menu = 'openBossMenu',
options = hireMenu,
})
lib.showContext('hireMenu')
end
-- Opens main boss menu changing function based on the group provided.
---@param groupType GroupType
function OpenBossMenu(groupType)
if groupType ~= 'gang' and groupType ~= 'job' or not QBX.PlayerData[groupType].name or not QBX.PlayerData[groupType].isboss then return end
local bossMenu = {
{
title = groupType == 'gang' and locale('menu.manage_gang') or locale('menu.manage_employees'),
description = groupType == 'gang' and locale('menu.check_gang') or locale('menu.check_employee'),
icon = 'list',
onSelect = function()
employeeList(groupType)
end,
},
{
title = groupType == 'gang' and locale('menu.hire_members') or locale('menu.hire_employees'),
description = groupType == 'gang' and locale('menu.hire_gang') or locale('menu.hire_civilians'),
icon = 'hand-holding',
onSelect = function()
showHireMenu(groupType)
end,
},
}
for _, menuItem in pairs(dynamicMenuItems) do
if string.lower(menuItem.args.type) == groupType then
bossMenu[#bossMenu + 1] = menuItem
end
end
lib.registerContext({
id = 'openBossMenu',
title = groupType == 'gang' and string.upper(QBX.PlayerData.gang.label) or string.upper(QBX.PlayerData.job.label),
options = bossMenu,
})
lib.showContext('openBossMenu')
end
exports('OpenBossMenu', OpenBossMenu)
local function createZone(zoneInfo)
if config.useTarget then
exports.ox_target:addBoxZone({
coords = zoneInfo.coords,
size = zoneInfo.size or vec3(1.5, 1.5, 1.5),
rotation = zoneInfo.rotation or 0.0,
debug = config.debugPoly,
options = {
{
name = zoneInfo.groupName..'_menu',
icon = 'right-to-bracket',
label = zoneInfo.type == 'gang' and locale('menu.gang_menu') or locale('menu.boss_menu'),
canInteract = function()
return zoneInfo.groupName == QBX.PlayerData[zoneInfo.type].name and QBX.PlayerData[zoneInfo.type].isboss
end,
onSelect = function()
OpenBossMenu(zoneInfo.type)
end
}
}
})
else
lib.zones.box({
coords = zoneInfo.coords,
size = zoneInfo.size or vec3(1.5, 1.5, 1.5),
rotation = zoneInfo.rotation or 0.0,
debug = config.debugPoly,
onEnter = function()
if zoneInfo.groupName == QBX.PlayerData[zoneInfo.type].name and QBX.PlayerData[zoneInfo.type].isboss then
lib.showTextUI(zoneInfo.type == 'gang' and locale('menu.gang_management') or locale('menu.boss_management'))
end
end,
onExit = function()
lib.hideTextUI()
end,
inside = function()
if IsControlJustPressed(0, 51) then -- E
if zoneInfo.groupName == QBX.PlayerData[zoneInfo.type].name and QBX.PlayerData[zoneInfo.type].isboss then
OpenBossMenu(zoneInfo.type)
lib.hideTextUI()
end
end
end
})
end
end
local function initZones()
local menus = lib.callback.await('qbx_management:server:getBossMenus', false)
for _, menuInfo in pairs(menus) do
createZone(menuInfo)
end
end
RegisterNetEvent('qbx_management:client:bossMenuRegistered', function(menuInfo)
createZone(menuInfo)
end)
if GetConvar('qbx:enablebridge', 'true') == 'true' then
RegisterNetEvent('qb-bossmenu:client:OpenMenu', function()
OpenBossMenu('job')
end)
RegisterNetEvent('qb-gangmenu:client:OpenMenu', function()
OpenBossMenu('gang')
end)
end
AddEventHandler('onClientResourceStart', function(resource)
if cache.resource ~= resource then return end
initZones()
end)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
isLoggedIn = true
end)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
isLoggedIn = false
end)
CreateThread(function()
if not isLoggedIn then return end
end)