Scripts/resources/[standalone]/dpemotes/client/Crouch.lua
2024-12-29 21:02:20 +01:00

487 lines
15 KiB
Lua

IsProne = false
local isCrouched = false
local isCrawling = false
local inAction = false
local proneType = "onfront"
local lastKeyPress = 0
-- Utils --
local function LoadAnimDict(dict)
RequestAnimDict(dict)
while not HasAnimDictLoaded(dict) do
Citizen.Wait(0)
end
end
local function LoadAnimSet(set)
RequestAnimSet(set)
while not HasAnimSetLoaded(set) do
Citizen.Wait(0)
end
end
local function IsPlayerAiming(player)
return IsPlayerFreeAiming(player) or IsAimCamActive() or IsAimCamThirdPersonActive()
end
local function CanPlayerCrouchCrawl(playerPed)
if not IsPedOnFoot(playerPed) or IsPedJumping(playerPed) or IsPedFalling(playerPed) or IsPedInjured(playerPed) or IsPedInMeleeCombat(playerPed) or IsPedRagdoll(playerPed) then
return false
end
return true
end
local function PlayAnimOnce(playerPed, animDict, animName, blendInSpeed, blendOutSpeed, duration, startTime)
LoadAnimDict(animDict)
TaskPlayAnim(playerPed, animDict, animName, blendInSpeed or 2.0, blendOutSpeed or 2.0, duration or -1, 0, startTime or 0.0, false, false, false)
RemoveAnimDict(animDict)
end
local function ChangeHeadingSmooth(playerPed, amount, time)
local times = math.abs(amount)
local test = amount / times
local wait = time / times
for _i = 1, times do
Wait(wait)
SetEntityHeading(playerPed, GetEntityHeading(playerPed) + test)
end
end
-- Crouching --
local function ResetCrouch()
local playerPed = PlayerPedId()
ResetPedStrafeClipset(playerPed)
ResetPedWeaponMovementClipset(playerPed)
SetPedMaxMoveBlendRatio(playerPed, 1.0)
SetPedCanPlayAmbientAnims(playerPed, true)
-- Applies the previous walk style (or resets to default if non had been set)
local walkStyle = GetResourceKvpString("walkstyle")
if walkStyle ~= nil then
LoadAnimSet(walkStyle)
SetPedMovementClipset(playerPed, walkStyle, 0.6)
RemoveAnimSet(walkStyle)
else
ResetPedMovementClipset(playerPed, 0.5)
end
RemoveAnimSet("move_ped_crouched")
end
local function CrouchThread()
CreateThread(function()
local playerId = PlayerId()
while isCrouched do
local playerPed = PlayerPedId()
-- Checks if the player is falling, in vehicle, dead etc.
if not CanPlayerCrouchCrawl(playerPed) then
isCrouched = false
break
end
-- Limit the speed that the player can walk when aiming
if IsPlayerAiming(playerId) then
SetPedMaxMoveBlendRatio(playerPed, 0.15)
end
-- This blocks the ped from standing up and playing idle anims (this needs to be looped)
SetPedCanPlayAmbientAnims(playerPed, false)
-- Disables "INPUT_DUCK" and blocks action mode
DisableControlAction(0, 36, true)
if IsPedUsingActionMode(playerPed) == 1 then
SetPedUsingActionMode(playerPed, false, -1, "DEFAULT_ACTION")
end
-- Disable first person
DisableFirstPersonCamThisFrame()
Wait(0)
end
-- Reset walk style and ped variables
ResetCrouch()
end)
end
local function StartCrouch()
isCrouched = true
LoadAnimSet("move_ped_crouched")
local playerPed = PlayerPedId()
-- Force leave stealth mode
if GetPedStealthMovement(playerPed) == 1 then
SetPedStealthMovement(playerPed, false, "DEFAULT_ACTION")
Wait(100)
end
-- Force leave first person view
if GetFollowPedCamViewMode() == 4 then
SetFollowPedCamViewMode(0) -- THIRD_PERSON_NEAR
end
SetPedMovementClipset(playerPed, "move_ped_crouched", 0.6)
SetPedStrafeClipset(playerPed, "move_ped_crouched_strafing")
CrouchThread()
end
local function AttemptCrouch(playerPed)
if CanPlayerCrouchCrawl(playerPed) then
StartCrouch()
return true
else
return false
end
end
local function CrouchKeyPressed()
-- If we already are doing something, then don't continue
if inAction then
return
end
-- If crouched then stop crouching
if isCrouched then
isCrouched = false
return
end
-- Get the player ped
local playerPed = PlayerPedId()
if Config.CrouchOverride then
DisableControlAction(0, 36, true) -- Disable INPUT_DUCK this frame
else
-- Get +crouch and INPUT_DUCK keys
local crouchKey = GetControlInstructionalButton(0, 0xD2D0BEBA, false)
local duckKey = GetControlInstructionalButton(0, 36, false)
-- If they are the same and we aren't prone, then check if we are in stealth mode and how long ago the last button press was.
if crouchKey == duckKey and not IsProne then
local timer = GetGameTimer()
-- If we are in stealth mode and we have already pressed the button in the last second
if GetPedStealthMovement(playerPed) == 1 and timer - lastKeyPress < 1000 then
DisableControlAction(0, 36, true) -- Disable INPUT_DUCK this frame
lastKeyPress = 0
AttemptCrouch(playerPed)
return
end
lastKeyPress = timer
return
end
end
-- Attempt to crouch, if we were successful, then also check if we are prone, if so then play an animaiton
if AttemptCrouch(playerPed) and IsProne then
inAction = true
IsProne = false
PlayAnimOnce(playerPed, "get_up@directional@transition@prone_to_knees@crawl", "front", nil, nil, 780)
Wait(780)
inAction = false
end
end
-- Crawling --
local function ShouldPlayerDiveToCrawl(playerPed)
if IsPedRunning(playerPed) or IsPedSprinting(playerPed) then
return true
end
return false
end
local function PlayIdleCrawlAnim(playerPed, heading, blendInSpeed)
local playerCoords = GetEntityCoords(playerPed)
TaskPlayAnimAdvanced(playerPed, "move_crawl", proneType.."_fwd", playerCoords.x, playerCoords.y, playerCoords.z, 0.0, 0.0, heading or GetEntityHeading(playerPed), blendInSpeed or 2.0, 2.0, -1, 2, 1.0, false, false)
end
local function PlayExitCrawlAnims(forceEnd)
if not forceEnd then
inAction = true
local playerPed = PlayerPedId()
if proneType == "onfront" then
PlayAnimOnce(playerPed, "get_up@directional@transition@prone_to_knees@crawl", "front", nil, nil, 780)
-- Only stand fully up if we are not crouching
if not isCrouched then
Wait(780)
PlayAnimOnce(playerPed, "get_up@directional@movement@from_knees@standard", "getup_l_0", nil, nil, 1300)
end
else
PlayAnimOnce(playerPed, "get_up@directional@transition@prone_to_seated@crawl", "back", 16.0, nil, 950)
-- Only stand fully up if we are not crouching
if not isCrouched then
Wait(950)
PlayAnimOnce(playerPed, "get_up@directional@movement@from_seated@standard", "get_up_l_0", nil, nil, 1300)
end
end
end
end
local function Crawl(playerPed, type, direction)
isCrawling = true
TaskPlayAnim(playerPed, "move_crawl", type.."_"..direction, 8.0, -8.0, -1, 2, 0.0, false, false, false)
local time = {
["onfront"] = {
["fwd"] = 820,
["bwd"] = 990
},
["onback"] = {
["fwd"] = 1200,
["bwd"] = 1200
}
}
SetTimeout(time[type][direction], function()
isCrawling = false
end)
end
local function CrawlFlip(playerPed)
inAction = true
local heading = GetEntityHeading(playerPed)
if proneType == "onfront" then
proneType = "onback"
PlayAnimOnce(playerPed, "get_up@directional_sweep@combat@pistol@front", "front_to_prone", 2.0)
ChangeHeadingSmooth(playerPed, -18.0, 3600)
else
proneType = "onfront"
PlayAnimOnce(playerPed, "move_crawlprone2crawlfront", "back", 2.0, nil, -1)
ChangeHeadingSmooth(playerPed, 12.0, 1700)
end
PlayIdleCrawlAnim(playerPed, heading + 180.0)
Wait(400)
inAction = false
end
local function CrawlThread()
CreateThread(function()
Wait(400)
local forceEnd = false
while IsProne do
local playerPed = PlayerPedId()
-- Checks if the player is falling, in vehicle, dead etc.
if not CanPlayerCrouchCrawl(playerPed) or IsEntityInWater(playerPed) then
ClearPedTasks(playerPed)
IsProne = false
forceEnd = true
break
end
-- Handles forwad/backward movement
local forward, backwards = IsControlPressed(0, 32), IsControlPressed(0, 33) -- INPUT_MOVE_UP_ONLY, INPUT_MOVE_DOWN_ONLY
if not isCrawling then
if forward then -- Forward
Crawl(playerPed, proneType, "fwd")
elseif backwards then -- Back
Crawl(playerPed, proneType, "bwd")
end
end
-- Moving left/right
if IsControlPressed(0, 34) then -- INPUT_MOVE_LEFT_ONLY
if isCrawling then
local headingDiff = forward and 1.0 or -1.0
SetEntityHeading(playerPed, GetEntityHeading(playerPed) + headingDiff)
else
inAction = true
if proneType == "onfront" then
local playerCoords = GetEntityCoords(playerPed)
TaskPlayAnimAdvanced(playerPed, "move_crawlprone2crawlfront", "left", playerCoords.x, playerCoords.y, playerCoords.z, 0.0, 0.0, GetEntityHeading(playerPed), 2.0, 2.0, -1, 2, 0.1, false, false)
ChangeHeadingSmooth(playerPed, -10.0, 300)
Wait(700)
else
PlayAnimOnce(playerPed, "get_up@directional_sweep@combat@pistol@left", "left_to_prone")
ChangeHeadingSmooth(playerPed, 25.0, 400)
PlayIdleCrawlAnim(playerPed)
Wait(600)
end
inAction = false
end
elseif IsControlPressed(0, 35) then -- INPUT_MOVE_RIGHT_ONLY
if isCrawling then
local headingDiff = backwards and 1.0 or -1.0
SetEntityHeading(playerPed, GetEntityHeading(playerPed) + headingDiff)
else
inAction = true
if proneType == "onfront" then
local playerCoords = GetEntityCoords(playerPed)
TaskPlayAnimAdvanced(playerPed, "move_crawlprone2crawlfront", "right", playerCoords.x, playerCoords.y, playerCoords.z, 0.0, 0.0, GetEntityHeading(playerPed), 2.0, 2.0, -1, 2, 0.1, false, false)
ChangeHeadingSmooth(playerPed, 10.0, 300)
Wait(700)
else
PlayAnimOnce(playerPed, "get_up@directional_sweep@combat@pistol@right", "right_to_prone")
ChangeHeadingSmooth(playerPed, -25.0, 400)
PlayIdleCrawlAnim(playerPed)
Wait(600)
end
inAction = false
end
end
-- Flipping around
if not isCrawling then
if IsControlPressed(0, 22) then -- INPUT_JUMP
CrawlFlip(playerPed)
end
end
Wait(0)
end
-- If the crawling wasn't forcefully ended, then play the get up animations
PlayExitCrawlAnims(forceEnd)
-- Reset variabels
isCrawling = false
inAction = false
proneType = "onfront"
SetPedConfigFlag(PlayerPedId(), 48, false) -- CPED_CONFIG_FLAG_BlockWeaponSwitching
-- Unload animation dictionaries
RemoveAnimDict("move_crawl")
RemoveAnimDict("move_crawlprone2crawlfront")
end)
end
local function CrawlKeyPressed()
-- If we already are doing something, then don't continue
if inAction then
return
end
-- Don't start/stop to crawl if we are in the pause menu
if IsPauseMenuActive() then
return
end
-- If already prone, then stop
if IsProne then
IsProne = false
return
end
-- If we are playing an animation, then cancel it first
if IsInAnimation then
EmoteCancel()
end
-- If we are crouching we should stop that first
local wasCrouched = false
if isCrouched then
isCrouched = false
wasCrouched = true
end
local playerPed = PlayerPedId()
if not CanPlayerCrouchCrawl(playerPed) or IsEntityInWater(playerPed) then
return
end
inAction = true
-- If we are pointing then stop pointing
if Pointing then
Pointing = false
end
IsProne = true
SetPedConfigFlag(playerPed, 48, true) -- CPED_CONFIG_FLAG_BlockWeaponSwitching
-- Force leave stealth mode
if GetPedStealthMovement(playerPed) == 1 then
SetPedStealthMovement(playerPed, false, "DEFAULT_ACTION")
Wait(100)
end
-- Load animations that the crawling is going to use
LoadAnimDict("move_crawl")
LoadAnimDict("move_crawlprone2crawlfront")
if ShouldPlayerDiveToCrawl(playerPed) then
PlayAnimOnce(playerPed, "explosions", "react_blown_forwards", nil, 3.0)
Wait(1100)
elseif wasCrouched then
PlayAnimOnce(playerPed, "amb@world_human_sunbathe@male@front@enter", "enter", nil, nil, -1, 0.3)
Wait(1500)
else
PlayAnimOnce(playerPed, "amb@world_human_sunbathe@male@front@enter", "enter")
Wait(3000)
end
-- Set the player into the idle position (but only if we can still crawl)
if CanPlayerCrouchCrawl(playerPed) and not IsEntityInWater(playerPed) then
PlayIdleCrawlAnim(playerPed, nil, 3.0)
end
inAction = false
CrawlThread()
end
-- Commands & KeyMapping --
if Config.CrouchEnabled then
if Config.CrouchKeybindEnabled then
RegisterKeyMapping('+crouch', "Crouch", "keyboard", Config.CrouchKeybind)
RegisterCommand('+crouch', function() CrouchKeyPressed() end, false)
RegisterCommand('-crouch', function() end, false) -- This needs to be here to prevent errors/warnings
end
RegisterCommand('crouch', function()
if isCrouched then
isCrouched = false
return
end
AttemptCrouch(PlayerPedId())
end, false)
TriggerEvent('chat:addSuggestion', '/crouch', 'Crouch')
end
if Config.CrawlEnabled then
if Config.CrawlKeybindEnabled then
RegisterKeyMapping('crawl', "Crawl", "keyboard", Config.CrawlKeybind)
end
RegisterCommand('crawl', function() CrawlKeyPressed() end, false)
end
-- Exports --
-- Returns weather or not the player is crouched
local function IsPlayerCrouched()
return isCrouched
end
-- Returns if the player is prone (both when laying still and when moving)
local function IsPlayerProne()
return IsProne
end
-- Returns if the player is crawling (only when moving forward/backwards)
local function IsPlayerCrawling()
return isCrawling
end
exports('IsPlayerCrouched', IsPlayerCrouched)
exports('IsPlayerProne', IsPlayerProne)
exports('IsPlayerCrawling', IsPlayerCrawling)