> For the complete documentation index, see [llms.txt](https://docs.vames-store.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vames-store.com/assets/vms_needs/configuration-files/config.client.lua.md).

# config.client.lua

{% code fullWidth="true" %}

```lua
CL = {}

-- ███╗   ██╗ ██████╗ ████████╗██╗███████╗██╗ ██████╗ █████╗ ████████╗██╗ ██████╗ ███╗   ██╗███████╗
-- ████╗  ██║██╔═══██╗╚══██╔══╝██║██╔════╝██║██╔════╝██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║██╔════╝
-- ██╔██╗ ██║██║   ██║   ██║   ██║█████╗  ██║██║     ███████║   ██║   ██║██║   ██║██╔██╗ ██║███████╗
-- ██║╚██╗██║██║   ██║   ██║   ██║██╔══╝  ██║██║     ██╔══██║   ██║   ██║██║   ██║██║╚██╗██║╚════██║
-- ██║ ╚████║╚██████╔╝   ██║   ██║██║     ██║╚██████╗██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║███████║
-- ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚═╝╚═╝     ╚═╝ ╚═════╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝
CL.Notification = function(data)
    local color = 
        data.type == "success" and '#36f230' or
        data.type == "error"   and '#f23030' or
        data.type == "info"    and '#4287f5'
    
    if GetResourceState("vms_notify") == 'started' then
        exports['vms_notify']:Notification("", data.message, data.time, color, data.icon)
    elseif GetResourceState("lation_ui") == 'started' then
        exports['lation_ui']:notify({
            message = data.message,
            type = data.type,
            duration = data.time,
        })
    else
        TriggerEvent('esx:showNotification', data.message)
        TriggerEvent('QBCore:Notify', data.message, 'primary', data.time)
    end
end


CL.QuestionMenu = function(data, cb)
    if GetResourceState("vms_notifyv2") == 'started' then
        local question = exports['vms_notifyv2']:Question({
            title = data.title,
            description = data.description,
            color = "#673feb",
            icon = "fa-solid fa-circle-question",
        }, {
            {
                displayKey = "Y",
                description = TRANSLATE("control.request:accept"),
                control = 246
            },
            {
                displayKey = "N",
                description = TRANSLATE("control.request:decline"),
                control = 306
            }
        })

        Citizen.Await(question) -- IT MUST BE HERE

        if question == "246" then -- export returns clicked control as string!
            cb(true)
        else
            cb(false)
        end
    elseif GetResourceState('lation_ui') == 'started' then
        local result = exports.lation_ui:alert({
            header = data.title,
            content = data.description,
            icon = 'fa-solid fa-circle-question',
            iconColor = '#673feb',
            type = 'default',
            labels = {
                cancel = TRANSLATE("control.request:decline"),
                confirm = TRANSLATE("control.request:accept"),
            }
        })

        if result == 'confirm' then
            cb(true)
        else
            cb(false)
        end
    end
end


-- ████████╗ █████╗ ██████╗  ██████╗ ███████╗████████╗
-- ╚══██╔══╝██╔══██╗██╔══██╗██╔════╝ ██╔════╝╚══██╔══╝
--    ██║   ███████║██████╔╝██║  ███╗█████╗     ██║   
--    ██║   ██╔══██║██╔══██╗██║   ██║██╔══╝     ██║   
--    ██║   ██║  ██║██║  ██║╚██████╔╝███████╗   ██║   
--    ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝   ╚═╝   
CL.Target = function(type, data)
    if type == 'entity' then
        if Config.TargetResource == 'ox_target' then
            local options = {}
            
            if data.options and next(data.options) then
                for k, v in pairs(data.options) do
                    local icon = v.icon or 'fa-solid fa-bars' -- Default Icon
                    
                    options[#options + 1] = {
                        name = v.name,
                        icon = icon,
                        label = v.label,
                        distance = v.distance or 1.2,
                        items = v.requiredItem,
                        groups = v.jobs,
                        onSelect = v.action,
                        canInteract = v.canInteract,
                    }
                end
            end

            exports['ox_target']:addLocalEntity(data.entity, options)
        elseif Config.TargetResource == 'qb-target' then
            local options = {}
            
            if data.options and next(data.options) then
                for k, v in pairs(data.options) do
                    local icon = v.icon or 'fa-solid fa-bars' -- Default Icon
                    
                    options[#options + 1] = {
                        num = #options + 1,
                        icon = icon,
                        label = v.label,
                        distance = v.distance or 1.2,
                        item = v.requiredItem,
                        job = v.jobs,
                        action = v.action,
                        canInteract = v.canInteract,
                    }
                end
            end
            
            exports['qb-target']:AddTargetEntity(data.entity, {
                options = options,
                distance = 2.0
            })
        else
            warn('You need to prepare CL.Target for the target system')
        end
        
    elseif type == 'remove-entity' then
        if Config.TargetResource == 'ox_target' then
            exports['ox_target']:removeLocalEntity(data)
        elseif Config.TargetResource == 'qb-target' then
            exports['qb-target']:RemoveTargetEntity(data)
        else
            warn('You need to prepare CL.Target for the target system')
        end

    end
end


-- ██████╗ ██████╗     ████████╗███████╗██╗  ██╗████████╗
-- ╚════██╗██╔══██╗    ╚══██╔══╝██╔════╝╚██╗██╔╝╚══██╔══╝
--  █████╔╝██║  ██║       ██║   █████╗   ╚███╔╝    ██║   
--  ╚═══██╗██║  ██║       ██║   ██╔══╝   ██╔██╗    ██║   
-- ██████╔╝██████╔╝       ██║   ███████╗██╔╝ ██╗   ██║   
-- ╚═════╝ ╚═════╝        ╚═╝   ╚══════╝╚═╝  ╚═╝   ╚═╝   
CL.DrawText3D = function(coords, text)
    if not Config.UseDrawText then return end
    
    local textScale = 0.50
    local camCoords = GetFinalRenderedCamCoord()
    local distance = #(coords.xyz - camCoords)
    local scale = (textScale / distance) * 2
    local fov = (1 / GetGameplayCamFov()) * 100
    scale = scale * fov
    
    SetTextScale(0.0 * scale, 0.50 * scale)
    SetTextFont(4)
    SetTextDropshadow(0, 0, 0, 0, 255)
    SetTextProportional(1)
    SetTextColour(255, 255, 255, 205)
    SetTextDropShadow()
    SetTextCentre(true)

    if Config.UseDrawTextBox then
        BeginTextCommandWidth("STRING")
        AddTextComponentString(text)
        local textWidth = EndTextCommandGetWidth(true) + (0.006 * scale * 2)
        
        SetDrawOrigin(coords.x, coords.y, coords.z, 0)
        DrawRect(0.0, 0.018 * scale, textWidth, 0.045 * scale, 11, 4, 20, 120)
    else
        SetDrawOrigin(coords.x, coords.y, coords.z, 0)
    end

    SetTextEntry("STRING")
    AddTextComponentString(text)
    DrawText(0.0, 0.0)

    ClearDrawOrigin()
end


-- ███████╗██████╗  █████╗ ███╗   ███╗███████╗██╗    ██╗ ██████╗ ██████╗ ██╗  ██╗
-- ██╔════╝██╔══██╗██╔══██╗████╗ ████║██╔════╝██║    ██║██╔═══██╗██╔══██╗██║ ██╔╝
-- █████╗  ██████╔╝███████║██╔████╔██║█████╗  ██║ █╗ ██║██║   ██║██████╔╝█████╔╝ 
-- ██╔══╝  ██╔══██╗██╔══██║██║╚██╔╝██║██╔══╝  ██║███╗██║██║   ██║██╔══██╗██╔═██╗ 
-- ██║     ██║  ██║██║  ██║██║ ╚═╝ ██║███████╗╚███╔███╔╝╚██████╔╝██║  ██║██║  ██╗
-- ╚═╝     ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝ ╚══╝╚══╝  ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝
CL.IsPlayerLoaded = function(type)
    if Config.Core == "ESX" then
        return ESX.IsPlayerLoaded()
    elseif Config.Core == "QB-Core" then
        return CL.GetPlayerData() and CL.GetPlayerData().job ~= nil
    end
end

CL.GetPlayerData = function(type)
    if Config.Core == "ESX" then
        return ESX.GetPlayerData()
    elseif Config.Core == "QB-Core" then
        return QBCore.Functions.GetPlayerData()
    end
end

CL.GetItemLabel = function(name)
    if GetItemLabel then
        return GetItemLabel(name)
    else
        if Config.Core == "QB-Core" and QBCore?.Shared?.Items then
            local item = QBCore.Shared.Items[name]
            if item.label then
                return item.label
            end
        end

        return name
    end
end

CL.GetCancelUsageAction = function(ped)
    -- Death Check
    if GetEntityHealth(ped) <= 0 or IsEntityDead(ped) or LocalPlayer.state.isDead then
        return 'drop'
    end

    -- Stun Check
    if IsPedBeingStunned(ped) then
        return 'drop'
    end

    -- Ragdoll
    local ragdollReason = DetectRagdollReason(ped)
    if ragdollReason == 'fall' or ragdollReason == 'vehicleHit' then
        return 'drop'
    end
    
    -- qb-smallresources handsup.lua
    -- if exports['qb-smallresources']:getHandsup() then
    --     return 'cancel'
    -- end

    -- Example: Handcuffed
    -- if exports['your_cuffs']:IsHandcuffed() then
    --     return 'cancel'
    -- end

    return false
end

CL.GetPlayerGender = function(ped)
    local model = GetEntityModel(ped)

    if model == GetHashKey("mp_m_freemode_01") then
        return "male"
    elseif model == GetHashKey("mp_f_freemode_01") then
        return "female"
    end

    return "unknown"
end


-- ███████╗████████╗ █████╗ ████████╗██╗   ██╗███████╗
-- ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██║   ██║██╔════╝
-- ███████╗   ██║   ███████║   ██║   ██║   ██║███████╗
-- ╚════██║   ██║   ██╔══██║   ██║   ██║   ██║╚════██║
-- ███████║   ██║   ██║  ██║   ██║   ╚██████╔╝███████║
-- ╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝    ╚═════╝ ╚══════╝
CL.OnConsume = function(itemName, biteSize)
    local isGymStarted = GetResourceState('vms_gym') == 'started'
    if isGymStarted then
        local value = ({
            -- Here you can configure the items that will negatively affect the player's stamina.
            ['cigarette'] = math.random(1, 8),  -- 0.1 - 0.8%
            ['joint_sd']  = math.random(0, 5),  -- 0.0 - 0.5%
            ['joint_nl']  = math.random(0, 5),  -- 0.0 - 0.5%
        })[itemName]

        if value and value >= 1 then
            value = value / 10
            exports["vms_gym"]:removeSkill('condition', value)
        end
    end
end

CreateThread(function()
    while WaitingForLoad do
        Citizen.Wait(100)
    end

    local resourceName = GetCurrentResourceName()
    while true do
        Wait(2000)

        if CL.IsPlayerLoaded() then
            local removeHealth = 0
            
            local hunger = exports[resourceName]:GetPercentageStatus('hunger')
            local thirst = exports[resourceName]:GetPercentageStatus('thirst')
    
            if hunger <= 5 then
                removeHealth = removeHealth + math.random(0, 2)
            end
    
            if thirst <= 5 then
                removeHealth = removeHealth + math.random(0, 3)
            end
    
            if removeHealth > 0 then
                local myPed = PlayerPedId()
                local health = GetEntityHealth(myPed)
    
                SetEntityHealth(myPed, health - removeHealth)
            end
        end
    end
end)


-- ██╗███╗   ██╗██╗████████╗██╗ █████╗ ████████╗██╗ ██████╗ ███╗   ██╗
-- ██║████╗  ██║██║╚══██╔══╝██║██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║
-- ██║██╔██╗ ██║██║   ██║   ██║███████║   ██║   ██║██║   ██║██╔██╗ ██║
-- ██║██║╚██╗██║██║   ██║   ██║██╔══██║   ██║   ██║██║   ██║██║╚██╗██║
-- ██║██║ ╚████║██║   ██║   ██║██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║
-- ╚═╝╚═╝  ╚═══╝╚═╝   ╚═╝   ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
function CL.InitiateFunctions()
    -- Ambulance Integration
    local function RestoreDefaultStatuses()
        local hunger = exports['vms_needs']:GetPercentageStatus('hunger')
        if hunger < 50.0 then
            exports['vms_needs']:SetStatus('hunger', 250.0) -- 250.0 = half
        end
            
        local thirst = exports['vms_needs']:GetPercentageStatus('thirst')
        if thirst < 50.0 then
            exports['vms_needs']:SetStatus('thirst', 250.0) -- 250.0 = half
        end
    end

    local foundIntegration = false
    if GetResourceState('tk_ambulancejob') == 'started' then
        foundIntegration = 'tk_ambulancejob'

        RegisterNetEvent('tk_ambulancejob:onPlayerRevive', function()
            RestoreDefaultStatuses()
            exports['vms_needs']:CleanupOptionalStatuses()
        end)

    elseif GetResourceState('wasabi_ambulance') == 'started' then
        foundIntegration = 'wasabi_ambulance'
        
        RegisterNetEvent('wasabi_ambulance:revive', function()
            Citizen.Wait(500) -- Wait for the player to be fully revived
            exports['vms_needs']:ReloadVisualEffect()
        end)

        RegisterNetEvent('wasabi_ambulance:revivePlayer', function()
            Citizen.Wait(500) -- Wait for the player to be fully revived
            exports['vms_needs']:ReloadVisualEffect()
        end)

    elseif GetResourceState('wasabi_ambulance_v2') == 'started' then
        foundIntegration = 'wasabi_ambulance_v2'

        RegisterNetEvent('wasabi_ambulance:Client:OnRevive', function()
            Citizen.Wait(500) -- Wait for the player to be fully revived
            exports['vms_needs']:ReloadVisualEffect()
        end)
        
        RegisterNetEvent('wasabi_ambulance:Client:Listeners:OnRespawn', function()
            exports['vms_needs']:CleanupOptionalStatuses()
        end)

        RegisterNetEvent('wasabi_ambulance:Client:Listeners:OnFacilityHeal', function()
            exports['vms_needs']:CleanupOptionalStatuses()
        end)

    end

    if foundIntegration then
        library.Debug(('^2[Integration]^7 Found Ambulance Integration: ^3%s^7'):format(foundIntegration))
    end
end

```

{% endcode %}
