From 8d8b124495ef57e0beeb88c211b4d5d1d51b7525 Mon Sep 17 00:00:00 2001 From: HC DEV <36608116+ArturMichalak@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:36:06 +0200 Subject: [PATCH] feat: renew resource (#72) * feat: renew resource * refactor(client/toggleEngine): to funcions * feat(config): skillcheck * feat(commands/giveKeys): remove redundant hasKeys checking * refactor(config/client): whitespaces * feat(shared): getIsVehicleInitiallyLocked * feat(client/doorlock): lock shared vehicle on driver leave * feat(client/hotwiring): gets vehicle keys if engine is running * Create da.json (#73) (#78) feat(locales): danish translation Co-authored-by: ARottenberger <69944020+iplayer1337fivem@users.noreply.github.com> * feat(locales): adapting da translation * feat(autolock): to leave the vehicle * feat(sendPoliceAlertAttempt): chance * feat(config): animations * feat(autolock): hotfix * feat(config/shared): restore * feat(server/lockOnCreate): lockNPCCars as chance * fix(client/carjack): progressActive in condition --------- Co-authored-by: ARottenberger <69944020+iplayer1337fivem@users.noreply.github.com> --- client/functions.lua | 111 +++++++++-------- client/main.lua | 267 ++++++++++++++++++++++------------------- config/client.lua | 275 ++++++++++++++++++++++++++++++++++++++++++- locales/en.json | 1 + 4 files changed, 480 insertions(+), 174 deletions(-) diff --git a/client/functions.lua b/client/functions.lua index bc58328..fc0f977 100644 --- a/client/functions.lua +++ b/client/functions.lua @@ -6,13 +6,20 @@ local getIsVehicleAlwaysUnlocked = functions.getIsVehicleAlwaysUnlocked local getIsVehicleLockpickImmune = functions.getIsVehicleLockpickImmune local getIsVehicleCarjackingImmune = functions.getIsVehicleCarjackingImmune local getIsVehicleTypeAlwaysUnlocked = functions.getIsVehicleTypeAlwaysUnlocked +local getIsVehicleTypeShared = functions.getIsVehicleTypeShared +local getIsVehicleShared = functions.getIsVehicleShared -local alertSend = false local public = {} public.getIsVehicleCarjackingImmune = getIsVehicleCarjackingImmune -- to prevent circular-dependency error -public.getIsVehicleLockpickImmune = getIsVehicleLockpickImmune public.getIsBlacklistedWeapon = getIsBlacklistedWeapon +public.getIsCloseToCoords = getIsCloseToCoords + +function public.getIsVehicleShared(vehicle) + return config.sharedVehicleClasses[GetVehicleClass(vehicle)] + or getIsVehicleTypeShared(vehicle) + or getIsVehicleShared(vehicle) +end ---Grants keys for job shared vehicles ---@param vehicle number The entity number of the vehicle. @@ -25,14 +32,7 @@ function public.areKeysJobShared(vehicle) assert(jobInfo.vehicles, string.format('Vehicles not configured for the %s job.', job)) - if not jobInfo.vehicles[GetEntityModel(vehicle)] then return end - - local vehPlate = qbx.getVehiclePlate(vehicle) - if not public.hasKeys(vehPlate) then - TriggerServerEvent('qb-vehiclekeys:server:AcquireVehicleKeys', vehPlate) - end - - return true + return jobInfo.vehicles[GetEntityModel(vehicle)] end ---Checks if player has vehicle keys @@ -57,10 +57,9 @@ end exports('HasAccess', public.getIsVehicleAccessible) function public.toggleEngine(vehicle) - local veh = vehicle or cache.vehicle - if not public.getIsVehicleAccessible(veh) then return end - local engineOn = GetIsVehicleEngineRunning(veh) - SetVehicleEngineOn(veh, not engineOn, false, true) + if not public.getIsVehicleAccessible(vehicle) then return end + local engineOn = GetIsVehicleEngineRunning(vehicle) + SetVehicleEngineOn(vehicle, not engineOn, false, true) end exports('ToggleEngine', public.toggleEngine) @@ -69,7 +68,8 @@ exports('ToggleEngine', public.toggleEngine) ---@param vehicle number The entity number of the vehicle. ---@return boolean? `true` if the vehicle is blacklisted, `nil` otherwise. function public.getIsVehicleAlwaysUnlocked(vehicle) - return getIsVehicleAlwaysUnlocked(vehicle) + return Entity(vehicle).state.ignoreLocks + or getIsVehicleAlwaysUnlocked(vehicle) or getIsVehicleTypeAlwaysUnlocked(vehicle) end @@ -113,23 +113,23 @@ function public.getVehicleInFront() end end +local alertSend = false --Variable strictly related to sendPoliceAlertAttempt, not used elsewhere function public.sendPoliceAlertAttempt(type) - if not alertSend then - alertSend = true - local chance = config.policeAlertChance + if alertSend then return end + alertSend = true - if GetClockHours() >= 1 and GetClockHours() <= 6 then - chance = config.policeNightAlertChance - end + local hoursOffset = (24 + GetClockHours() - config.policeAlertNightStartHour) % 24; --Hour from the start of the night hours + local chance = hoursOffset > config.policeAlertNightDuration + and config.policeAlertChance + or config.policeNightAlertChance - if math.random() <= chance then - TriggerServerEvent('police:server:policeAlert', locale("info.vehicle_theft") .. type) - end - - SetTimeout(config.alertCooldown, function() - alertSend = false - end) + if math.random() <= chance then + TriggerServerEvent('police:server:policeAlert', locale("info.vehicle_theft") .. type) end + + SetTimeout(config.alertCooldown, function() + alertSend = false + end) end ---Gets bone coords @@ -202,7 +202,6 @@ local function lockpickSuccessCallback(vehicle) TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) exports.qbx_core:Notify(locale("notify.vehicle_lockedpick"), 'success') TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), 1) - Entity(vehicle).state.isOpen = true end ---Operations done after the LockpickDoor quickevent done. @@ -235,36 +234,38 @@ function public.lockpickDoor(isAdvancedLockedpick, maxDistance, customChallenge) if not vehicle then return end - local class = GetVehicleClass(vehicle) - local plate = qbx.getVehiclePlate(vehicle) local isDriverSeatFree = IsVehicleSeatFree(vehicle, -1) - assert(plate, 'Vehicle has no plate') - --- player may attempt to open the lock if: if not isDriverSeatFree -- no one in the driver's seat - or public.hasKeys(plate) -- player does not have keys to the vehicle - or Entity(vehicle).state.isOpen -- the lock is locked or not getIsCloseToAnyBone(pedCoords, vehicle, doorBones, maxDistance) -- the player's ped is close enough to the driver's door or GetVehicleDoorLockStatus(vehicle) < 2 -- the vehicle is locked - or (not isAdvancedLockedpick and config.advancedLockpickVehicleClasses[class]) + or getIsVehicleLockpickImmune(vehicle) then return end - if islockpickingProcessLocked then return end -- start of the critical section + local skillCheckConfig = config.skillCheck[isAdvancedLockedpick and 'advancedLockpick' or 'lockpick'] + + skillCheckConfig = skillCheckConfig.model[GetEntityModel(vehicle)] + or skillCheckConfig.class[GetVehicleClass(vehicle)] + or skillCheckConfig.default + + if #skillCheckConfig == 0 or islockpickingProcessLocked then return end -- start of the critical section islockpickingProcessLocked = true -- one call per player at a time CreateThread(function() - lib.playAnim(cache.ped, 'veh@break_in@0h@p_m_one@', "low_force_entry_ds", 3.0, 3.0, -1, 16, 0, false, false, false) -- lock opening animation - local isSuccess = customChallenge or lib.skillCheck({ 'easy', 'easy', { areaSize = 60, speedMultiplier = 1 }, 'medium' }, { '1', '2', '3', '4' }) + local anim = config.anims.lockpick.model[GetEntityModel(vehicle)] + or config.anims.lockpick.model[GetVehicleClass(vehicle)] + or config.anims.lockpick.default + lib.playAnim(cache.ped, anim.dict, anim.clip, 3.0, 3.0, -1, 16, 0, false, false, false) -- lock opening animation + local isSuccess = customChallenge or lib.skillCheck(skillCheckConfig[1], skillCheckConfig[2]) if getIsVehicleInRange(vehicle, maxDistance) then -- the action will be aborted if the opened vehicle is too far. lockpickCallback(vehicle, isAdvancedLockedpick, isSuccess) end Wait(config.lockpickCooldown) + islockpickingProcessLocked = false -- end of the critical section end) - - islockpickingProcessLocked = false -- end of the critical section end ---Will be executed when the lock opening is successful. @@ -292,20 +293,32 @@ end local isHotwiringProcessLocked = false -- lock flag ---Hotwiring with a tool quickevent. +---@param vehicle number The entity number of the vehicle. ---@param isAdvancedLockedpick boolean Determines whether an advanced lockpick was used ---@param customChallenge boolean? lockpick challenge -function public.hotwire(isAdvancedLockedpick, customChallenge) - if cache.seat ~= -1 or isHotwiringProcessLocked then return end -- start of the critical section +function public.hotwire(vehicle, isAdvancedLockedpick, customChallenge) + if cache.seat ~= -1 or public.getIsVehicleAccessible(vehicle) then return end + local skillCheckConfig = config.skillCheck[isAdvancedLockedpick and 'advancedHotwire' or 'hotwire'] + + skillCheckConfig = skillCheckConfig.model[GetEntityModel(vehicle)] + or skillCheckConfig.class[GetVehicleClass(vehicle)] + or skillCheckConfig.default + + if #skillCheckConfig == 0 or isHotwiringProcessLocked then return end -- start of the critical section isHotwiringProcessLocked = true -- one call per player at a time CreateThread(function() - lib.playAnim(cache.ped, 'veh@break_in@0h@p_m_one@', "low_force_entry_ds", 3.0, 3.0, -1, 16, 0, false, false, false) -- lock opening animation - local isSuccess = customChallenge or lib.skillCheck({ 'easy', 'easy', { areaSize = 60, speedMultiplier = 1 }, 'medium' }, { '1', '2', '3', '4' }) - hotwireCallback(cache.vehicle, isAdvancedLockedpick, isSuccess) - Wait(config.lockpickCooldown) - end) + local anim = config.anims.hotwire.model[GetEntityModel(vehicle)] + or config.anims.hotwire.model[GetVehicleClass(vehicle)] + or config.anims.hotwire.default + lib.playAnim(cache.ped, anim.dict, anim.clip, 3.0, 3.0, -1, 16, 0, false, false, false) -- lock opening animation + local isSuccess = customChallenge or lib.skillCheck(skillCheckConfig[1], skillCheckConfig[2]) - isHotwiringProcessLocked = false -- end of the critical section + hotwireCallback(vehicle, isAdvancedLockedpick, isSuccess) + + Wait(config.hotwireCooldown) + isHotwiringProcessLocked = false -- end of the critical section + end) end return public diff --git a/client/main.lua b/client/main.lua index b476c6e..813c020 100644 --- a/client/main.lua +++ b/client/main.lua @@ -5,25 +5,20 @@ local config = require 'config.client' local functions = require 'client.functions' -local hasKeys = functions.hasKeys local hotwire = functions.hotwire local toggleEngine = functions.toggleEngine local lockpickDoor = functions.lockpickDoor +local areKeysJobShared = functions.areKeysJobShared local getVehicleInFront = functions.getVehicleInFront +local getIsCloseToCoords = functions.getIsCloseToCoords +local getIsVehicleShared = functions.getIsVehicleShared local getNPCPedsInVehicle = functions.getNPCPedsInVehicle local sendPoliceAlertAttempt = functions.sendPoliceAlertAttempt +local getIsVehicleAccessible = functions.getIsVehicleAccessible local getIsBlacklistedWeapon = functions.getIsBlacklistedWeapon local getIsVehicleAlwaysUnlocked = functions.getIsVehicleAlwaysUnlocked -local areKeysJobShared = functions.areKeysJobShared -local getIsVehicleLockpickImmune = functions.getIsVehicleLockpickImmune local getIsVehicleCarjackingImmune = functions.getIsVehicleCarjackingImmune ------------------------ ----- Variables ---- ------------------------ - -local isCarjackingAvailable = true - ----------------------- ---- Functions ---- ----------------------- @@ -33,57 +28,51 @@ local isCarjackingAvailable = true ---@param state boolean? State of the vehicle lock. ---@param anim any Aniation local function setVehicleDoorLock(vehicle, state, anim) - if not vehicle then return end - if not getIsVehicleAlwaysUnlocked(vehicle) then - if hasKeys(qbx.getVehiclePlate(vehicle)) or areKeysJobShared(vehicle) then + if not vehicle or getIsVehicleAlwaysUnlocked(vehicle) or getIsVehicleShared(vehicle) then return end + if getIsVehicleAccessible(vehicle) then - if anim then - lib.playAnim(cache.ped, 'anim@mp_player_intmenu@key_fob@', 'fob_click', 3.0, 3.0, -1, 49) - end - - StartVehicleHorn(vehicle, 50, `HELDDOWN`, false) - NetworkRequestControlOfEntity(vehicle) - - local lockstate - if state ~= nil then - lockstate = state and 2 or 1 - else - lockstate = (GetVehicleDoorLockStatus(vehicle) % 2) + 1 -- (1 % 2) + 1 -> 2 (2 % 2) + 1 -> 1 - end - - TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), lockstate) - exports.qbx_core:Notify(locale(lockstate == 2 and 'notify.vehicle_locked' or 'notify.vehicle_unlocked')) + if anim then + lib.playAnim(cache.ped, 'anim@mp_player_intmenu@key_fob@', 'fob_click', 3.0, 3.0, -1, 49) + end - SetVehicleLights(vehicle, 2) - Wait(250) - SetVehicleLights(vehicle, 1) - Wait(200) - SetVehicleLights(vehicle, 0) - Wait(300) - ClearPedTasks(cache.ped) + local lockstate + if state ~= nil then + lockstate = state and 2 or 1 else - exports.qbx_core:Notify(locale('notify.no_keys'), 'error') + lockstate = (GetVehicleDoorLockStatus(vehicle) % 2) + 1 -- (1 % 2) + 1 -> 2 (2 % 2) + 1 -> 1 end + + TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), lockstate) + exports.qbx_core:Notify(locale(lockstate == 2 and 'notify.vehicle_locked' or 'notify.vehicle_unlocked')) + + qbx.playAudio({ audioName = 'Door_Close', audioRef = 'GTAO_EXEC_WH_GARAGE_DOOR_SOUNDS', source = vehicle }) + SetVehicleLights(vehicle, 2) + Wait(250) + SetVehicleLights(vehicle, 1) + Wait(200) + SetVehicleLights(vehicle, 0) + Wait(300) + ClearPedTasks(cache.ped) else - TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), 1) + exports.qbx_core:Notify(locale('notify.no_keys'), 'error') end end exports('SetVehicleDoorLock', setVehicleDoorLock) -local function findKeys(vehicleClass, plate) +local function findKeys(vehicleModel, vehicleClass, plate) local hotwireTime = math.random(config.minKeysSearchTime, config.maxKeysSearchTime) + local anim = config.anims.lockpick.model[vehicleModel] + or config.anims.lockpick.model[vehicleClass] + or config.anims.lockpick.default if lib.progressCircle({ duration = hotwireTime, label = locale('progress.searching_keys'), position = 'bottom', useWhileDead = false, canCancel = true, - anim = { - dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', - clip = 'machinic_loop_mechandplayer' - }, + anim = anim, disable = { move = true, car = true, @@ -99,51 +88,54 @@ local function findKeys(vehicleClass, plate) end end +local isSearchAllowed = false +local function setSearchLabelState(isAllowed) + local isOpen, text = lib.isTextUIOpen() + local newText = locale('info.search_keys_dispatch') + local isValidMessage = text and text == newText + if isAllowed and not isValidMessage then + lib.showTextUI(newText) + elseif not isAllowed and isOpen and isValidMessage then + lib.hideTextUI() + end + + isSearchAllowed = isAllowed +end + local isShowHotwiringLabelRunning = false -local function showHotwiringLabel() - if isShowHotwiringLabelRunning then return end +local function showHotwiringLabel(vehicle) + if not (vehicle and DoesEntityExist(vehicle)) then return end + SetVehicleKeepEngineOnWhenAbandoned(vehicle, true) + if getIsVehicleShared(vehicle) + or isShowHotwiringLabelRunning then return end isShowHotwiringLabelRunning = true CreateThread(function() + local plate = qbx.getVehiclePlate(vehicle) + local isVehicleAccessible = getIsVehicleAccessible(vehicle, plate) -- Hotwiring while in vehicle, also keeps engine off for vehicles you don't own keys to - if cache.vehicle and not(getIsVehicleLockpickImmune(cache.vehicle) or getIsVehicleAlwaysUnlocked(cache.vehicle) or areKeysJobShared(cache.vehicle)) then - SetVehicleNeedsToBeHotwired(cache.vehicle, false) - SetVehicleKeepEngineOnWhenAbandoned(cache.vehicle, true) - local plate = qbx.getVehiclePlate(cache.vehicle) - local isSearchAllowed = true - while cache.vehicle and not hasKeys(plate) do - if cache.seat == -1 then + if not (isVehicleAccessible or cache.seat ~= -1) then + local isVehicleRunning = GetIsVehicleEngineRunning(vehicle) + if config.keepVehicleRunning and isVehicleRunning then + TriggerServerEvent('qb-vehiclekeys:server:AcquireVehicleKeys', qbx.getVehiclePlate(vehicle)) + else + SetVehicleNeedsToBeHotwired(vehicle, false) + setSearchLabelState(true) + while not isVehicleAccessible and cache.seat == -1 do SetVehicleEngineOn(cache.vehicle, false, true, true) - - if isSearchAllowed then - if IsControlJustPressed(0, 74) then - isSearchAllowed = false - CreateThread(function () - findKeys(GetVehicleClass(cache.vehicle), plate) - Wait(config.timeBetweenHotwires) - SetTimeout(10000, function() - sendPoliceAlertAttempt('steal') - end) - isSearchAllowed = true - end) - end - - qbx.drawText3d({ - text = locale('info.search_keys_dispatch'), - coords = GetOffsetFromEntityInWorldCoords(cache.vehicle, 0.0, 1.0, 0.5) - }) - end - Wait(0) - else - if lib.progressActive() then - lib.cancelProgress() - end - Wait(1000) + isVehicleAccessible = getIsVehicleAccessible(vehicle, plate) + end + + if lib.progressActive() then + lib.cancelProgress() end + + setSearchLabelState(false) end end + + isShowHotwiringLabelRunning = false end) - isShowHotwiringLabelRunning = false end local function makePedFlee(ped) @@ -152,8 +144,6 @@ local function makePedFlee(ped) end local function carjackVehicle(target) - if not isCarjackingAvailable then return end - isCarjackingAvailable = false local isCarjacking = true local vehicle = GetVehiclePedIsUsing(target) local occupants = getNPCPedsInVehicle(vehicle) @@ -168,13 +158,16 @@ local function carjackVehicle(target) for p = 1, #occupants do local occupant = occupants[p] CreateThread(function() - Wait(math.random(100, 600)) - lib.playAnim(occupant, 'mp_am_hold_up', 'holdup_victim_20s', 8.0, -8.0, -1, 49, 0, false, false, false) + Wait(math.random(100, 600)) --Random reaction time to increase realism + local anim = config.anims.holdup.model[GetEntityModel(vehicle)] + or config.anims.holdup.model[GetVehicleClass(vehicle)] + or config.anims.holdup.default + lib.playAnim(occupant, anim.dict, anim.clip, 8.0, -8.0, -1, 49, 0, false, false, false) PlayPain(occupant, 6, 0) end) end - -- Cancel progress bar if: Ped dies during robbery, car gets too far away + --Cancel progress bar if: Ped dies during robbery, car gets too far away CreateThread(function() while isCarjacking do local distance = #(GetEntityCoords(cache.ped) - GetEntityCoords(target)) @@ -225,55 +218,44 @@ local function carjackVehicle(target) makePedFlee(target) TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) end - isCarjacking = false Wait(2000) sendPoliceAlertAttempt('carjack') end else ClearPedTasks(target) makePedFlee(target) - isCarjacking = false end Wait(config.delayBetweenCarjackingsInMs) - isCarjackingAvailable = true + isCarjacking = false end -local isWatchCarjackingAttemptsRunning = false +local isWatchCarjackingAttemptRunning = false local function watchCarjackingAttempts() - if isWatchCarjackingAttemptsRunning then return end - isWatchCarjackingAttemptsRunning = true + if isWatchCarjackingAttemptRunning then return end + isWatchCarjackingAttemptRunning = true CreateThread(function() - while cache.weapon do - if isCarjackingAvailable then - local aiming, target = GetEntityPlayerIsFreeAimingAt(cache.playerId) - if aiming - and target - and target ~= 0 - and DoesEntityExist(target) - and IsPedInAnyVehicle(target, false) - and not IsEntityDead(target) - and not IsPedAPlayer(target) + while cache.weapon and not getIsBlacklistedWeapon(cache.weapon) do + local aiming, target = GetEntityPlayerIsFreeAimingAt(cache.playerId) + if aiming + and DoesEntityExist(target) + and IsPedInAnyVehicle(target, false) + and not IsEntityDead(target) + and not IsPedAPlayer(target) + then + local targetveh = GetVehiclePedIsIn(target, false) + + if not (GetPedInVehicleSeat(targetveh, -1) ~= target + or getIsVehicleCarjackingImmune(targetveh)) + and getIsCloseToCoords(GetEntityCoords(cache.ped), GetEntityCoords(target), 5.0) then - local targetveh = GetVehiclePedIsIn(target, false) - local isVehicleImmune = getIsVehicleCarjackingImmune(targetveh) - - if not(isVehicleImmune - or getIsBlacklistedWeapon(cache.weapon)) - and GetPedInVehicleSeat(targetveh, -1) == target - then - local pos = GetEntityCoords(cache.ped) - local targetpos = GetEntityCoords(target) - if #(pos - targetpos) < 5.0 and not isVehicleImmune then - carjackVehicle(target) - end - end + carjackVehicle(target) end end Wait(100) end + isWatchCarjackingAttemptRunning = false end) - isWatchCarjackingAttemptsRunning = false end ----------------------- @@ -301,12 +283,35 @@ engineBind = lib.addKeybind({ disabled = not cache.vehicle, onPressed = function() engineBind:disable(true) - toggleEngine() + toggleEngine(cache.vehicle) Wait(1000) engineBind:disable(false) end }) +lib.addKeybind({ + name = 'searchkeys', + description = locale('info.search_keys'), + defaultKey = 'H', + secondaryMapper = 'PAD_DIGITALBUTTONANY', + secondaryKey = 'LRIGHT_INDEX', + onPressed = function() + if isSearchAllowed and cache.vehicle then + setSearchLabelState(false) + local vehicle = cache.vehicle + local plate = qbx.getVehiclePlate(vehicle) + if not getIsVehicleAccessible(vehicle, plate) then + findKeys(GetEntityModel(vehicle), GetVehicleClass(vehicle), plate) + SetTimeout(10000, function() + sendPoliceAlertAttempt('steal') + end) + end + Wait(config.timeBetweenHotwires) + setSearchLabelState(true) + end + end +}) + ----------------------- ---- Client Events ---- ----------------------- @@ -338,8 +343,13 @@ RegisterNetEvent('QBCore:Client:VehicleInfo', function(data) end) RegisterNetEvent('lockpicks:UseLockpick', function(isAdvanced) - if cache.vehicle then - hotwire(isAdvanced) + local vehicle = cache.vehicle + if vehicle then + if isSearchAllowed then + setSearchLabelState(false) + hotwire(vehicle, isAdvanced) + setSearchLabelState(true) + end else lockpickDoor(isAdvanced) end @@ -347,17 +357,36 @@ end) RegisterNetEvent('qbx_vehiclekeys:client:OnLostKeys', function() Wait(0) - showHotwiringLabel() + showHotwiringLabel(cache.vehicle) end) AddEventHandler('ox_lib:cache:seat', function() - showHotwiringLabel() + showHotwiringLabel(cache.vehicle) end) AddEventHandler('ox_lib:cache:vehicle', function() - showHotwiringLabel() + showHotwiringLabel(cache.vehicle) end) +lib.onCache('vehicle', function (vehicle) ---for some reason the autolock works with this +end) + +for _, info in pairs(config.sharedKeys) do + if info.enableAutolock then + lib.onCache('vehicle', function (vehicle) + local leftVehicle = cache.vehicle + if not vehicle and leftVehicle then + local isShared = areKeysJobShared(leftVehicle) + local isAutolockEnabled = config.sharedKeys[QBX.PlayerData.job.name].enableAutolock + + if isShared and isAutolockEnabled then + TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(leftVehicle), 2) + end + end + end) + break; + end +end if config.carjackEnable then AddEventHandler('ox_lib:cache:weapon', function() @@ -368,7 +397,7 @@ end AddEventHandler('onResourceStart', function(resourceName) if (GetCurrentResourceName() ~= resourceName) then return end - showHotwiringLabel() + showHotwiringLabel(cache.vehicle) if config.carjackEnable then watchCarjackingAttempts() diff --git a/config/client.lua b/config/client.lua index 98a86c9..400eba4 100644 --- a/config/client.lua +++ b/config/client.lua @@ -39,10 +39,21 @@ WeaponTypeGroups = { MISC = 4257178988, } +EasyLockpickSkillCheck = { { 'easy', 'easy', { areaSize = 60, speedMultiplier = 1 }, 'medium' }, { '1', '2', '3' } } +NormalLockpickSkillCheck = { { 'easy', 'easy', { areaSize = 60, speedMultiplier = 1 }, 'medium' }, { '1', '2', '3', '4' } } +HardLockpickSkillCheck = { { 'easy', 'easy', { areaSize = 60, speedMultiplier = 2 }, 'medium' }, { '1', '2', '3', '4' } } + +DefaultHotwireAnim = { dict = 'anim@veh@plane@howard@front@ds@base', clip = 'hotwire' } +DefaultSearchKeysAnim = { dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', clip = 'machinic_loop_mechandplayer' } +DefaultLockpickAnim = { dict = 'anim@mp_player_intmenu@key_fob@', clip = 'fob_click' } +DefaultHoldupAnim = { dict = 'mp_am_hold_up', clip = 'holdup_victim_20s' } + return { vehicleMaximumLockingDistance = 5.0, -- Minimum distance for vehicle locking -- Lockpick Settings + keepVehicleRunning = true, + removeNormalLockpickChance = { -- Chance to remove lockpick on fail by vehicle class [VehicleClasses.COMPACTS] = 0.5, [VehicleClasses.SEDANS] = 0.5, @@ -94,11 +105,6 @@ return { [VehicleClasses.OPEN_WHEEL] = 0.5 }, - advancedLockpickVehicleClasses = { -- The vehicle classes can only be opened with an advanced lockpick - [VehicleClasses.HELICOPTERS] = true, - [VehicleClasses.MILITARY] = true - }, - -- Carjack Settings carjackEnable = true, -- Enables the ability to carjack pedestrian vehicles, stealing them by pointing a weapon at them carjackingTimeInMs = 7500, -- Time it takes to successfully carjack in miliseconds @@ -150,14 +156,17 @@ return { alertCooldown = 10000, -- Cooldown period in milliseconds (10 seconds) policeAlertChance = 0.75, -- Chance of alerting the police during the day policeNightAlertChance = 0.50, -- Chance of alerting the police at night (times: 01-06) + policeAlertNightStartHour = 1, + policeAlertNightDuration = 5, vehicleAlarmDuration = 10000, lockpickCooldown = 1000, - searchKeysCooldown = 1000, + hotwireCooldown = 1000, -- Job Settings sharedKeys = { -- Share keys amongst employees. Employees can lock/unlock any job-listed vehicle police = { -- Job name + enableAutolock = true, requireOnduty = false, vehicles = { [`police`] = true, -- Vehicle model @@ -174,5 +183,259 @@ return { sharedVehicleClasses = { [VehicleClasses.CYCLES] = true + }, + + skillCheck = { + lockpick = { + default = NormalLockpickSkillCheck, + class = { + [VehicleClasses.COMPACTS] = NormalLockpickSkillCheck, + [VehicleClasses.SEDANS] = NormalLockpickSkillCheck, + [VehicleClasses.SUVS] = NormalLockpickSkillCheck, + [VehicleClasses.COUPES] = NormalLockpickSkillCheck, + [VehicleClasses.COMPACTS] = NormalLockpickSkillCheck, + [VehicleClasses.SEDANS] = NormalLockpickSkillCheck, + [VehicleClasses.SUVS] = NormalLockpickSkillCheck, + [VehicleClasses.COUPES] = NormalLockpickSkillCheck, + [VehicleClasses.MUSCLE] = NormalLockpickSkillCheck, + [VehicleClasses.SPORTS_CLASSICS] = NormalLockpickSkillCheck, + [VehicleClasses.SPORTS] = NormalLockpickSkillCheck, + [VehicleClasses.SUPER] = NormalLockpickSkillCheck, + [VehicleClasses.MOTORCYCLES] = NormalLockpickSkillCheck, + [VehicleClasses.OFF_ROAD] = NormalLockpickSkillCheck, + [VehicleClasses.INDUSTRIAL] = NormalLockpickSkillCheck, + [VehicleClasses.UTILITY] = NormalLockpickSkillCheck, + [VehicleClasses.VANS] = NormalLockpickSkillCheck, + [VehicleClasses.BOATS] = NormalLockpickSkillCheck, + [VehicleClasses.HELICOPTERS] = {}, + [VehicleClasses.PLANES] = NormalLockpickSkillCheck, + [VehicleClasses.SERVICE] = NormalLockpickSkillCheck, + [VehicleClasses.EMERGENCY] = HardLockpickSkillCheck, + [VehicleClasses.MILITARY] = {}, -- The vehicle class can only be opened with an advanced lockpick + [VehicleClasses.COMMERCIAL] = NormalLockpickSkillCheck, + [VehicleClasses.TRAINS] = {}, + [VehicleClasses.OPEN_WHEEL] = EasyLockpickSkillCheck, + }, + model = { + [`zombiea`] = NormalLockpickSkillCheck + } + }, + advancedLockpick = { + default = EasyLockpickSkillCheck, + class = { + [VehicleClasses.COMPACTS] = EasyLockpickSkillCheck, + [VehicleClasses.SEDANS] = EasyLockpickSkillCheck, + [VehicleClasses.SUVS] = EasyLockpickSkillCheck, + [VehicleClasses.COUPES] = EasyLockpickSkillCheck, + [VehicleClasses.MUSCLE] = EasyLockpickSkillCheck, + [VehicleClasses.SPORTS_CLASSICS] = EasyLockpickSkillCheck, + [VehicleClasses.SPORTS] = EasyLockpickSkillCheck, + [VehicleClasses.SUPER] = EasyLockpickSkillCheck, + [VehicleClasses.MOTORCYCLES] = EasyLockpickSkillCheck, + [VehicleClasses.OFF_ROAD] = EasyLockpickSkillCheck, + [VehicleClasses.INDUSTRIAL] = EasyLockpickSkillCheck, + [VehicleClasses.UTILITY] = EasyLockpickSkillCheck, + [VehicleClasses.VANS] = EasyLockpickSkillCheck, + [VehicleClasses.BOATS] = EasyLockpickSkillCheck, + [VehicleClasses.HELICOPTERS] = HardLockpickSkillCheck, + [VehicleClasses.PLANES] = HardLockpickSkillCheck, + [VehicleClasses.SERVICE] = EasyLockpickSkillCheck, + [VehicleClasses.EMERGENCY] = EasyLockpickSkillCheck, + [VehicleClasses.MILITARY] = HardLockpickSkillCheck, + [VehicleClasses.COMMERCIAL] = EasyLockpickSkillCheck, + [VehicleClasses.TRAINS] = {}, -- The vehicle class can't be opened with an lockpick + [VehicleClasses.OPEN_WHEEL] = EasyLockpickSkillCheck, + }, + model = { + [`zombiea`] = EasyLockpickSkillCheck + } + }, + hotwire = { + default = NormalLockpickSkillCheck, + class = { + [VehicleClasses.COMPACTS] = NormalLockpickSkillCheck, + [VehicleClasses.SEDANS] = NormalLockpickSkillCheck, + [VehicleClasses.SUVS] = NormalLockpickSkillCheck, + [VehicleClasses.COUPES] = NormalLockpickSkillCheck, + [VehicleClasses.COMPACTS] = NormalLockpickSkillCheck, + [VehicleClasses.SEDANS] = NormalLockpickSkillCheck, + [VehicleClasses.SUVS] = NormalLockpickSkillCheck, + [VehicleClasses.COUPES] = NormalLockpickSkillCheck, + [VehicleClasses.MUSCLE] = NormalLockpickSkillCheck, + [VehicleClasses.SPORTS_CLASSICS] = NormalLockpickSkillCheck, + [VehicleClasses.SPORTS] = NormalLockpickSkillCheck, + [VehicleClasses.SUPER] = NormalLockpickSkillCheck, + [VehicleClasses.MOTORCYCLES] = NormalLockpickSkillCheck, + [VehicleClasses.OFF_ROAD] = NormalLockpickSkillCheck, + [VehicleClasses.INDUSTRIAL] = NormalLockpickSkillCheck, + [VehicleClasses.UTILITY] = NormalLockpickSkillCheck, + [VehicleClasses.VANS] = NormalLockpickSkillCheck, + [VehicleClasses.BOATS] = NormalLockpickSkillCheck, + [VehicleClasses.HELICOPTERS] = {}, + [VehicleClasses.PLANES] = NormalLockpickSkillCheck, + [VehicleClasses.SERVICE] = NormalLockpickSkillCheck, + [VehicleClasses.EMERGENCY] = HardLockpickSkillCheck, + [VehicleClasses.MILITARY] = {}, + [VehicleClasses.COMMERCIAL] = NormalLockpickSkillCheck, + [VehicleClasses.TRAINS] = {}, + [VehicleClasses.OPEN_WHEEL] = EasyLockpickSkillCheck, + }, + model = { + [`zombiea`] = NormalLockpickSkillCheck + } + }, + advancedHotwire = { + default = EasyLockpickSkillCheck, + class = { + [VehicleClasses.COMPACTS] = EasyLockpickSkillCheck, + [VehicleClasses.SEDANS] = EasyLockpickSkillCheck, + [VehicleClasses.SUVS] = EasyLockpickSkillCheck, + [VehicleClasses.COUPES] = EasyLockpickSkillCheck, + [VehicleClasses.MUSCLE] = EasyLockpickSkillCheck, + [VehicleClasses.SPORTS_CLASSICS] = EasyLockpickSkillCheck, + [VehicleClasses.SPORTS] = EasyLockpickSkillCheck, + [VehicleClasses.SUPER] = EasyLockpickSkillCheck, + [VehicleClasses.MOTORCYCLES] = EasyLockpickSkillCheck, + [VehicleClasses.OFF_ROAD] = EasyLockpickSkillCheck, + [VehicleClasses.INDUSTRIAL] = EasyLockpickSkillCheck, + [VehicleClasses.UTILITY] = EasyLockpickSkillCheck, + [VehicleClasses.VANS] = EasyLockpickSkillCheck, + [VehicleClasses.BOATS] = EasyLockpickSkillCheck, + [VehicleClasses.HELICOPTERS] = HardLockpickSkillCheck, + [VehicleClasses.PLANES] = HardLockpickSkillCheck, + [VehicleClasses.SERVICE] = EasyLockpickSkillCheck, + [VehicleClasses.EMERGENCY] = EasyLockpickSkillCheck, + [VehicleClasses.MILITARY] = HardLockpickSkillCheck, + [VehicleClasses.COMMERCIAL] = EasyLockpickSkillCheck, + [VehicleClasses.TRAINS] = {}, -- The vehicle class can't be hotwired + [VehicleClasses.OPEN_WHEEL] = EasyLockpickSkillCheck, + }, + model = { + [`zombiea`] = EasyLockpickSkillCheck + } + } + }, + + anims = { + hotwire = { + default = DefaultHotwireAnim, + class = { + [VehicleClasses.COMPACTS] = DefaultHotwireAnim, + [VehicleClasses.SEDANS] = DefaultHotwireAnim, + [VehicleClasses.SUVS] = DefaultHotwireAnim, + [VehicleClasses.COUPES] = DefaultHotwireAnim, + [VehicleClasses.MUSCLE] = DefaultHotwireAnim, + [VehicleClasses.SPORTS_CLASSICS] = DefaultHotwireAnim, + [VehicleClasses.SPORTS] = DefaultHotwireAnim, + [VehicleClasses.SUPER] = DefaultHotwireAnim, + [VehicleClasses.MOTORCYCLES] = DefaultHotwireAnim, + [VehicleClasses.OFF_ROAD] = DefaultHotwireAnim, + [VehicleClasses.INDUSTRIAL] = DefaultHotwireAnim, + [VehicleClasses.UTILITY] = DefaultHotwireAnim, + [VehicleClasses.VANS] = DefaultHotwireAnim, + [VehicleClasses.BOATS] = DefaultHotwireAnim, + [VehicleClasses.HELICOPTERS] = DefaultHotwireAnim, + [VehicleClasses.PLANES] = DefaultHotwireAnim, + [VehicleClasses.SERVICE] = DefaultHotwireAnim, + [VehicleClasses.EMERGENCY] = DefaultHotwireAnim, + [VehicleClasses.MILITARY] = DefaultHotwireAnim, + [VehicleClasses.COMMERCIAL] = DefaultHotwireAnim, + [VehicleClasses.TRAINS] = DefaultHotwireAnim, + [VehicleClasses.OPEN_WHEEL] = DefaultHotwireAnim, + }, + model = { + [`zombiea`] = DefaultHotwireAnim + } + }, + searchKeys = { + default = DefaultSearchKeysAnim, + class = { + [VehicleClasses.COMPACTS] = DefaultSearchKeysAnim, + [VehicleClasses.SEDANS] = DefaultSearchKeysAnim, + [VehicleClasses.SUVS] = DefaultSearchKeysAnim, + [VehicleClasses.COUPES] = DefaultSearchKeysAnim, + [VehicleClasses.MUSCLE] = DefaultSearchKeysAnim, + [VehicleClasses.SPORTS_CLASSICS] = DefaultSearchKeysAnim, + [VehicleClasses.SPORTS] = DefaultSearchKeysAnim, + [VehicleClasses.SUPER] = DefaultSearchKeysAnim, + [VehicleClasses.MOTORCYCLES] = DefaultSearchKeysAnim, + [VehicleClasses.OFF_ROAD] = DefaultSearchKeysAnim, + [VehicleClasses.INDUSTRIAL] = DefaultSearchKeysAnim, + [VehicleClasses.UTILITY] = DefaultSearchKeysAnim, + [VehicleClasses.VANS] = DefaultSearchKeysAnim, + [VehicleClasses.BOATS] = DefaultSearchKeysAnim, + [VehicleClasses.HELICOPTERS] = DefaultSearchKeysAnim, + [VehicleClasses.PLANES] = DefaultSearchKeysAnim, + [VehicleClasses.SERVICE] = DefaultSearchKeysAnim, + [VehicleClasses.EMERGENCY] = DefaultSearchKeysAnim, + [VehicleClasses.MILITARY] = DefaultSearchKeysAnim, + [VehicleClasses.COMMERCIAL] = DefaultSearchKeysAnim, + [VehicleClasses.TRAINS] = DefaultSearchKeysAnim, + [VehicleClasses.OPEN_WHEEL] = DefaultSearchKeysAnim, + }, + model = { + [`zombiea`] = DefaultSearchKeysAnim + } + }, + lockpick = { + default = DefaultLockpickAnim, + class = { + [VehicleClasses.COMPACTS] = DefaultLockpickAnim, + [VehicleClasses.SEDANS] = DefaultLockpickAnim, + [VehicleClasses.SUVS] = DefaultLockpickAnim, + [VehicleClasses.COUPES] = DefaultLockpickAnim, + [VehicleClasses.MUSCLE] = DefaultLockpickAnim, + [VehicleClasses.SPORTS_CLASSICS] = DefaultLockpickAnim, + [VehicleClasses.SPORTS] = DefaultLockpickAnim, + [VehicleClasses.SUPER] = DefaultLockpickAnim, + [VehicleClasses.MOTORCYCLES] = DefaultLockpickAnim, + [VehicleClasses.OFF_ROAD] = DefaultLockpickAnim, + [VehicleClasses.INDUSTRIAL] = DefaultLockpickAnim, + [VehicleClasses.UTILITY] = DefaultLockpickAnim, + [VehicleClasses.VANS] = DefaultLockpickAnim, + [VehicleClasses.BOATS] = DefaultLockpickAnim, + [VehicleClasses.HELICOPTERS] = DefaultLockpickAnim, + [VehicleClasses.PLANES] = DefaultLockpickAnim, + [VehicleClasses.SERVICE] = DefaultLockpickAnim, + [VehicleClasses.EMERGENCY] = DefaultLockpickAnim, + [VehicleClasses.MILITARY] = DefaultLockpickAnim, + [VehicleClasses.COMMERCIAL] = DefaultLockpickAnim, + [VehicleClasses.TRAINS] = DefaultLockpickAnim, + [VehicleClasses.OPEN_WHEEL] = DefaultLockpickAnim, + }, + model = { + [`zombiea`] = DefaultLockpickAnim + } + }, + holdup = { + default = DefaultHoldupAnim, + class = { + [VehicleClasses.COMPACTS] = DefaultHoldupAnim, + [VehicleClasses.SEDANS] = DefaultHoldupAnim, + [VehicleClasses.SUVS] = DefaultHoldupAnim, + [VehicleClasses.COUPES] = DefaultHoldupAnim, + [VehicleClasses.MUSCLE] = DefaultHoldupAnim, + [VehicleClasses.SPORTS_CLASSICS] = DefaultHoldupAnim, + [VehicleClasses.SPORTS] = DefaultHoldupAnim, + [VehicleClasses.SUPER] = DefaultHoldupAnim, + [VehicleClasses.MOTORCYCLES] = DefaultHoldupAnim, + [VehicleClasses.OFF_ROAD] = DefaultHoldupAnim, + [VehicleClasses.INDUSTRIAL] = DefaultHoldupAnim, + [VehicleClasses.UTILITY] = DefaultHoldupAnim, + [VehicleClasses.VANS] = DefaultHoldupAnim, + [VehicleClasses.BOATS] = DefaultHoldupAnim, + [VehicleClasses.HELICOPTERS] = DefaultHoldupAnim, + [VehicleClasses.PLANES] = DefaultHoldupAnim, + [VehicleClasses.SERVICE] = DefaultHoldupAnim, + [VehicleClasses.EMERGENCY] = DefaultHoldupAnim, + [VehicleClasses.MILITARY] = DefaultHoldupAnim, + [VehicleClasses.COMMERCIAL] = DefaultHoldupAnim, + [VehicleClasses.TRAINS] = DefaultHoldupAnim, + [VehicleClasses.OPEN_WHEEL] = DefaultHoldupAnim, + }, + model = { + [`zombiea`] = DefaultHoldupAnim + } + } } } diff --git a/locales/en.json b/locales/en.json index 04ce4fb..7bfe6e2 100644 --- a/locales/en.json +++ b/locales/en.json @@ -22,6 +22,7 @@ "info": { "engine": "Toggle Engine", "search_keys_dispatch": "[H] - Search for Keys", + "search_keys": "Search for vehicle keys", "toggle_locks": "Toggle Vehicle Locks", "vehicle_theft": "Vehicle theft in progress. Type: " },