mirror of
https://github.com/jimathy/rpemotes.git
synced 2026-07-22 13:43:34 -04:00
* fix: only setup +-crouch keys if enabled Keys only need to be set up if keybinding is enabled. * dev: move function * fix: add ragdoll test * refactor: get player ped after anim loaded * grammar * refactor: add return to AttemptCrouch returns if it was successful * style: add category name * feat: add crawling * fix: added missing config Config was missing, sorry! * refactor: use PlayAnimOnce We should use PlayAnimOnce here as it would lower the complexity and make the code easier to read. * feat: add exports Add exports to be used by other developers when creating scripts for their own servers. * refactor: redo config setup * refactor: add blendInSpeed to PlayAnimOnce * refactor: use local function instead of global local functions are much faster to load then global ones. * refactor: redo CrouchKeyPressed Rewrite the entire function to use new configs * style: remove commented code * dev: add new version of crawl A temporary version of crawl, still in development. * refactor: make isProne a global variable Add @iSentrie 's suggestion to make isProne a global variable so it can be used in Emotes.lua to prevent animations being played while crawling. Co-authored-by: iSentrie <xvender7@gmail.com> * refactor: make global isProne uppercase * fix: add prone check before playing anim Add a check to see if we are prone before we play any animations. TODO: This needs to be translated for all the different languages. Co-Authored-By: iSentrie <29688478+iSentrie@users.noreply.github.com> * refactor: add function for idle crawl anim * refactor: increase blend in speed * refactor: add ChangeHeadingSmooth func * feat: add on back rotation anims * feat: use PlayAnimOnce instead * style: whitespace * feat: add config to disable keybinds * fix: convert to PlayAnimOnce func We aren't loading anim dict, let's use PlayAnimOnce instead to make it simple. * Update config default states * refactor: remove unnecessary variable keyPressed is just not needed, the command 'crouch' should't be fired at the same time regardless, so this can be safely removed. * refactor: merge functions * refactor: increase timer Increase the amount of time we should wait before we move to the idle state again. * fix: check if we are in water Only needs to be in crawl, you should be able to crouch along the waterfront. ClearPedTasks is also necessary to prevent the player getting stuck in an animation. * refactor: remove chat message As @iSentrie pointed out these are annoying in some situations. It's pretty self-explanatory why you can't crouch/crawl when these appear anyway. Co-Authored-By: iSentrie <29688478+iSentrie@users.noreply.github.com> * refactor: separate out exit crawl animations * refactor: better crawl entry anim * refactor: allow heading input on PlayIdleCrawlAnim * refactor: use PlayIdleCrawlAnim instead * fix: add inAction checks Fixes issues @iSentrie commented on. This may not cover all situations, needs more testing. * refactor: flip anim I've yet to find any good anims for this, this is the best, or least worst I've found so far. Better to have something then to literately do a flip. * fix: add point checks Disable pointing while crawling. * fix: remove clipsetreset There should be no reason to reset the clipset/walkstyle. This will only mess with crouching. * fix: disable weapon switching while prone * fix: don't play idle anim if we can't crawl We shouldn't play the anim as it will lead to weird behavior when ragdolling/falling while entry anim is played. * fix: move inAction Only set inAction to true when we actually can lay down. * fix: missing pointing check I'll just sneak this in here, "nobody will notice". * fix: check if in animation We should check if we are in an animation before crawling. * refactor: remove command args Remove command args to clean thing up. Suggested by @iSentrie Co-Authored-By: iSentrie <29688478+iSentrie@users.noreply.github.com> * refactor: cancel emote on crawl As suggested by @iSentrie Co-Authored-By: iSentrie <29688478+iSentrie@users.noreply.github.com> * Add comments * fix: add water checks Add checks, to lazy to type more, read the code. * fix: correct check statement Don't juge me, it's late ok Co-authored-by: iSentrie <xvender7@gmail.com> Co-authored-by: iSentrie <29688478+iSentrie@users.noreply.github.com>
479 lines
15 KiB
Lua
479 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, duration, blendInSpeed, startTime)
|
|
LoadAnimDict(animDict)
|
|
TaskPlayAnim(playerPed, animDict, animName, blendInSpeed or 2.0, 2.0, duration, 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", 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)
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
TaskPlayAnimAdvanced(playerPed, "move_crawl", proneType.."_fwd", playerCoords.x, playerCoords.y, playerCoords.z, 0.0, 0.0, heading or GetEntityHeading(playerPed), 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", 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", 1300)
|
|
end
|
|
else
|
|
PlayAnimOnce(playerPed, "get_up@directional@transition@prone_to_seated@crawl", "back", 950, 16.0)
|
|
|
|
-- 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", 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", -1, 2.0)
|
|
ChangeHeadingSmooth(playerPed, -18.0, 3600)
|
|
else
|
|
proneType = "onfront"
|
|
|
|
PlayAnimOnce(playerPed, "amb@world_human_bum_slumped@male@laying_on_left_side@flee", "back", 500, 2.0)
|
|
Wait(500)
|
|
end
|
|
|
|
PlayIdleCrawlAnim(playerPed, heading + 180.0)
|
|
Wait(400)
|
|
inAction = false
|
|
end
|
|
|
|
local function CrawlThread()
|
|
CreateThread(function()
|
|
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", -1)
|
|
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", -1)
|
|
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
|
|
|
|
-- 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, "move_jump", "dive_start_run", -1)
|
|
Wait(1050)
|
|
elseif wasCrouched then
|
|
PlayAnimOnce(playerPed, "amb@world_human_sunbathe@male@front@enter", "enter", -1, 2.0, 0.3)
|
|
Wait(1500)
|
|
else
|
|
PlayAnimOnce(playerPed, "amb@world_human_sunbathe@male@front@enter", "enter", -1)
|
|
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)
|
|
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)
|
|
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)
|