--[[ Duty & Interaction Utilities Module -------------------------------------- This module provides functions related to: • Determining boss roles from Jobs and Gangs tables. • Checking a player's job and duty status. • Toggling duty state. • Simulating player interactions such as hand washing, using toilets/urinals, and teleporting via doors. ]] local bossMenuFunc = { { name = "qb-management", openBossMenu = function(isGang, group) if isGang then TriggerEvent("qb-gangmenu:client:OpenMenu") else TriggerEvent("qb-bossmenu:client:OpenMenu") end end, }, { name = "qbx_management", openBossMenu = function(isGang, group) if isGang then exports["qbx_management"]:OpenBossMenu("gang") else exports["qbx_management"]:OpenBossMenu("job") end end, }, { name = "esx_society", openBossMenu = function(isGang, group) TriggerServerEvent(getScript()..":registerESXSociety", isGang, group) TriggerEvent('esx_society:openBossMenu', group, function() end, { wash = false }) end, }, { name = "tss-bossmenu", openBossMenu = function(isGang, group) TriggerEvent("tss-bossmenu:client:OpenMenu") end, }, { name = "okokBossMenu", openBossMenu = function(isGang, group) ExecuteCommand('openbossmenu') end, }, } function openBossMenu(isGang, group) for i = 1, #bossMenuFunc do local bossmenu = bossMenuFunc[i] if isStarted(bossmenu.name) then bossmenu.openBossMenu(isGang, group) return end end end -- Register ESX Society account in the server RegisterNetEvent(getScript()..":registerESXSociety", function(group) local checkExist = exports.esx_society:GetSociety(group) if checkExist == nil then exports.esx_society:registerSociety( group, Gangs[group] and Gangs[group].label or Jobs[group] and Jobs[group].label, group, group, group, {type = "public"} ) end end) ------------------------------------------------------------- -- Global Duty Status ------------------------------------------------------------- -- This attempts to sync up with the players framework onDuty variable -- This stops the script getting confused when one is false and one is true onDuty = false if not isServer() then onPlayerLoaded(function() onDuty = getPlayer().onDuty end, true) end ------------------------------------------------------------- -- Boss Role Detection ------------------------------------------------------------- --- Scans the 'Jobs' and 'Gangs' tables to identify roles classified as bosses. --- --- Iterates through the specified role's grades in the Jobs or Gangs table and returns --- a table mapping the role to the lowest grade number that qualifies as a boss (isboss or bankAuth). --- --- @param role string The job or gang role to check. --- @return table table A table with the role mapped to its boss grade number. --- --- @usage --- ```lua --- local bosses = makeBossRoles("police") --- if bosses["police"] then --- print("Police role has a boss grade.") --- end --- ``` function makeBossRoles(role) local boss = {} local data = (Jobs and Jobs[role]) or (Gangs and Gangs[role]) if data then for grade, info in pairs(data.grades) do if info.isboss or info.bankAuth or info.isBoss then boss[role] = boss[role] and math.min(boss[role], tonumber(grade)) or tonumber(grade) end end end return boss end ------------------------------------------------------------- -- Job & Duty Checks ------------------------------------------------------------- --- Checks if the player has a specific job (or gang) and is on duty. --- --- Verifies whether the player possesses the specified role. If the role is defined in the Jobs table, --- it also checks that the player is clocked in (onDuty). If the check fails, a notification is sent. --- --- @param job string The job or gang to check. --- @return boolean Returns true if the player meets the criteria; false otherwise. --- --- @usage --- ```lua --- if jobCheck("mechanic") then --- -- Allow mechanic features. --- else --- -- Deny access. --- end --- ``` function jobCheck(job) local canDo = true if Jobs[job] then if not hasJob(job) or not getPlayer().onDuty then triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"]) canDo = false end end if Gangs[job] then if not hasJob(job) then canDo = false end end return canDo end --- Toggles the player's duty status. --- --- Switches the player's duty state between on-duty and off-duty. If using QBcore, --- it triggers the appropriate server event. Otherwise, it manually toggles the onDuty variable and notifies the player. --- --- @usage --- ```lua --- toggleDuty() -- Player receives a notification of their new duty status. --- ``` function toggleDuty() local dutyFunc = { { framework = QBExport, func = function() TriggerServerEvent("QBCore:ToggleDuty") Wait(100) onDuty = getPlayer().onDuty end }, { framework = QBXExport, func = function() TriggerServerEvent("QBCore:ToggleDuty") Wait(100) onDuty = getPlayer().onDuty end }, { framework = RSGExport, func = function() TriggerServerEvent("RSGCore:ToggleDuty") Wait(100) onDuty = getPlayer().onDuty end }, { framework = ESXExport, func = function() local tempJob = ESX.GetPlayerData().job tempJob.onDuty = not onDuty ESX.SetPlayerData("job", tempJob) onDuty = getPlayer().onDuty if onDuty then triggerNotify(nil, "Now on duty", "success") else triggerNotify(nil, "Now off duty", "success") end end }, } for i = 1, #dutyFunc do local framework = dutyFunc[i] if isStarted(framework.framework) then framework.func() return end end -- fallback onDuty = not onDuty if onDuty then triggerNotify(nil, "Now on duty", "success") else triggerNotify(nil, "Now off duty", "success") end end -- Framework specific functions to keep duty status synced RegisterNetEvent("QBCore:Client:OnJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end) RegisterNetEvent("QBCore:Client:SetDuty", function(duty) onDuty = duty end) RegisterNetEvent("qbx_core:client:onJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end) RegisterNetEvent("RSGCore:Client:OnJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end) RegisterNetEvent("RSGCore:Client:SetDuty", function(duty) onDuty = duty end) ------------------------------------------------------------- -- Interaction Functions ------------------------------------------------------------- --- Initiates the hand-washing action for the player. --- --- Triggers an animation and a progress bar to simulate hand washing at the specified coordinates. --- On success, it notifies the player; if cancelled, it sends an error notification. --- --- @param data table A table containing: --- - coords (vector3): The location where the hand-washing action occurs. --- --- @usage --- ```lua --- washHands({ coords = vector3(200.0, 300.0, 40.0) }) --- ``` function washHands(data) local ped = PlayerPedId() lookEnt(data.coords) local cam = createTempCam(ped, data.coords) if progressBar({ label = Loc[Config.Lan].progressbar["progress_washing"], time = 5000, cancel = true, dict = "mp_arresting", anim = "a_uncuff", flag = 32, icon = "fas fa-hand-holding-droplet", cam = cam }) then triggerNotify(nil, Loc[Config.Lan].success["washed_hands"], "success") else triggerNotify(nil, Loc[Config.Lan].error["cancel"], "error") end ClearPedTasks(ped) end --- Handles the player's interaction with a toilet or urinal. --- --- Manages animations and progress bars for using a urinal or a toilet. If the action is successful, --- it triggers the appropriate server event (urinal usage) or notifies the player if cancelled. --- --- @param data table A table containing: --- - urinal (boolean): `true if using a urinal; false for a toilet.` --- - sitcoords (vector4): `Coordinates and heading for seating when using a toilet.` --- --- @usage --- ```lua --- useToilet({ urinal = true }) --- -- Player uses a urinal with corresponding animations and notifications --- --- useToilet({ urinal = false, sitcoords = vector4(215.76, -810.12, 29.73, 90.0) }) --- -- Player sits down to use a toilet with corresponding animations and notifications --- ``` function useToilet(data) if data.urinal then if progressBar({ label = "Using Urinal", time = 5000, cancel = true, dict = "misscarsteal2peeing", anim = "peeing_loop", flag = 32 }) then TriggerServerEvent(getScript().."server:Urinal") else lockInv(false) triggerNotify(nil, Loc[Config.Lan].error["cancelled"], "error") end else TaskStartScenarioAtPosition(PlayerPedId(), "PROP_HUMAN_SEAT_CHAIR_MP_PLAYER", data.sitcoords.x, data.sitcoords.y, data.sitcoords.z, data.sitcoords[4], 0, 1, true) if progressBar({ label = "Using Toilet", time = 10000, cancel = true }) then TriggerServerEvent(getScript().."server:Urinal") ClearPedTasks(PlayerPedId()) else lockInv(false) triggerNotify(nil, Loc[Config.Lan].error["cancelled"], "error") end end end --- Teleports the player to specified coordinates with a fade effect. --- --- Fades the screen out, moves the player to the target coordinates, sets the player's heading, --- then fades the screen back in. Commonly used for door interactions or teleportation points. --- --- @param data table A table containing: --- - telecoords (vector4): The target coordinates and heading. --- --- @usage --- ```lua --- useDoor({ telecoords = vector4(215.76, -810.12, 29.73, 90.0) }) --- ``` function useDoor(data) DoScreenFadeOut(500) while not IsScreenFadedOut() do Wait(10) end SetEntityCoords(PlayerPedId(), data.telecoords.xyz, 0, 0, 0, false) SetEntityHeading(PlayerPedId(), data.telecoords.w) DoScreenFadeIn(1000) Wait(100) end