252 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			252 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local Action = {
 | |
|     name = '',
 | |
|     duration = 0,
 | |
|     label = '',
 | |
|     useWhileDead = false,
 | |
|     canCancel = true,
 | |
|     disarm = true,
 | |
|     controlDisables = {
 | |
|         disableMovement = false,
 | |
|         disableCarMovement = false,
 | |
|         disableMouse = false,
 | |
|         disableCombat = false,
 | |
|     },
 | |
|     animation = {
 | |
|         animDict = nil,
 | |
|         anim = nil,
 | |
|         flags = 0,
 | |
|         task = nil,
 | |
|     },
 | |
|     prop = {
 | |
|         model = nil,
 | |
|         bone = nil,
 | |
|         coords = vec3(0.0, 0.0, 0.0),
 | |
|         rotation = vec3(0.0, 0.0, 0.0),
 | |
|     },
 | |
|     propTwo = {
 | |
|         model = nil,
 | |
|         bone = nil,
 | |
|         coords = vec3(0.0, 0.0, 0.0),
 | |
|         rotation = vec3(0.0, 0.0, 0.0),
 | |
|     },
 | |
| }
 | |
| 
 | |
| local isDoingAction = false
 | |
| local wasCancelled = false
 | |
| local prop_net = nil
 | |
| local propTwo_net = nil
 | |
| local isAnim = false
 | |
| local isProp = false
 | |
| local isPropTwo = false
 | |
| 
 | |
| local controls = {
 | |
|     disableMouse = { 1, 2, 106 },
 | |
|     disableMovement = { 30, 31, 36, 21, 75 },
 | |
|     disableCarMovement = { 63, 64, 71, 72 },
 | |
|     disableCombat = { 24, 25, 37, 47, 58, 140, 141, 142, 143, 263, 264, 257 }
 | |
| }
 | |
| 
 | |
| -- Functions
 | |
| 
 | |
| local function loadAnimDict(dict)
 | |
|     RequestAnimDict(dict)
 | |
|     while not HasAnimDictLoaded(dict) do
 | |
|         Wait(5)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function loadModel(model)
 | |
|     RequestModel(model)
 | |
|     while not HasModelLoaded(model) do
 | |
|         Wait(5)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function createAndAttachProp(prop, ped)
 | |
|     loadModel(prop.model)
 | |
|     local coords = GetOffsetFromEntityInWorldCoords(ped, 0.0, 0.0, 0.0)
 | |
|     local propEntity = CreateObject(GetHashKey(prop.model), coords.x, coords.y, coords.z, true, true, true)
 | |
|     local netId = ObjToNet(propEntity)
 | |
|     SetNetworkIdExistsOnAllMachines(netId, true)
 | |
|     NetworkUseHighPrecisionBlending(netId, true)
 | |
|     SetNetworkIdCanMigrate(netId, false)
 | |
|     local boneIndex = GetPedBoneIndex(ped, prop.bone or 60309)
 | |
|     AttachEntityToEntity(
 | |
|         propEntity, ped, boneIndex,
 | |
|         prop.coords.x, prop.coords.y, prop.coords.z,
 | |
|         prop.rotation.x, prop.rotation.y, prop.rotation.z,
 | |
|         true, true, false, true, 0, true
 | |
|     )
 | |
|     return netId
 | |
| end
 | |
| 
 | |
| local function disableControls()
 | |
|     CreateThread(function()
 | |
|         while isDoingAction do
 | |
|             for disableType, isEnabled in pairs(Action.controlDisables) do
 | |
|                 if isEnabled and controls[disableType] then
 | |
|                     for _, control in ipairs(controls[disableType]) do
 | |
|                         DisableControlAction(0, control, true)
 | |
|                     end
 | |
|                 end
 | |
|             end
 | |
|             if Action.controlDisables.disableCombat then
 | |
|                 DisablePlayerFiring(PlayerId(), true)
 | |
|             end
 | |
|             Wait(0)
 | |
|         end
 | |
|     end)
 | |
| end
 | |
| 
 | |
| local function StartActions()
 | |
|     local ped = PlayerPedId()
 | |
|     if isDoingAction then
 | |
|         if not isAnim and Action.animation then
 | |
|             if Action.animation.task then
 | |
|                 TaskStartScenarioInPlace(ped, Action.animation.task, 0, true)
 | |
|             else
 | |
|                 local anim = Action.animation
 | |
|                 if anim.animDict and anim.anim and DoesEntityExist(ped) and not IsEntityDead(ped) then
 | |
|                     loadAnimDict(anim.animDict)
 | |
|                     TaskPlayAnim(ped, anim.animDict, anim.anim, 3.0, 3.0, -1, anim.flags or 1, 0, false, false, false)
 | |
|                 end
 | |
|             end
 | |
|             isAnim = true
 | |
|         end
 | |
|         if not isProp and Action.prop and Action.prop.model then
 | |
|             prop_net = createAndAttachProp(Action.prop, ped)
 | |
|             isProp = true
 | |
|         end
 | |
