257 lines
7.8 KiB
Lua
257 lines
7.8 KiB
Lua
local progress
|
|
local DisableControlAction = DisableControlAction
|
|
local DisablePlayerFiring = DisablePlayerFiring
|
|
local playerState = LocalPlayer.state
|
|
local createdProps = {}
|
|
|
|
---@class ProgressPropProps
|
|
---@field model string
|
|
---@field bone? number
|
|
---@field pos vector3
|
|
---@field rot vector3
|
|
---@field rotOrder? number
|
|
|
|
---@class ProgressProps
|
|
---@field label? string
|
|
---@field duration number
|
|
---@field position? 'middle' | 'bottom'
|
|
---@field useWhileDead? boolean
|
|
---@field allowRagdoll? boolean
|
|
---@field allowCuffed? boolean
|
|
---@field allowFalling? boolean
|
|
---@field allowSwimming? boolean
|
|
---@field canCancel? boolean
|
|
---@field anim? { dict?: string, clip: string, flag?: number, blendIn?: number, blendOut?: number, duration?: number, playbackRate?: number, lockX?: boolean, lockY?: boolean, lockZ?: boolean, scenario?: string, playEnter?: boolean }
|
|
---@field prop? ProgressPropProps | ProgressPropProps[]
|
|
---@field disable? { move?: boolean, sprint?: boolean, car?: boolean, combat?: boolean, mouse?: boolean }
|
|
|
|
local function createProp(ped, prop)
|
|
lib.requestModel(prop.model)
|
|
local coords = GetEntityCoords(ped)
|
|
local object = CreateObject(prop.model, coords.x, coords.y, coords.z, false, false, false)
|
|
|
|
AttachEntityToEntity(object, ped, GetPedBoneIndex(ped, prop.bone or 60309), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, prop.rotOrder or 0, true)
|
|
SetModelAsNoLongerNeeded(prop.model)
|
|
|
|
return object
|
|
end
|
|
|
|
local function interruptProgress(data)
|
|
if not data.useWhileDead and IsEntityDead(cache.ped) then return true end
|
|
if not data.allowRagdoll and IsPedRagdoll(cache.ped) then return true end
|
|
if not data.allowCuffed and IsPedCuffed(cache.ped) then return true end
|
|
if not data.allowFalling and IsPedFalling(cache.ped) then return true end
|
|
if not data.allowSwimming and IsPedSwimming(cache.ped) then return true end
|
|
end
|
|
|
|
local isFivem = cache.game == 'fivem'
|
|
|
|
local controls = {
|
|
INPUT_LOOK_LR = isFivem and 1 or 0xA987235F,
|
|
INPUT_LOOK_UD = isFivem and 2 or 0xD2047988,
|
|
INPUT_SPRINT = isFivem and 21 or 0x8FFC75D6,
|
|
INPUT_AIM = isFivem and 25 or 0xF84FA74F,
|
|
INPUT_MOVE_LR = isFivem and 30 or 0x4D8FB4C1,
|
|
INPUT_MOVE_UD = isFivem and 31 or 0xFDA83190,
|
|
INPUT_DUCK = isFivem and 36 or 0xDB096B85,
|
|
INPUT_VEH_MOVE_LEFT_ONLY = isFivem and 63 or 0x9DF54706,
|
|
INPUT_VEH_MOVE_RIGHT_ONLY = isFivem and 64 or 0x97A8FD98,
|
|
INPUT_VEH_ACCELERATE = isFivem and 71 or 0x5B9FD4E2,
|
|
INPUT_VEH_BRAKE = isFivem and 72 or 0x6E1F639B,
|
|
INPUT_VEH_EXIT = isFivem and 75 or 0xFEFAB9B4,
|
|
INPUT_VEH_MOUSE_CONTROL_OVERRIDE = isFivem and 106 or 0x39CCABD5
|
|
}
|
|
|
|
local function startProgress(data)
|
|
playerState.invBusy = true
|
|
progress = data
|
|
local anim = data.anim
|
|
|
|
if anim then
|
|
if anim.dict then
|
|
lib.requestAnimDict(anim.dict)
|
|
|
|
TaskPlayAnim(cache.ped, anim.dict, anim.clip, anim.blendIn or 3.0, anim.blendOut or 1.0, anim.duration or -1, anim.flag or 49, anim.playbackRate or 0, anim.lockX, anim.lockY, anim.lockZ)
|
|
RemoveAnimDict(anim.dict)
|
|
elseif anim.scenario then
|
|
TaskStartScenarioInPlace(cache.ped, anim.scenario, 0, anim.playEnter ~= nil and anim.playEnter or true)
|
|
end
|
|
end
|
|
|
|
if data.prop then
|
|
playerState:set('lib:progressProps', data.prop, true)
|
|
end
|
|
|
|
local disable = data.disable
|
|
|
|
while progress do
|
|
if disable then
|
|
if disable.mouse then
|
|
DisableControlAction(0, controls.INPUT_LOOK_LR, true)
|
|
DisableControlAction(0, controls.INPUT_LOOK_UD, true)
|
|
DisableControlAction(0, controls.INPUT_VEH_MOUSE_CONTROL_OVERRIDE, true)
|
|
end
|
|
|
|
if disable.move then
|
|
DisableControlAction(0, controls.INPUT_SPRINT, true)
|
|
DisableControlAction(0, controls.INPUT_MOVE_LR, true)
|
|
DisableControlAction(0, controls.INPUT_MOVE_UD, true)
|
|
DisableControlAction(0, controls.INPUT_DUCK, true)
|
|
end
|
|
|
|
if disable.sprint and not disable.move then
|
|
DisableControlAction(0, controls.INPUT_SPRINT, true)
|
|
end
|
|
|
|
if disable.car then
|
|
DisableControlAction(0, controls.INPUT_VEH_MOVE_LEFT_ONLY, true)
|
|
DisableControlAction(0, controls.INPUT_VEH_MOVE_RIGHT_ONLY, true)
|
|
DisableControlAction(0, controls.INPUT_VEH_ACCELERATE, true)
|
|
DisableControlAction(0, controls.INPUT_VEH_BRAKE, true)
|
|
DisableControlAction(0, controls.INPUT_VEH_EXIT, true)
|
|
end
|
|
|
|
if disable.combat then
|
|
DisableControlAction(0, controls.INPUT_AIM, true)
|
|
DisablePlayerFiring(cache.playerId, true)
|
|
end
|
|
end
|
|
|
|
if interruptProgress(progress) then
|
|
progress = false
|
|
end
|
|
|
|
Wait(0)
|
|
end
|
|
|
|
if data.prop then
|
|
playerState:set('lib:progressProps', nil, true)
|
|
end
|
|
|
|
if anim then
|
|
if anim.dict then
|
|
StopAnimTask(cache.ped, anim.dict, anim.clip, 1.0)
|
|
Wait(0) -- This is needed here otherwise the StopAnimTask is cancelled
|
|
else
|
|
ClearPedTasks(cache.ped)
|
|
end
|
|
end
|
|
|
|
playerState.invBusy = false
|
|
|
|
if progress == false then
|
|
SendNUIMessage({ action = 'progressCancel' })
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
---@param data ProgressProps
|
|
---@return boolean?
|
|
function lib.progressBar(data)
|
|
while progress ~= nil do Wait(0) end
|
|
|
|
if not interruptProgress(data) then
|
|
SendNUIMessage({
|
|
action = 'progress',
|
|
data = {
|
|
label = data.label,
|
|
duration = data.duration
|
|
}
|
|
})
|
|
|
|
return startProgress(data)
|
|
end
|
|
end
|
|
|
|
---@param data ProgressProps
|
|
---@return boolean?
|
|
function lib.progressCircle(data)
|
|
while progress ~= nil do Wait(0) end
|
|
|
|
if not interruptProgress(data) then
|
|
SendNUIMessage({
|
|
action = 'circleProgress',
|
|
data = {
|
|
duration = data.duration,
|
|
position = data.position,
|
|
label = data.label
|
|
}
|
|
})
|
|
|
|
return startProgress(data)
|
|
end
|
|
end
|
|
|
|
function lib.cancelProgress()
|
|
if not progress then
|
|
error('No progress bar is active')
|
|
end
|
|
|
|
progress = false
|
|
end
|
|
|
|
---@return boolean
|
|
function lib.progressActive()
|
|
return progress and true
|
|
end
|
|
|
|
RegisterNUICallback('progressComplete', function(data, cb)
|
|
cb(1)
|
|
progress = nil
|
|
end)
|
|
|
|
RegisterCommand('cancelprogress', function()
|
|
if progress?.canCancel then progress = false end
|
|
end)
|
|
|
|
if isFivem then
|
|
RegisterKeyMapping('cancelprogress', locale('cancel_progress'), 'keyboard', 'x')
|
|
end
|
|
|
|
local function deleteProgressProps(serverId)
|
|
local playerProps = createdProps[serverId]
|
|
if not playerProps then return end
|
|
for i = 1, #playerProps do
|
|
local prop = playerProps[i]
|
|
if DoesEntityExist(prop) then
|
|
DeleteEntity(prop)
|
|
end
|
|
end
|
|
createdProps[serverId] = nil
|
|
end
|
|
|
|
RegisterNetEvent('onPlayerDropped', function(serverId)
|
|
deleteProgressProps(serverId)
|
|
end)
|
|
|
|
AddStateBagChangeHandler('lib:progressProps', nil, function(bagName, key, value, reserved, replicated)
|
|
if replicated then return end
|
|
|
|
local ply = GetPlayerFromStateBagName(bagName)
|
|
if ply == 0 then return end
|
|
|
|
local ped = GetPlayerPed(ply)
|
|
local serverId = GetPlayerServerId(ply)
|
|
|
|
if not value then
|
|
return deleteProgressProps(serverId)
|
|
end
|
|
|
|
createdProps[serverId] = {}
|
|
local playerProps = createdProps[serverId]
|
|
|
|
if value.model then
|
|
playerProps[#playerProps+1] = createProp(ped, value)
|
|
else
|
|
for i = 1, #value do
|
|
local prop = value[i]
|
|
|
|
if prop then
|
|
playerProps[#playerProps+1] = createProp(ped, prop)
|
|
end
|
|
end
|
|
end
|
|
end)
|