1
0
Fork 0
forked from Simnation/Main
Main/resources/[standalone]/rpemotes-reborn/client/Utils.lua

396 lines
13 KiB
Lua
Raw Permalink Normal View History

2025-06-07 08:51:21 +02:00
-- You can edit this function to add support for your favorite notification system
function SimpleNotify(message)
if Config.NotificationsAsChatMessage then
TriggerEvent("chat:addMessage", { color = { 255, 255, 255 }, args = { tostring(message) } })
else
BeginTextCommandThefeedPost("STRING")
AddTextComponentSubstringPlayerName(message)
EndTextCommandThefeedPostTicker(true, true)
end
end
2025-06-12 03:36:12 +02:00
-- Don't touch after this line if you don't know what you're doing
CreateExport = function(name, func)
AddEventHandler('__cfx_export_rpemotes_'..name, function(setCb)
setCb(function(...)
return func(...)
end)
end)
exports(name, func)
end
2025-06-07 08:51:21 +02:00
function DebugPrint(...)
if Config.DebugDisplay then
print(...)
end
end
function FirstToUpper(str)
return (str:gsub("^%l", string.upper))
end
function IsPlayerAiming(player)
return (IsPlayerFreeAiming(player) or IsAimCamActive() or IsAimCamThirdPersonActive()) and
tonumber(GetSelectedPedWeapon(player)) ~= tonumber(GetHashKey("WEAPON_UNARMED"))
end
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
function PlayAnimOnce(playerPed, animDict, animName, blendInSpeed, blendOutSpeed, duration, startTime)
LoadAnim(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
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
function EmoteChatMessage(msg, multiline)
if msg then
TriggerEvent("chat:addMessage", {
multiline = multiline == true or false,
color = { 255, 255, 255 },
args = { "^1Help^0", tostring(msg) }
})
end
end
function PairsByKeys(t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function() -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
function LoadAnim(dict)
if not DoesAnimDictExist(dict) then
return false
end
local timeout = 2000
while not HasAnimDictLoaded(dict) and timeout > 0 do
RequestAnimDict(dict)
Wait(5)
timeout = timeout - 5
end
if timeout == 0 then
DebugPrint("Loading anim dict " .. dict .. " timed out")
return false
else
return true
end
end
function LoadPropDict(model)
2025-06-12 03:36:12 +02:00
if not HasModelLoaded(GetHashKey(model)) then
RequestModel(GetHashKey(model))
2025-06-07 08:51:21 +02:00
local timeout = 2000
2025-06-12 03:36:12 +02:00
while not HasModelLoaded(GetHashKey(model)) and timeout > 0 do
2025-06-07 08:51:21 +02:00
Wait(5)
timeout = timeout - 5
end
if timeout == 0 then
DebugPrint("Loading model " .. model .. " timed out")
return
end
end
end
function TableHasKey(table, key)
return table[key] ~= nil
end
function RequestWalking(set)
local timeout = GetGameTimer() + 5000
while not HasAnimSetLoaded(set) and GetGameTimer() < timeout do
RequestAnimSet(set)
Wait(5)
end
end
function GetPedInFront()
local player = PlayerId()
local plyPed = GetPlayerPed(player)
local plyPos = GetEntityCoords(plyPed, false)
local plyOffset = GetOffsetFromEntityInWorldCoords(plyPed, 0.0, 1.3, 0.0)
local rayHandle = StartShapeTestCapsule(plyPos.x, plyPos.y, plyPos.z, plyOffset.x, plyOffset.y, plyOffset.z, 10.0, 12
, plyPed, 7)
local _, _, _, _, ped2 = GetShapeTestResult(rayHandle)
return ped2
end
function NearbysOnCommand(source, args, raw)
local NearbysCommand = ""
2025-06-12 03:36:12 +02:00
for a, b in PairsByKeys(RP) do
if type(b) == "table" and b.category == "Shared" then
NearbysCommand = NearbysCommand .. a .. ", "
end
2025-06-07 08:51:21 +02:00
end
EmoteChatMessage(NearbysCommand)
EmoteChatMessage(Translate('emotemenucmd'))
end
function GetClosestPlayer()
local players = GetPlayers()
local closestDistance = -1
local closestPlayer
local ped = PlayerPedId()
local pedCoords = GetEntityCoords(ped, false)
for index, value in ipairs(players) do
local target = GetPlayerPed(value)
if (target ~= ped) then
local targetCoords = GetEntityCoords(GetPlayerPed(value), false)
local distance = GetDistanceBetweenCoords(targetCoords["x"], targetCoords["y"], targetCoords["z"],
pedCoords["x"], pedCoords["y"], pedCoords["z"], true)
if (closestDistance == -1 or closestDistance > distance) then
closestPlayer = value
closestDistance = distance
end
end
end
return closestPlayer, closestDistance
end
function GetPlayers()
local players = {}
for i = 0, 255 do
if NetworkIsPlayerActive(i) then
table.insert(players, i)
end
end
return players
end
-- Function that'll check if player is already proning, using news cam or else
---@param ignores? table | nil key string is the ignored value
function IsInActionWithErrorMessage(ignores)
2025-06-12 03:36:12 +02:00
if ignores then DebugPrint(ignores) end
2025-06-07 08:51:21 +02:00
DebugPrint('IsProne', IsProne)
DebugPrint('IsUsingNewscam', IsUsingNewscam)
DebugPrint('IsUsingBinoculars', IsUsingBinoculars)
if (ignores == nil) then ignores = {} end
if not ignores['IsProne'] and IsProne then
EmoteChatMessage(Translate('no_anim_crawling'))
return true
end
if not ignores['IsUsingNewscam'] and IsUsingNewscam then
-- TODO: use specific error message
EmoteChatMessage(Translate('no_anim_right_now'))
return true
end
if not ignores['IsUsingBinoculars'] and IsUsingBinoculars then
-- TODO: use specific error message
EmoteChatMessage(Translate('no_anim_right_now'))
return true
end
return false
end
function HideHUDThisFrame()
HideHelpTextThisFrame()
HideHudAndRadarThisFrame()
HideHudComponentThisFrame(19) -- weapon wheel
HideHudComponentThisFrame(1) -- Wanted Stars
HideHudComponentThisFrame(2) -- Weapon icon
HideHudComponentThisFrame(3) -- Cash
HideHudComponentThisFrame(4) -- MP CASH
HideHudComponentThisFrame(13) -- Cash Change
HideHudComponentThisFrame(11) -- Floating Help Text
HideHudComponentThisFrame(12) -- more floating help text
HideHudComponentThisFrame(15) -- Subtitle Text
HideHudComponentThisFrame(18) -- Game Stream
end
function SetupButtons(button)
local scaleform = RequestScaleformMovie("instructional_buttons")
while not HasScaleformMovieLoaded(scaleform) do
Wait(10)
end
PushScaleformMovieFunction(scaleform, "CLEAR_ALL")
PopScaleformMovieFunctionVoid()
PushScaleformMovieFunction(scaleform, "SET_CLEAR_SPACE")
PushScaleformMovieFunctionParameterInt(200)
PopScaleformMovieFunctionVoid()
for i, btn in pairs(button) do
PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT")
PushScaleformMovieFunctionParameterInt(i - 1)
ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(0, btn.key, true))
BeginTextCommandScaleformString("STRING")
AddTextComponentScaleform(Translate(btn.text))
EndTextCommandScaleformString()
PopScaleformMovieFunctionVoid()
end
PushScaleformMovieFunction(scaleform, "DRAW_INSTRUCTIONAL_BUTTONS")
PopScaleformMovieFunctionVoid()
return scaleform
end
function HandleZoomAndCheckRotation(cam, fov)
local zoomspeed = 10.0 -- camera zoom speed
local lPed = PlayerPedId()
local fov_max = 70.0
local fov_min = 10.0 -- max zoom level (smaller fov is more zoom)
local speed_lr = 8.0 -- speed by which the camera pans left-right
local speed_ud = 8.0 -- speed by which the camera pans up-down
local zoomvalue = (1.0 / (fov_max - fov_min)) * (fov - fov_min)
local rightAxisX = GetDisabledControlNormal(0, 220)
local rightAxisY = GetDisabledControlNormal(0, 221)
local rotation = GetCamRot(cam, 2)
if rightAxisX ~= 0.0 or rightAxisY ~= 0.0 then
local new_z = rotation.z + rightAxisX * -1.0 * (speed_ud) * (zoomvalue + 0.1)
local new_x = math.max(math.min(20.0, rotation.x + rightAxisY * -1.0 * (speed_lr) * (zoomvalue + 0.1)), -29.5)
SetCamRot(cam, new_x, 0.0, new_z, 2)
end
if not (IsPedSittingInAnyVehicle(lPed)) then
if IsControlJustPressed(0, 241) then -- Scrollup
fov = math.max(fov - zoomspeed, fov_min)
end
if IsControlJustPressed(0, 242) then
fov = math.min(fov + zoomspeed, fov_max) -- ScrollDown
end
local current_fov = GetCamFov(cam)
if math.abs(fov - current_fov) < 0.1 then
fov = current_fov
end
SetCamFov(cam, current_fov + (fov - current_fov) * 0.05)
else
if IsControlJustPressed(0, 17) then -- Scrollup
fov = math.max(fov - zoomspeed, fov_min)
end
if IsControlJustPressed(0, 16) then
fov = math.min(fov + zoomspeed, fov_max) -- ScrollDown
end
local current_fov = GetCamFov(cam)
if math.abs(fov - current_fov) < 0.1 then -- the difference is too small, just set the value directly to avoid unneeded updates to FOV of order 10^-5
fov = current_fov
end
SetCamFov(cam, current_fov + (fov - current_fov) * 0.05) -- Smoothing of camera zoom
end
return fov
end
----------------------------------------------------------------------
ShowPed = false
function ShowPedMenu(zoom)
if not Config.PreviewPed then return end
if not ShowPed then
CreateThread(function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed) - vector3(0.0, 0.0, 10.0)
ClonedPed = CreatePed(26, GetEntityModel(playerPed), coords.x, coords.y, coords.z, 0, false, false)
ClonePedToTarget(playerPed, ClonedPed)
SetEntityInvincible(ClonedPed, true)
SetEntityLocallyVisible(ClonedPed)
NetworkSetEntityInvisibleToNetwork(ClonedPed, true)
SetEntityCanBeDamaged(ClonedPed, false)
SetBlockingOfNonTemporaryEvents(ClonedPed, true)
SetEntityAlpha(ClonedPed, 254, false)
SetEntityCollision(ClonedPed, false, false)
ShowPed = true
local positionBuffer = {}
local bufferSize = 5
while ShowPed do
local screencoordsX = zoom and 0.6 or 0.65135417461395
local screencoordsY = zoom and 1.9 or 0.77
if Config.MenuPosition == "left" then
screencoordsX = 1.0 - screencoordsX
end
local world, normal = GetWorldCoordFromScreenCoord(screencoordsX, screencoordsY)
local depth = zoom and 2.0 or 3.5
local target = world + normal * depth
local camRot = GetGameplayCamRot(2)
table.insert(positionBuffer, target)
if #positionBuffer > bufferSize then
table.remove(positionBuffer, 1)
end
local averagedTarget = vector3(0, 0, 0)
for _, position in ipairs(positionBuffer) do
averagedTarget = averagedTarget + position
end
averagedTarget = averagedTarget / #positionBuffer
SetEntityCoords(ClonedPed, averagedTarget.x, averagedTarget.y, averagedTarget.z, false, false, false, true)
local heading_offset = Config.MenuPosition == "left" and 170.0 or 190.0
SetEntityHeading(ClonedPed, camRot.z + heading_offset)
SetEntityRotation(ClonedPed, camRot.x * (-1), 0.0, camRot.z + 170.0, 2, false)
Wait(4)
end
DeleteEntity(ClonedPed)
ClonedPed = nil
end)
end
end
function ClosePedMenu()
if not Config.PreviewPed then return end
if ClonedPed then
ShowPed = false
ClearPedTaskPreview()
DeleteEntity(ClonedPed)
end
end
function ClearPedTaskPreview()
if not Config.PreviewPed then return end
if ClonedPed then
DestroyAllProps(true)
ClearPedTasksImmediately(ClonedPed)
end
end