1065 lines
33 KiB
Lua
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)
|