Explorer
KNOW-PAT-099

FiveM - Visual Effects State Machine (Drunk) : niveaux, AnimSet, TimecycleModifier, reset

Domaine
fivem
Type
pattern
Priorité
P2

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Visual Effects State Machine (Drunk) : niveaux, AnimSet, TimecycleModifier, reset

Problème

Les effets visuels (ivresse, drogue, fatigue) doivent être progressifs, avec plusieurs niveaux, et doivent être complètement réversibles.

Solution

Machine à états visuels avec 3 niveaux d'ivresse (slightly/moderate/very drunk), chargement d'AnimSet, TimecycleModifier, ScreenFade, et fonction de reset complet (Reality).

local IsAlreadyDrunk = false
local DrunkLevel = -1

function Drunk(level, start)
    CreateThread(function()
        local playerPed = PlayerPedId()

        if start then
            DoScreenFadeOut(800)
            Wait(1000)
        end

        if level == 0 then
            RequestAnimSet("move_m@drunk@slightlydrunk")
            while not HasAnimSetLoaded("move_m@drunk@slightlydrunk") do Wait(0) end
            SetPedMovementClipset(playerPed, "move_m@drunk@slightlydrunk", true)
        elseif level == 1 then
            RequestAnimSet("move_m@drunk@moderatedrunk")
            while not HasAnimSetLoaded("move_m@drunk@moderatedrunk") do Wait(0) end
            SetPedMovementClipset(playerPed, "move_m@drunk@moderatedrunk", true)
        elseif level == 2 then
            RequestAnimSet("move_m@drunk@verydrunk")
            while not HasAnimSetLoaded("move_m@drunk@verydrunk") do Wait(0) end
            SetPedMovementClipset(playerPed, "move_m@drunk@verydrunk", true)
        end

        SetTimecycleModifier("spectator5")
        SetPedMotionBlur(playerPed, true)
        SetPedIsDrunk(playerPed, true)

        if start then
            DoScreenFadeIn(800)
        end
    end)
end

function Reality()
    CreateThread(function()
        local playerPed = PlayerPedId()

        DoScreenFadeOut(800)
        Wait(1000)

        ClearTimecycleModifier()
        ResetScenarioTypesEnabled()
        ResetPedMovementClipset(playerPed, 0)
        SetPedIsDrunk(playerPed, false)
        SetPedMotionBlur(playerPed, false)

        DoScreenFadeIn(800)
    end)
end

-- Trigger via statut ESX
AddEventHandler('esx_status:loaded', function(status)
    TriggerEvent('esx_status:registerStatus', 'drunk', 0, '#8F15A5',
        function(status)
            if status.val > 0 then
                return true
            else
                return false
            end
        end,
        function(status)
            status.remove(1500) -- Se dissipe lentement
        end
    )
end)

AddEventHandler('esx_status:onTick', function(status)
    if status.val > 500000 then
        Drunk(2, false)
    elseif status.val > 250000 then
        Drunk(1, false)
    elseif status.val > 100000 then
        Drunk(0, false)
    else
        Reality()
    end
end)

Pourquoi

  • ScreenFade masque le changement brusque d'effets visuels
  • ResetPedMovementClipset et ClearTimecycleModifier garantissent un retour propre à la normal
  • Les niveaux progressifs créent une expérience réaliste

Quand l'utiliser

  • Systèmes de consommation (alcool, drogue)
  • Effets de blessure (fatigue, saignement)
  • Environnement (tempête de sable, gaz)

Quand NE PAS l'utiliser

  • Effets permanents (tatouages, cicatrices) → pas de reset
  • Si le ScreenFade est trop disruprif pour du gameplay compétitif

Exemples

Correct

-- Gestion complète avec garde-fou
function ApplyEffect(level, effectType)
    if level < 0 or level > 2 then return end
    
    if IsAlreadyDrunk and DrunkLevel == level then return end
    
    IsAlreadyDrunk = true
    DrunkLevel = level
    Drunk(level, true)
end

function ClearAllEffects()
    if not IsAlreadyDrunk then return end
    IsAlreadyDrunk = false
    DrunkLevel = -1
    Reality()
end

Incorrect

-- Pas de reset complet → effets qui persistent après respawn
RegisterNetEvent('drug:take')
AddEventHandler('drug:take', function()
    SetTimecycleModifier("spectator5")
    SetPedMovementClipset(PlayerPedId(), "move_m@drunk@verydrunk", true)
    -- JAMAIS reset → effet permanent
end)

Références

  • esx_optionalneeds/client/main.lua L1-77