local RSGCore = exports['rsg-core']:GetCoreObject()
local speed = 0.0
local radarActive = false
local stress = 0
local cleanliness = 100
local hunger = 100
local thirst = 100
local cashAmount = 0
local bankAmount = 0
local isLoggedIn = false
local youhavemail = false
local incinematic = false
local inBathing = false
local showUI = true

RegisterNetEvent("HideAllUI")
AddEventHandler("HideAllUI", function()
    showUI = not showUI
    if not showUI then
        Citizen.InvokeNative(0xC116E6DF68DCE667, 6, 2) -- ICON_HORSE_HEALTH / HIDE
        Citizen.InvokeNative(0xC116E6DF68DCE667, 7, 2) -- ICON_HORSE_HEALTH_CORE / HIDE
        
        Citizen.InvokeNative(0xC116E6DF68DCE667, 8, 2) -- ICON_HORSE_STAMINA / HIDE
        Citizen.InvokeNative(0xC116E6DF68DCE667, 9, 2) -- ICON_HORSE_STAMINA_CORE / HIDE
    else
        Citizen.InvokeNative(0xC116E6DF68DCE667, 6, 1) -- ICON_HORSE_HEALTH / HIDE
        Citizen.InvokeNative(0xC116E6DF68DCE667, 7, 1) -- ICON_HORSE_HEALTH_CORE / HIDE
        
        Citizen.InvokeNative(0xC116E6DF68DCE667, 8, 1) -- ICON_HORSE_STAMINA / HIDE
        Citizen.InvokeNative(0xC116E6DF68DCE667, 9, 1) -- ICON_HORSE_STAMINA_CORE / HIDE
    end
end)

-- functions
local function GetShakeIntensity(stresslevel)
    local retval = 0.05
    for _, v in pairs(Config.Intensity['shake']) do
        if stresslevel >= v.min and stresslevel <= v.max then
            retval = v.intensity
            break
        end
    end
    return retval
end

local function GetEffectInterval(stresslevel)
    local retval = 60000
    for _, v in pairs(Config.EffectInterval) do
        if stresslevel >= v.min and stresslevel <= v.max then
            retval = v.timeout
            break
        end
    end
    return retval
end

-- Events

RegisterNetEvent('RSGCore:Client:OnPlayerUnload', function()
    isLoggedIn = false
end)

RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', function()
    isLoggedIn = true
end)

RegisterNetEvent('hud:client:UpdateNeeds', function(newHunger, newThirst)
    hunger = newHunger
    thirst = newThirst
end)

RegisterNetEvent('hud:client:UpdateThirst', function(newThirst)
    thirst = newThirst
end)

RegisterNetEvent('hud:client:UpdateStress', function(newStress)
    stress = newStress
end)

RegisterNetEvent('hud:client:UpdateCleanliness', function(newCleanliness)
    cleanliness = newCleanliness
end)

local voicelevel = 50
local voicetalking = false

AddEventHandler('onClientMapStart', function()
    local getVoiceRange = exports.saltychat:GetVoiceRange(true)
    if getVoiceRange == 3.5 then
        voicelevel = 25
    elseif getVoiceRange == 8.0 then
        voicelevel = 50
    elseif getVoiceRange == 15.0 then
        voicelevel = 75
    elseif getVoiceRange == 32.0 then
        voicelevel = 100
    end
end)

RegisterNetEvent('SaltyChat_TalkStateChanged')
AddEventHandler("SaltyChat_TalkStateChanged", function(isTalking)
	voicetalking = isTalking
end)

RegisterNetEvent('SaltyChat_VoiceRangeChanged')
AddEventHandler("SaltyChat_VoiceRangeChanged", function(TalkRange, Index, Count)
    voicelevel = Index / Count
end)