|         if not isPropTwo and Action.propTwo and Action.propTwo.model then
 | |
|             propTwo_net = createAndAttachProp(Action.propTwo, ped)
 | |
|             isPropTwo = true
 | |
|         end
 | |
|         disableControls()
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function StartProgress(action, onStart, onTick, onFinish)
 | |
|     local playerPed = PlayerPedId()
 | |
|     local isPlayerDead = IsEntityDead(playerPed)
 | |
|     if (not isPlayerDead or action.useWhileDead) and not isDoingAction then
 | |
|         isDoingAction = true
 | |
|         LocalPlayer.state:set('inv_busy', true, true)
 | |
|         Action = action
 | |
|         SendNUIMessage({
 | |
|             action = 'progress',
 | |
|             duration = action.duration,
 | |
|             label = action.label
 | |
|         })
 | |
|         StartActions()
 | |
|         CreateThread(function()
 | |
|             if onStart then onStart() end
 | |
|             while isDoingAction do
 | |
|                 Wait(1)
 | |
|                 if onTick then onTick() end
 | |
|                 if IsControlJustPressed(0, 200) and action.canCancel then
 | |
|                     TriggerEvent('progressbar:client:cancel')
 | |
|                     wasCancelled = true
 | |
|                     break
 | |
|                 end
 | |
|                 if IsEntityDead(playerPed) and not action.useWhileDead then
 | |
|                     TriggerEvent('progressbar:client:cancel')
 | |
|                     wasCancelled = true
 | |
|                     break
 | |
|                 end
 | |
|             end
 | |
|             if onFinish then onFinish(wasCancelled) end
 | |
|             isDoingAction = false
 | |
|         end)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function ActionCleanup()
 | |
|     local ped = PlayerPedId()
 | |
|     if Action.animation then
 | |
|         if Action.animation.task or (Action.animation.animDict and Action.animation.anim) then
 | |
|             StopAnimTask(ped, Action.animation.animDict, Action.animation.anim, 1.0)
 | |
|             ClearPedSecondaryTask(ped)
 | |
|         else
 | |
|             ClearPedTasks(ped)
 | |
|         end
 | |
|     end
 | |
|     if prop_net then
 | |
|         DetachEntity(NetToObj(prop_net), true, true)
 | |
|         DeleteObject(NetToObj(prop_net))
 | |
|     end
 | |
|     if propTwo_net then
 | |
|         DetachEntity(NetToObj(propTwo_net), true, true)
 | |
|         DeleteObject(NetToObj(propTwo_net))
 | |
|     end
 | |
|     prop_net = nil
 | |
|     propTwo_net = nil
 | |
|     isDoingAction = false
 | |
|     wasCancelled = false
 | |
|     isAnim = false
 | |
|     isProp = false
 | |
|     isPropTwo = false
 | |
|     LocalPlayer.state:set('inv_busy', false, true)
 | |
| end
 | |
| 
 | |
| -- Events
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:ToggleBusyness', function(bool)
 | |
|     isDoingAction = bool
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:progress', function(action, finish)
 | |
|     StartProgress(action, nil, nil, finish)
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:ProgressWithStartEvent', function(action, start, finish)
 | |
|     StartProgress(action, start, nil, finish)
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:ProgressWithTickEvent', function(action, tick, finish)
 | |
|     StartProgress(action, nil, tick, finish)
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:ProgressWithStartAndTick', function(action, start, tick, finish)
 | |
|     StartProgress(action, start, tick, finish)
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent('progressbar:client:cancel', function()
 | |
|     ActionCleanup()
 | |
|     SendNUIMessage({
 | |
|         action = 'cancel'
 | |
|     })
 | |
| end)
 | |
| 
 | |
| -- NUI Callback
 | |
| 
 | |
| RegisterNUICallback('FinishAction', function(data, cb)
 | |
|     ActionCleanup()
 | |
|     cb('ok')
 | |
| end)
 | |
| 
 | |
| -- Exports
 | |
| 
 | |
| local function Progress(action, finish)
 | |
|     StartProgress(action, nil, nil, finish)
 | |
| end
 | |
| exports('Progress', Progress)
 | |
| 
 | |
| local function ProgressWithStartEvent(action, start, finish)
 | |
|     StartProgress(action, start, nil, finish)
 | |
| end
 | |
| exports('ProgressWithStartEvent', ProgressWithStartEvent)
 | |
| 
 | |
| local function ProgressWithTickEvent(action, tick, finish)
 | |
|     StartProgress(action, nil, tick, finish)
 | |
| end
 | |
| exports('ProgressWithTickEvent', ProgressWithTickEvent)
 | |
| 
 | |
| local function ProgressWithStartAndTick(action, start, tick, finish)
 | |
|     StartProgress(action, start, tick, finish)
 | |
| end
 | |
| exports('ProgressWithStartAndTick', ProgressWithStartAndTick)
 | |
| 
 | |
| local function isDoingSomething()
 | |
|     return isDoingAction
 | |
| end
 | |
| exports('isDoingSomething', isDoingSomething)
 | 
