2025-04-07 01:41:12 +00:00

1065 lines
33 KiB
Lua

local config = require 'config.client'
local sharedConfig = require 'config.shared'
local speedMultiplier = config.useMPH and 2.23694 or 3.6
local cruiseOn = false
local showAltitude = false
local showSeatbelt = false
local nos = 0
local playerState = LocalPlayer.state
local stress = playerState.stress or 0
local hunger = playerState.hunger or 100
local thirst = playerState.thirst or 100
local cashAmount = 0
local bankAmount = 0
local nitroActive = 0
local hp = 100
local armed = false
local parachute = -1
local oxygen = 100
local dev = false
local playerDead = false
local showMenu = false
local showCircleB = false
local showSquareB = false
local CinematicHeight = 0.2
local w = 0
local hasWeapon = false
DisplayRadar(false)
local function cinematicShow(bool)
SetBigmapActive(true, false)
Wait(0)
SetBigmapActive(false, false)
if bool then
for i = CinematicHeight, 0, -1.0 do
Wait(10)
w = i
end
else
for i = 0, CinematicHeight, 1.0 do
Wait(10)
w = i
end
end
end
local function loadSettings(settings)
for k, v in pairs(settings) do
if k == 'isToggleMapShapeChecked' then
sharedConfig.menu.isToggleMapShapeChecked = v
SendNUIMessage({test = true, event = k, toggle = v})
elseif k == 'isCineamticModeChecked' then
sharedConfig.menu.isCineamticModeChecked = v
cinematicShow(v)
SendNUIMessage({test = true, event = k, toggle = v})
elseif k == 'isChangeFPSChecked' then
sharedConfig.menu[k] = v
local val = v and 'Optimized' or 'Synced'
SendNUIMessage({test = true, event = k, toggle = val})
else
sharedConfig.menu[k] = v
SendNUIMessage({test = true, event = k, toggle = v})
end
end
exports.qbx_core:Notify(locale('notify.hud_settings_loaded'), 'success')
Wait(1000)
TriggerEvent('hud:client:LoadMap')
end
local function saveSettings()
SetResourceKvp('hudSettings', json.encode(sharedConfig.menu))
end
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
Wait(2000)
local hudSettings = GetResourceKvpString('hudSettings')
if hudSettings then loadSettings(json.decode(hudSettings)) end
stress = QBX.PlayerData.metadata.stress
hunger = QBX.PlayerData.metadata.hunger
thirst = QBX.PlayerData.metadata.thirst
hp = QBX.PlayerData.metadata.health
end)
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
Wait(2000)
local hudSettings = GetResourceKvpString('hudSettings')
if hudSettings then loadSettings(json.decode(hudSettings)) end
end)
-- Callbacks & Events
local function settingsMenu()
if showMenu then return end
SetNuiFocus(true, true)
SendNUIMessage({action = 'open'})
showMenu = true
end
lib.addKeybind({
name = 'hud_menu',
description = locale('info.open_menu'),
defaultKey = config.menuKey,
defaultMapper = 'keyboard',
onPressed = settingsMenu,
})
RegisterNUICallback('closeMenu', function(_, cb)
Wait(50)
showMenu = false
SetNuiFocus(false, false)
cb('ok')
end)
-- Reset hud
local function restartHud()
exports.qbx_core:Notify(locale('notify.hud_restart'), 'error')
if cache.vehicle then
Wait(2600)
SendNUIMessage({action = 'car', show = false})
SendNUIMessage({action = 'car', show = true})
end
Wait(2600)
SendNUIMessage({action = 'hudtick', show = false})
SendNUIMessage({action = 'hudtick', show = true})
Wait(2600)
exports.qbx_core:Notify(locale('notify.hud_start'), 'success')
end
RegisterNUICallback('restartHud', function(_, cb)
Wait(50)
restartHud()
cb('ok')
end)
RegisterCommand('resethud', function(_, cb)
Wait(50)
restartHud()
cb('ok')
end)
RegisterNUICallback('resetStorage', function(_, cb)
Wait(50)
TriggerEvent('hud:client:resetStorage')
cb('ok')
end)
RegisterNetEvent('hud:client:resetStorage', function()
Wait(50)
local menu = lib.callback.await('hud:server:getMenu', false)
loadSettings(menu)
SetResourceKvp('hudSettings', json.encode(menu))
end)
RegisterNUICallback('showOutMap', function(_, cb)
Wait(50)
sharedConfig.menu.isOutMapChecked = not sharedConfig.menu.isOutMapChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showOutCompass', function(_, cb)
Wait(50)
sharedConfig.menu.isOutCompassChecked = not sharedConfig.menu.isOutCompassChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showFollowCompass', function(_, cb)
Wait(50)
sharedConfig.menu.isCompassFollowChecked = not sharedConfig.menu.isCompassFollowChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showMapNotif', function(_, cb)
Wait(50)
sharedConfig.menu.isMapNotifChecked = not sharedConfig.menu.isMapNotifChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showFuelAlert', function(_, cb)
Wait(50)
sharedConfig.menu.isLowFuelChecked = not sharedConfig.menu.isLowFuelChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showCinematicNotif', function(_, cb)
Wait(50)
sharedConfig.menu.isCinematicNotifChecked = not sharedConfig.menu.isCinematicNotifChecked
saveSettings()
cb('ok')
end)
-- Status
RegisterNUICallback('dynamicHealth', function(_, cb)
Wait(50)
TriggerEvent('hud:client:ToggleHealth')
cb('ok')
end)
RegisterNetEvent('hud:client:ToggleHealth', function()
Wait(50)
sharedConfig.menu.isDynamicHealthChecked = not sharedConfig.menu.isDynamicHealthChecked
saveSettings()
end)
RegisterNUICallback('dynamicArmor', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicArmorChecked = not sharedConfig.menu.isDynamicArmorChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicHunger', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicHungerChecked = not sharedConfig.menu.isDynamicHungerChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicThirst', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicThirstChecked = not sharedConfig.menu.isDynamicThirstChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicStress', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicStressChecked = not sharedConfig.menu.isDynamicStressChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicOxygen', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicOxygenChecked = not sharedConfig.menu.isDynamicOxygenChecked
saveSettings()
cb('ok')
end)
-- Vehicle
RegisterNUICallback('changeFPS', function(_, cb)
Wait(50)
sharedConfig.menu.isChangeFPSChecked = not sharedConfig.menu.isChangeFPSChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('HideMap', function(_, cb)
Wait(50)
sharedConfig.menu.isHideMapChecked = not sharedConfig.menu.isHideMapChecked
DisplayRadar(not sharedConfig.menu.isHideMapChecked)
saveSettings()
cb('ok')
end)
RegisterNetEvent('hud:client:LoadMap', function()
Wait(50)
-- Credit to Dalrae for the solve.
local defaultAspectRatio = 1920 / 1080 -- Don't change this.
local resolutionX, resolutionY = GetActiveScreenResolution()
local aspectRatio = resolutionX / resolutionY
local minimapOffset = 0
if aspectRatio > defaultAspectRatio then
minimapOffset = ((defaultAspectRatio-aspectRatio) / 3.6) - 0.008
end
if sharedConfig.menu.isToggleMapShapeChecked == 'square' then
lib.requestStreamedTextureDict('squaremap')
if sharedConfig.menu.isMapNotifChecked then
exports.qbx_core:Notify(locale('notify.load_square_map'), 'inform')
end
SetMinimapClipType(0)
AddReplaceTexture('platform:/textures/graphics', 'radarmasksm', 'squaremap', 'radarmasksm')
AddReplaceTexture('platform:/textures/graphics', 'radarmask1g', 'squaremap', 'radarmasksm')
-- 0.0 = nav symbol and icons left
-- 0.1638 = nav symbol and icons stretched
-- 0.216 = nav symbol and icons raised up
SetMinimapComponentPosition('minimap', 'L', 'B', 0.0 + minimapOffset, -0.047, 0.1638, 0.183)
-- icons within map
SetMinimapComponentPosition('minimap_mask', 'L', 'B', 0.0 + minimapOffset, 0.0, 0.128, 0.20)
-- -0.01 = map pulled left
-- 0.025 = map raised up
-- 0.262 = map stretched
-- 0.315 = map shorten
SetMinimapComponentPosition('minimap_blur', 'L', 'B', -0.01 + minimapOffset, 0.025, 0.262, 0.300)
SetBlipAlpha(GetNorthRadarBlip(), 0)
SetBigmapActive(true, false)
SetMinimapClipType(0)
Wait(50)
SetBigmapActive(false, false)
if sharedConfig.menu.isToggleMapBordersChecked then
showCircleB = false
showSquareB = true
end
Wait(1200)
if sharedConfig.menu.isMapNotifChecked then
exports.qbx_core:Notify(locale('notify.loaded_square_map'), 'success')
end
elseif sharedConfig.menu.isToggleMapShapeChecked == 'circle' then
lib.requestStreamedTextureDict('circlemap')
if sharedConfig.menu.isMapNotifChecked then
exports.qbx_core:Notify(locale('notify.load_circle_map'), 'inform')
end
SetMinimapClipType(1)
AddReplaceTexture('platform:/textures/graphics', 'radarmasksm', 'circlemap', 'radarmasksm')
AddReplaceTexture('platform:/textures/graphics', 'radarmask1g', 'circlemap', 'radarmasksm')
-- -0.0100 = nav symbol and icons left
-- 0.180 = nav symbol and icons stretched
-- 0.258 = nav symbol and icons raised up
SetMinimapComponentPosition('minimap', 'L', 'B', -0.0100 + minimapOffset, -0.030, 0.180, 0.258)
-- icons within map
SetMinimapComponentPosition('minimap_mask', 'L', 'B', 0.200 + minimapOffset, 0.0, 0.065, 0.20)
-- -0.00 = map pulled left
-- 0.015 = map raised up
-- 0.252 = map stretched
-- 0.338 = map shorten
SetMinimapComponentPosition('minimap_blur', 'L', 'B', -0.00 + minimapOffset, 0.015, 0.252, 0.338)
SetBlipAlpha(GetNorthRadarBlip(), 0)
SetMinimapClipType(1)
SetBigmapActive(true, false)
Wait(50)
SetBigmapActive(false, false)
if sharedConfig.menu.isToggleMapBordersChecked then
showSquareB = false
showCircleB = true
end
Wait(1200)
if sharedConfig.menu.isMapNotifChecked then
exports.qbx_core:Notify(locale('notify.loaded_circle_map'), 'success')
end
end
end)
RegisterNUICallback('ToggleMapShape', function(_, cb)
Wait(50)
if not sharedConfig.menu.isHideMapChecked then
sharedConfig.menu.isToggleMapShapeChecked = sharedConfig.menu.isToggleMapShapeChecked == 'circle' and 'square' or 'circle'
Wait(50)
TriggerEvent('hud:client:LoadMap')
end
saveSettings()
cb('ok')
end)
RegisterNUICallback('ToggleMapBorders', function(_, cb)
Wait(50)
sharedConfig.menu.isToggleMapBordersChecked = not sharedConfig.menu.isToggleMapBordersChecked
if sharedConfig.menu.isToggleMapBordersChecked then
if sharedConfig.menu.isToggleMapShapeChecked == 'square' then
showSquareB = true
else
showCircleB = true
end
else
showSquareB = false
showCircleB = false
end
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicEngine', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicEngineChecked = not sharedConfig.menu.isDynamicEngineChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('dynamicNitro', function(_, cb)
Wait(50)
sharedConfig.menu.isDynamicNitroChecked = not sharedConfig.menu.isDynamicNitroChecked
saveSettings()
cb('ok')
end)
-- Compass
RegisterNUICallback('showCompassBase', function(_, cb)
Wait(50)
sharedConfig.menu.isCompassShowChecked = not sharedConfig.menu.isCompassShowChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showStreetsNames', function(_, cb)
Wait(50)
sharedConfig.menu.isShowStreetsChecked = not sharedConfig.menu.isShowStreetsChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showPointerIndex', function(_, cb)
Wait(50)
sharedConfig.menu.isPointerShowChecked = not sharedConfig.menu.isPointerShowChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('showDegreesNum', function(_, cb)
Wait(50)
sharedConfig.menu.isDegreesShowChecked = not sharedConfig.menu.isDegreesShowChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('changeCompassFPS', function(_, cb)
Wait(50)
sharedConfig.menu.isChangeCompassFPSChecked = not sharedConfig.menu.isChangeCompassFPSChecked
saveSettings()
cb('ok')
end)
RegisterNUICallback('cinematicMode', function(_, cb)
Wait(50)
if sharedConfig.menu.isCineamticModeChecked then
cinematicShow(false)
sharedConfig.menu.isCineamticModeChecked = false
if sharedConfig.menu.isCinematicNotifChecked then
exports.qbx_core:Notify(locale('notify.cinematic_off'), 'error')
end
DisplayRadar(true)
else
cinematicShow(true)
sharedConfig.menu.isCineamticModeChecked = true
if sharedConfig.menu.isCinematicNotifChecked then
exports.qbx_core:Notify(locale('notify.cinematic_on'), 'success')
end
end
saveSettings()
cb('ok')
end)
RegisterNetEvent('hud:client:ToggleAirHud', function()
showAltitude = not showAltitude
end)
---@deprecated Use statebags instead
RegisterNetEvent('hud:client:UpdateNeeds', function(newHunger, newThirst) -- Triggered in qb-core
hunger = newHunger
thirst = newThirst
end)
AddStateBagChangeHandler('hunger', ('player:%s'):format(cache.serverId), function(_, _, value)
hunger = value
end)
AddStateBagChangeHandler('thirst', ('player:%s'):format(cache.serverId), function(_, _, value)
thirst = value
end)
---@deprecated Use statebags instead
RegisterNetEvent('hud:client:UpdateStress', function(newStress)
stress = newStress
end)
AddStateBagChangeHandler('stress', ('player:%s'):format(cache.serverId), function(_, _, value)
stress = value
end)
RegisterNetEvent('hud:client:ToggleShowSeatbelt', function()
showSeatbelt = not showSeatbelt
end)
RegisterNetEvent('seatbelt:client:ToggleCruise', function() -- Triggered in smallresources
cruiseOn = not cruiseOn
end)
---@deprecated Use statebags instead
RegisterNetEvent('hud:client:UpdateNitrous', function(_, nitroLevel, bool)
nos = nitroLevel
nitroActive = bool
end)
qbx.entityStateHandler('nitroFlames', function(veh, netId, value)
local plate = qbx.string.trim(GetVehicleNumberPlateText(veh))
local cachePlate = qbx.string.trim(GetVehicleNumberPlateText(cache.vehicle))
if plate ~= cachePlate then return end
nitroActive = value
end)
qbx.entityStateHandler('nitro', function(veh, netId, value)
local plate = qbx.string.trim(GetVehicleNumberPlateText(veh))
local cachePlate = qbx.string.trim(GetVehicleNumberPlateText(cache.vehicle))
if plate ~= cachePlate then return end
nos = value
end)
RegisterNetEvent('hud:client:UpdateHarness', function(harnessHp)
hp = harnessHp
end)
RegisterNetEvent('qb-admin:client:ToggleDevmode', function()
dev = not dev
end)
local function isWhitelistedWeaponArmed(weapon)
if weapon then
for _, v in pairs(config.weaponsArmedMode) do
if weapon == v then
return true
end
end
end
return false
end
local prevPlayerStats = {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}
local function updatePlayerHud(data)
local shouldUpdate = false
for k, v in pairs(data) do
if prevPlayerStats[k] ~= v then
shouldUpdate = true
break
end
end
prevPlayerStats = data
if shouldUpdate then
SendNUIMessage({
action = 'hudtick',
show = data[1],
dynamicHealth = data[2],
dynamicArmor = data[3],
dynamicHunger = data[4],
dynamicThirst = data[5],
dynamicStress = data[6],
dynamicOxygen = data[7],
dynamicEngine = data[8],
dynamicNitro = data[9],
health = data[10],
playerDead = data[11],
armor = data[12],
thirst = data[13],
hunger = data[14],
stress = data[15],
voice = data[16],
radio = data[17],
talking = data[18],
armed = data[19],
oxygen = data[20],
parachute = data[21],
nos = data[22],
cruise = data[23],
nitroActive = data[24],
harness = data[25],
hp = data[26],
speed = data[27],
engine = data[28],
cinematic = data[29],
dev = data[30],
})
end
end
local prevVehicleStats = {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}
local function updateVehicleHud(data)
local shouldUpdate = false
local invOpen = LocalPlayer.state.invOpen
for k, v in pairs(data) do
if prevVehicleStats[k] ~= v then shouldUpdate = true break end
end
prevVehicleStats = data
if shouldUpdate and not invOpen then
SendNUIMessage({
action = 'car',
show = data[1],
isPaused = data[2],
seatbelt = data[3],
speed = data[4],
fuel = data[5],
altitude = data[6],
showAltitude = data[7],
showSeatbelt = data[8],
showSquareB = data[9],
showCircleB = data[10],
})
end
end
local lastFuelUpdate = 0
local lastFuelCheck = 0
local function getFuelLevel(vehicle)
local updateTick = GetGameTimer()
if (updateTick - lastFuelUpdate) > 2000 then
lastFuelUpdate = updateTick
lastFuelCheck = math.floor(GetVehicleFuelLevel(vehicle))
end
return lastFuelCheck
end
-- HUD Update loop
CreateThread(function()
local wasInVehicle = false
while true do
if sharedConfig.menu.isChangeFPSChecked then
Wait(500)
else
Wait(50)
end
if LocalPlayer.state.isLoggedIn then
local show = true
local weapon = GetSelectedPedWeapon(cache.ped)
-- Player hud
if not isWhitelistedWeaponArmed(weapon) then
if weapon ~= `WEAPON_UNARMED` then
armed = true
else
armed = false
end
end
playerDead = IsEntityDead(cache.ped) or QBX.PlayerData.metadata.inlaststand or QBX.PlayerData.metadata.isdead
parachute = GetPedParachuteState(cache.ped)
-- Stamina
if not IsEntityInWater(cache.ped) then
oxygen = 100 - GetPlayerSprintStaminaRemaining(cache.playerId)
end
-- Oxygen
if IsEntityInWater(cache.ped) then
oxygen = GetPlayerUnderwaterTimeRemaining(cache.playerId) * 10
end
-- Player hud
local talking = NetworkIsPlayerTalking(cache.playerId)
local voice = 0
if LocalPlayer.state.proximity then
voice = LocalPlayer.state.proximity.distance
end
if IsPauseMenuActive() then
show = false
end
if not (cache.vehicle and not IsThisModelABicycle(cache.vehicle)) then
updatePlayerHud({
show,
sharedConfig.menu.isDynamicHealthChecked,
sharedConfig.menu.isDynamicArmorChecked,
sharedConfig.menu.isDynamicHungerChecked,
sharedConfig.menu.isDynamicThirstChecked,
sharedConfig.menu.isDynamicStressChecked,
sharedConfig.menu.isDynamicOxygenChecked,
sharedConfig.menu.isDynamicEngineChecked,
sharedConfig.menu.isDynamicNitroChecked,
GetEntityHealth(cache.ped) - 100,
playerDead,
GetPedArmour(cache.ped),
thirst,
hunger,
stress,
voice,
LocalPlayer.state.radioChannel,
talking,
armed,
oxygen,
parachute,
-1,
cruiseOn,
nitroActive,
LocalPlayer.state?.harness,
hp,
math.ceil(GetEntitySpeed(cache.vehicle) * speedMultiplier),
-1,
sharedConfig.menu.isCineamticModeChecked,
dev,
})
end
-- Vehicle hud
if IsPedInAnyHeli(cache.ped) or IsPedInAnyPlane(cache.ped) then
showAltitude = true
showSeatbelt = false
end
if cache.vehicle and not IsThisModelABicycle(cache.vehicle) then
if not wasInVehicle then
DisplayRadar(true)
end
wasInVehicle = true
updatePlayerHud({
show,
sharedConfig.menu.isDynamicHealthChecked,
sharedConfig.menu.isDynamicArmorChecked,
sharedConfig.menu.isDynamicHungerChecked,
sharedConfig.menu.isDynamicThirstChecked,
sharedConfig.menu.isDynamicStressChecked,
sharedConfig.menu.isDynamicOxygenChecked,
sharedConfig.menu.isDynamicEngineChecked,
sharedConfig.menu.isDynamicNitroChecked,
GetEntityHealth(cache.ped) - 100,
playerDead,
GetPedArmour(cache.ped),
thirst,
hunger,
stress,
voice,
LocalPlayer.state.radioChannel,
talking,
armed,
oxygen,
GetPedParachuteState(cache.ped),
nos,
cruiseOn,
nitroActive,
LocalPlayer.state?.harness,
hp,
math.ceil(GetEntitySpeed(cache.vehicle) * speedMultiplier),
(GetVehicleEngineHealth(cache.vehicle) / 10),
sharedConfig.menu.isCineamticModeChecked,
dev,
})
updateVehicleHud({
show,
IsPauseMenuActive(),
LocalPlayer.state?.seatbelt,
math.ceil(GetEntitySpeed(cache.vehicle) * speedMultiplier),
getFuelLevel(cache.vehicle),
math.ceil(GetEntityCoords(cache.ped).z * 0.5),
showAltitude,
showSeatbelt,
showSquareB,
showCircleB,
})
showAltitude = false
showSeatbelt = true
else
if wasInVehicle then
wasInVehicle = false
SendNUIMessage({
action = 'car',
show = false,
seatbelt = false,
cruise = false,
})
cruiseOn = false
end
DisplayRadar(sharedConfig.menu.isOutMapChecked)
end
else
SendNUIMessage({
action = 'hudtick',
show = false
})
end
end
end)
-- Low fuel
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
if cache.vehicle and not IsThisModelABicycle(GetEntityModel(cache.vehicle)) then
if getFuelLevel(cache.vehicle) <= 20 then -- At 20% Fuel Left
if sharedConfig.menu.isLowFuelChecked then
-- Add pager sound for when fuel is low
exports.qbx_core:Notify(locale('notify.low_fuel'), 'error')
Wait(60000) -- repeats every 1 min until empty
end
end
end
end
Wait(10000)
end
end)
-- Money HUD
RegisterNetEvent('hud:client:ShowAccounts', function(type, amount)
if type == 'cash' then
SendNUIMessage({
action = 'show',
type = 'cash',
cash = amount
})
else
SendNUIMessage({
action = 'show',
type = 'bank',
bank = amount
})
end
end)
RegisterNetEvent('hud:client:OnMoneyChange', function(type, amount, isMinus)
cashAmount = QBX.PlayerData.money.cash
bankAmount = QBX.PlayerData.money.bank
SendNUIMessage({
action = 'updatemoney',
cash = cashAmount,
bank = bankAmount,
amount = amount,
minus = isMinus,
type = type
})
end)
-- Stress Gain
if config.stress.enableStress then
CreateThread(function() -- Speeding
while true do
if LocalPlayer.state.isLoggedIn then
if cache.vehicle then
local vehClass = GetVehicleClass(cache.vehicle)
local speed = GetEntitySpeed(cache.vehicle) * speedMultiplier
if vehClass ~= 13 and vehClass ~= 14 and vehClass ~= 15 and vehClass ~= 16 and vehClass ~= 21 then
local stressSpeed
if vehClass == 8 then
stressSpeed = config.stress.minForSpeeding
else
stressSpeed = LocalPlayer.state?.seatbelt and config.stress.minForSpeeding or config.stress.minForSpeedingUnbuckled
end
if speed >= stressSpeed then
TriggerServerEvent('hud:server:GainStress', math.random(1, 3))
end
end
end
end
Wait(10000)
end
end)
end
local function isWhitelistedWeaponStress(weapon)
if weapon then
for _, v in pairs(config.stress.whitelistedWeapons) do
if weapon == v then
return true
end
end
end
return false
end
local function startWeaponStressThread(weapon)
if isWhitelistedWeaponStress(weapon) then return end
hasWeapon = true
CreateThread(function()
while hasWeapon do
if IsPedShooting(cache.ped) then
if math.random() <= config.stress.chance then
TriggerServerEvent('hud:server:GainStress', math.random(1, 5))
end
end
Wait(0)
end
end)
end
AddEventHandler('ox_inventory:currentWeapon', function(currentWeapon)
hasWeapon = false
Wait(0)
if not currentWeapon then return end
startWeaponStressThread(currentWeapon.hash)
end)
-- Stress Screen Effects
local function getBlurIntensity(stresslevel)
for _, v in pairs(config.stress.blurIntensity) do
if stresslevel >= v.min and stresslevel <= v.max then
return v.intensity
end
end
return 1500
end
local function getEffectInterval(stresslevel)
for _, v in pairs(config.stress.effectInterval) do
if stresslevel >= v.min and stresslevel <= v.max then
return v.timeout
end
end
return 60000
end
CreateThread(function()
while true do
local effectInterval = getEffectInterval(stress)
if stress >= 100 then
local blurIntensity = getBlurIntensity(stress)
local fallRepeat = math.random(2, 4)
local ragdollTimeout = fallRepeat * 1750
TriggerScreenblurFadeIn(1000.0)
Wait(blurIntensity)
TriggerScreenblurFadeOut(1000.0)
if not IsPedRagdoll(cache.ped) and IsPedOnFoot(cache.ped) and not IsPedSwimming(cache.ped) then
local forwardVector = GetEntityForwardVector(cache.ped)
SetPedToRagdollWithFall(cache.ped, ragdollTimeout, ragdollTimeout, 1, forwardVector.x, forwardVector.y, forwardVector.z, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
end
Wait(1000)
for _ = 1, fallRepeat, 1 do
Wait(750)
DoScreenFadeOut(200)
Wait(1000)
DoScreenFadeIn(200)
TriggerScreenblurFadeIn(1000.0)
Wait(blurIntensity)
TriggerScreenblurFadeOut(1000.0)
end
elseif stress >= config.stress.minForShaking then
local blurIntensity = getBlurIntensity(stress)
TriggerScreenblurFadeIn(1000.0)
Wait(blurIntensity)
TriggerScreenblurFadeOut(1000.0)
end
Wait(effectInterval)
end
end)
local function blackBars()
DrawRect(0.0, 0.0, 2.0, w, 0, 0, 0, 255)
DrawRect(0.0, 1.0, 2.0, w, 0, 0, 0, 255)
end
CreateThread(function()
while true do
if w > 0 then
blackBars()
DisplayRadar(false)
SendNUIMessage({
action = 'hudtick',
show = false,
})
SendNUIMessage({
action = 'car',
show = false,
})
end
Wait(0)
end
end)
-- Compass
local prevBaseplateStats = {nil, nil, nil, nil, nil, nil, nil}
local function updateBaseplateHud(data)
local shouldUpdate = false
for k, v in pairs(data) do
if prevBaseplateStats[k] ~= v then shouldUpdate = true break end
end
prevBaseplateStats = data
if shouldUpdate then
SendNUIMessage ({
action = 'baseplate',
show = data[1],
street1 = data[2],
street2 = data[3],
showCompass = data[4],
showStreets = data[5],
showPointer = data[6],
showDegrees = data[7],
})
end
end
local lastCrossroadUpdate = 0
local lastCrossroadCheck = {}
local function getCrossroads(player)
local updateTick = GetGameTimer()
if updateTick - lastCrossroadUpdate > 1500 then
local pos = GetEntityCoords(player)
local street1, street2 = GetStreetNameAtCoord(pos.x, pos.y, pos.z)
lastCrossroadUpdate = updateTick
lastCrossroadCheck = {GetStreetNameFromHashKey(street1), GetStreetNameFromHashKey(street2)}
end
return lastCrossroadCheck
end
-- Compass Update loop
CreateThread(function()
local lastHeading = 1
local heading
while true do
if sharedConfig.menu.isChangeCompassFPSChecked then
Wait(50)
else
Wait(0)
end
local show = true
local camRot = GetGameplayCamRot(0)
if sharedConfig.menu.isCompassFollowChecked then
heading = qbx.math.round(360.0 - ((camRot.z + 360.0) % 360.0))
else
heading = qbx.math.round(360.0 - GetEntityHeading(cache.ped))
end
if heading == 360 then heading = 0 end
if heading ~= lastHeading then
if cache.vehicle then
local crossroads = getCrossroads(cache.ped)
SendNUIMessage ({
action = 'update',
value = heading
})
updateBaseplateHud({
show,
crossroads[1],
crossroads[2],
sharedConfig.menu.isCompassShowChecked,
sharedConfig.menu.isShowStreetsChecked,
sharedConfig.menu.isPointerShowChecked,
sharedConfig.menu.isDegreesShowChecked,
})
else
if sharedConfig.menu.isOutCompassChecked then
SendNUIMessage ({
action = 'update',
value = heading
})
SendNUIMessage ({
action = 'baseplate',
show = true,
showCompass = true,
})
else
SendNUIMessage ({
action = 'baseplate',
show = false,
})
end
end
end
lastHeading = heading
end
end)
RegisterNetEvent('qbx_hud:client:showHud', function()
if cache.vehicle then
DisplayRadar(true)
updateVehicleHud({
true,
IsPauseMenuActive(),
LocalPlayer.state?.seatbelt,
math.ceil(GetEntitySpeed(cache.vehicle) * speedMultiplier),
getFuelLevel(cache.vehicle),
math.ceil(GetEntityCoords(cache.ped).z * 0.5),
showAltitude,
showSeatbelt,
showSquareB,
showCircleB,
})
end
end)
RegisterNetEvent('qbx_hud:client:hideHud', function()
if cache.vehicle then
DisplayRadar(false)
SendNUIMessage({
action = 'car',
show = false,
})
end
end)