-- Player HUD
CreateThread(function()
    while true do
        Wait(250)
        if LocalPlayer.state['isLoggedIn'] and incinematic == false and inBathing == false and showUI then
            local show = true
            local player = PlayerPedId()
            local playerid = PlayerId()
            if IsPauseMenuActive() then
                show = false
            end
            -- local voice = 0
            -- local talking = Citizen.InvokeNative(0x33EEF97F, playerid)
            -- if LocalPlayer.state['proximity'] then
            --     voice = LocalPlayer.state['proximity'].distance
            -- end
            --Citizen.Wait(1000)
            -- local getVoiceRange = exports.saltychat:GetVoiceRange(true)
            local playerPed = PlayerPedId()
            local coords = GetEntityCoords(playerPed)
            local metric = ShouldUseMetricTemperature() or ShouldUseMetricMeasurements()
            local temperature
            local stamina = tonumber(string.format("%.2f", Citizen.InvokeNative(0x0FF421E467373FCF, PlayerId(), Citizen.ResultAsFloat())))
            local mounted = IsPedOnMount(PlayerPedId())
            if metric then
                temperature = math.floor(GetTemperatureAtCoords(coords)) .. "°C" --Uncomment for celcius
                -- temperature = math.floor(GetTemperatureAtCoords(coords) * 9/5 + 32) .. "°F" --Comment out for celcius 
            end
            ---@type any
            local horsehealth = 0 
            
            ---@type any
            local horsestam = 0 

            if mounted then
                local horse = GetMount(PlayerPedId())
                local maxHealth = Citizen.InvokeNative(0x4700A416E8324EF3, horse, Citizen.ResultAsInteger())
                local maxStamina = Citizen.InvokeNative(0xCB42AFE2B613EE55, horse, Citizen.ResultAsFloat())
                horsehealth = tonumber(
                    string.format(
                        "%.2f", Citizen.InvokeNative(0x82368787EA73C0F7, horse) / maxHealth * 100 
                    )
                )
                horsestam = tonumber(
                    string.format(
                        "%.2f", Citizen.InvokeNative(0x775A1CA7893AA8B5, horse, Citizen.ResultAsFloat()) / maxStamina * 100
                    )
                )
            end
            SendNUIMessage({
                action = 'hudtick',
                show = show,
                health = GetEntityHealth(player) / 6, -- health in red dead max health is 600 so dividing by 6 makes it 100 here
                armor = Citizen.InvokeNative(0x2CE311A7, player),
                thirst = thirst,
                hunger = hunger,
                stress = stress,
                cleanliness = cleanliness,
                talking = voicetalking,
                temp = temperature,
                onHorse = mounted,
                horsehealth = horsehealth,
                horsestamina = horsestam,
                stamina = stamina,
                voice = voicelevel,
                youhavemail = youhavemail,
            })
        else
            SendNUIMessage({
                action = 'hudtick',
                show = false,
            })
        end
    end
end)

CreateThread(function()
    while true do
        Wait(1000)

        local ped = PlayerPedId()
        local isMounted = IsPedOnMount(ped) or IsPedInAnyVehicle(ped)
        local IsBirdPostApproaching = exports['rsg-telegram']:IsBirdPostApproaching()

        if isMounted or IsBirdPostApproaching then
            if Config.MounttMinimap and showUI then
                if Config.MountCompass then
                    SetMinimapType(3)
                else
                    SetMinimapType(1)
                end
            else
                SetMinimapType(0)
            end
        else
            if Config.OnFootMinimap and showUI then
                SetMinimapType(1)
            else
                if Config.OnFootCompass and showUI then
                    SetMinimapType(3)
                else
                    SetMinimapType(0)
                end
            end
        end
    end
end)

-- Money HUD
RegisterNetEvent('hud:client:ShowAccounts', function(type, amount)
    if type == 'cash' then
        SendNUIMessage({
            action = 'show',
            type = 'cash',
            cash = string.format("%.2f", amount)
        })
    elseif type == 'bloodmoney' then
        SendNUIMessage({
            action = 'show',
            type = 'bloodmoney',
            bloodmoney = string.format("%.2f", amount)
        })
    elseif type == 'bank' then
        SendNUIMessage({
            action = 'show',
            type = 'bank',
            bank = string.format("%.2f", amount)
        })
    end
end)

RegisterNetEvent('hud:client:OnMoneyChange', function(type, amount, isMinus)
    RSGCore.Functions.GetPlayerData(function(PlayerData)
        cashAmount = PlayerData.money['cash']
        bloodmoneyAmount = PlayerData.money['bloodmoney']
        bankAmount = PlayerData.money['bank']
    end)
    SendNUIMessage({
        action = 'update',
        cash = RSGCore.Shared.Round(cashAmount, 2),
        bloodmoney = RSGCore.Shared.Round(bloodmoneyAmount, 2),
        bank = RSGCore.Shared.Round(bankAmount, 2),
        amount = RSGCore.Shared.Round(amount, 2),
        minus = isMinus,
        type = type,
    })
end)

-- Stress Gain

CreateThread(function() -- Speeding
    while true do
        if RSGCore ~= nil --[[ and isLoggedIn ]] then
            local ped = PlayerPedId()
            if IsPedInAnyVehicle(ped, false) then
                speed = GetEntitySpeed(GetVehiclePedIsIn(ped, false)) * 2.237 --mph
                if speed >= Config.MinimumSpeed then
                    TriggerServerEvent('hud:server:GainStress', math.random(2, 4))
                end
            end
        end
        Wait(20000)
    end
end)

CreateThread(function() -- Shooting
    while true do
        if RSGCore ~= nil --[[ and isLoggedIn ]] then
            if IsPedShooting(PlayerPedId()) then
                if math.random() < Config.StressChance then
                    TriggerServerEvent('hud:server:GainStress', math.random(1, 3))
                end
            end
        end
        Wait(6)
    end
end)

-- Stress Screen Effects
CreateThread(function()
    while true do
        local ped = PlayerPedId()
        local sleep = GetEffectInterval(stress)

        if stress >= 100 then
            local ShakeIntensity = GetShakeIntensity(stress)
            local FallRepeat = math.random(1, 2)
            local RagdollTimeout = (FallRepeat * 1750)
            ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', ShakeIntensity)

            if not IsPedRagdoll(ped) and IsPedOnFoot(ped) and not IsPedSwimming(ped) then
                local player = PlayerPedId()
                SetPedToRagdollWithFall(player, RagdollTimeout, RagdollTimeout, 1, GetEntityForwardVector(player), 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
            end

            Wait(500)
            for i = 1, FallRepeat, 1 do
                Wait(750)
                DoScreenFadeOut(200)
                Wait(1000)
                DoScreenFadeIn(200)
                ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', ShakeIntensity)
            end
        elseif stress >= Config.MinimumStress then
            local ShakeIntensity = GetShakeIntensity(stress)
            ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', ShakeIntensity)
        end
        Wait(sleep)
    end
end)

local ipea = false
local cphi = false
function GetDirtyEffect()
    local npd = "scr_fme_spawn_effects"
    local npn = "scr_animal_poop_flies"
    
    local cpd = npd
    local cpn = npn
    
    
    local bones = 1058
    
    local po_x = -0.35
    local po_y = 0.85
    local po_z = 0.10
    local pr_x = -90.0
    local pr_y = -20.0
    local pr_z = -170.00
    local ps = 0.9
    local pa_x = 0
    local pa_y = 0
    local pa_z = 0
    
    
    if not ipea then
        cpd = npd
        cpn = npn
        if not Citizen.InvokeNative(0x65BB72F29138F5D6, GetHashKey(cpd)) then -- HasNamedPtfxAssetLoaded
            Citizen.InvokeNative(0xF2B2353BBC0D4E8F, GetHashKey(cpd))  -- RequestNamedPtfxAsset
            local counter = 0
            while not Citizen.InvokeNative(0x65BB72F29138F5D6, GetHashKey(cpd)) and counter <= 300 do  -- while not HasNamedPtfxAssetLoaded
                Citizen.Wait(0)
            end
        end
        if Citizen.InvokeNative(0x65BB72F29138F5D6, GetHashKey(cpd)) then  -- HasNamedPtfxAssetLoaded
            Citizen.InvokeNative(0xA10DB07FC234DD12, cpd) -- UseParticleFxAsset

            cphi = Citizen.InvokeNative(0x9C56621462FFE7A6,cpn,PlayerPedId(),po_x,po_y,po_z,pr_x,pr_y,pr_z,bones,ps,pa_x,pa_y,pa_z) -- StartNetworkedParticleFxLoopedOnEntityBone
            ipea = true
        else
            print("Can't load ptfx dictionary!")
        end
    else
        if cphi then
            if Citizen.InvokeNative(0x9DD5AFF561E88F2A, cphi) then   -- DoesParticleFxLoopedExist
                Citizen.InvokeNative(0x459598F579C98929, cphi, false)   -- RemoveParticleFx
            end
        end
        cphi = false
        ipea = false
    end
end

exports("GetDirtyEffect", GetDirtyEffect)

-- Dirty Fiels & Sickness Effects
CreateThread(function()
    while true do
        local iPed = PlayerPedId()
        local sleep = cleanliness

        -- if IsPedOnFoot(iPed) and IsPedOnMount(iPed) and IsPedSitting(iPed) and IsPedAPlayer(iPed) and not IsPedSwimming(iPed) then
            if cleanliness >= Config.MinimumClean then
                GetDirtyEffect(iPed)
            end
        -- end

        Wait(sleep)
    end
end)

-- Cleanliness / Dirtylevel
CreateThread(function()
    while true do
        Wait(30000) -- Every 1 minutes
        if RSGCore ~= nil then
            TriggerServerEvent('hud:server:RelieveCleanliness', 0.1) -- 3Hours from Fullbar to End.
        end
    end
end)

CreateThread(function()
    while true do
        Wait(10)
        if cleanliness < 20 then
            RSGCore.Functions.Notify("You smell like *****..", 'primary', 7500)
            Wait(60000)
        end
    end
end)

-- check telegrams
CreateThread(function()
    while true do
        if isLoggedIn == true then
            RSGCore.Functions.TriggerCallback('hud:server:getTelegramsAmount', function(amount)
                if amount > 0 then
                    youhavemail = true
                else
                    youhavemail = false
                end
            end)
        end
        Wait(Config.TelegramCheck)
    end
end)

-- check cinematic and hide hud
CreateThread(function()
    while true do
        if LocalPlayer.state['isLoggedIn'] then
            local cinematic = Citizen.InvokeNative(0xBF7C780731AADBF8, Citizen.ResultAsInteger())
            local isBathingActive = exports['rsg-bathing']:IsBathingActive()

            if cinematic == 1 then
                incinematic = true
            else
                incinematic = false
            end

            if isBathingActive then
                inBathing = true
            else
                inBathing = false
            end
        end

        Wait(500)
    end
end)
 

Lua online compiler

Write, Run & Share Lua code online using OneCompiler's Lua online compiler for free. It's one of the robust, feature-rich online compilers for Lua language, running the latest Lua version 5.4. Getting started with the OneCompiler's Lua editor is easy and fast. The editor shows sample boilerplate code when you choose language as Lua and start coding.

Taking inputs (stdin)

OneCompiler's Lua online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Lua program which takes name as input and prints hello message with your name.

name = io.read("*a")
print ("Hello ", name)

About Lua

Lua is a light weight embeddable scripting language which is built on top of C. It is used in almost all kind of applications like games, web applications, mobile applications, image processing etc. It's a very powerful, fast, easy to learn, open-source scripting language.

Syntax help

Variables

  • By default all the variables declared are global variables
  • If the variables are explicitly mentioned as local then they are local variables.
  • Lua is a dynamically typed language and hence only the values will have types not the variables.

Examples

-- global variables
a = 10

-- local variables

local x = 30
Value TypeDescription
numberRepresents numbers
stringRepresents text
nilDifferentiates values whether it has data or not
booleanValue can be either true or false
functionRepresents a sub-routine
userdataRepresents arbitary C data
threadRepresents independent threads of execution.
tableCan hold any value except nil

Loops

1. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while(condition)
do
--code
end

2. Repeat-Until:

Repeat-Until is also used to iterate a set of statements based on a condition. It is very similar to Do-While, it is mostly used when you need to execute the statements atleast once.

repeat
   --code
until( condition )

3. For:

For loop is used to iterate a set of statements based on a condition.

for init,max/min value, increment
do
   --code
end

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increase re-usuability and modularity.

optional_function_scope function function_name( argument1, argument2, argument3........, argumentn)
--code
return params with comma seperated
end