diff --git a/client/carjack.lua b/client/carjack.lua new file mode 100644 index 0000000..a8760a9 --- /dev/null +++ b/client/carjack.lua @@ -0,0 +1,154 @@ +local config = require 'config.client' +local functions = require 'client.functions' +local sharedFunctions = require 'shared.functions' + +local sendPoliceAlertAttempt = functions.sendPoliceAlertAttempt + +local getIsCloseToCoords = sharedFunctions.getIsCloseToCoords +local getIsBlacklistedWeapon = sharedFunctions.getIsBlacklistedWeapon +local getIsVehicleCarjackingImmune = sharedFunctions.getIsVehicleCarjackingImmune + +local function getNPCPedsInVehicle(vehicle) + local otherPeds = {} + for seat = -1, GetVehicleModelNumberOfSeats(GetEntityModel(vehicle)) - 2 do + local pedInSeat = GetPedInVehicleSeat(vehicle, seat) + if pedInSeat ~= 0 and not IsPedAPlayer(pedInSeat) then + otherPeds[#otherPeds + 1] = pedInSeat + end + end + return otherPeds +end + +local function makePedFlee(ped) + ClearPedTasks(ped) + SetPedFleeAttributes(ped, 0, false) + TaskReactAndFleePed(ped, cache.ped) + TaskSmartFleePed(ped, cache.ped, 100.0, -1, false, false) + ResetPedLastVehicle(ped) -- make ped forget about his last car, so he cant return to it +end + +local function makePedsPutHandsUpAndScream(occupants, vehicle) + for p = 1, #occupants do + local occupant = occupants[p] + CreateThread(function() + 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 +end + +local function onCarjackSuccess(occupants, vehicle) + local plate = qbx.getVehiclePlate(vehicle) + for p = 1, #occupants do + local ped = occupants[p] + CreateThread(function() + TaskLeaveVehicle(ped, vehicle, 256) -- flag 256 to leave door open + PlayPain(ped, 6, 0) + Wait(1250) + PlayPain(ped, math.random(7, 8), 0) + makePedFlee(ped) + end) + end + TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) + TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), 1) + TriggerServerEvent('qb-vehiclekeys:server:AcquireVehicleKeys', plate) +end + +local function onCarjackFail(driver) + exports.qbx_core:Notify(locale('notify.carjack_failed'), 'error') + makePedFlee(driver) + TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) +end + +local function carjackVehicle(driver, vehicle) + local isCarjacking = true + local occupants = getNPCPedsInVehicle(vehicle) + + CreateThread(function() + while isCarjacking do + TaskVehicleTempAction(occupants[1], vehicle, 6, 1) + Wait(0) + end + end) + + makePedsPutHandsUpAndScream(occupants, vehicle) + + --Cancel progress bar if: Ped dies during robbery, car gets too far away + CreateThread(function() + while isCarjacking do + local distance = #(GetEntityCoords(cache.ped) - GetEntityCoords(driver)) + if (IsPedDeadOrDying(driver, false) or distance > 7.5) and lib.progressActive() then + lib.cancelProgress() + end + Wait(100) + end + end) + + if lib.progressCircle({ + duration = config.carjackingTimeInMs, + label = locale('progress.attempting_carjack'), + position = 'bottom', + useWhileDead = false, + canCancel = true, + disable = { + car = true, + }, + }) then + if cache.weapon and isCarjacking then + local carjackChance = config.carjackChance[GetWeapontypeGroup(cache.weapon) --[[@as string]]] or 0.5 + isCarjacking = false -- make this false to stop TaskVehicleTempAction from preventing ped to leave the car + + if math.random() <= carjackChance then + onCarjackSuccess(occupants, vehicle) + else + onCarjackFail(driver) + end + Wait(2000) + sendPoliceAlertAttempt('carjack') + end + else + makePedFlee(driver) + end + + Wait(config.delayBetweenCarjackingsInMs) + isCarjacking = false +end + +local isWatchCarjackingAttemptRunning = false +local function watchCarjackingAttempts() + if isWatchCarjackingAttemptRunning then return end + isWatchCarjackingAttemptRunning = true + CreateThread(function() + 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 GetPedInVehicleSeat(targetveh, -1) == target + and not getIsVehicleCarjackingImmune(targetveh) + and getIsCloseToCoords(GetEntityCoords(cache.ped), GetEntityCoords(target), 5.0) + then + carjackVehicle(target, targetveh) + end + end + Wait(100) + end + isWatchCarjackingAttemptRunning = false + end) +end + +if config.carjackEnable then + AddEventHandler('ox_lib:cache:weapon', function() + watchCarjackingAttempts() + end) + watchCarjackingAttempts() +end \ No newline at end of file diff --git a/client/functions.lua b/client/functions.lua index 6825c4c..e70ab4f 100644 --- a/client/functions.lua +++ b/client/functions.lua @@ -45,17 +45,6 @@ end exports('ToggleEngine', public.toggleEngine) -function public.getNPCPedsInVehicle(vehicle) - local otherPeds = {} - for seat = -1, GetVehicleModelNumberOfSeats(GetEntityModel(vehicle)) - 2 do - local pedInSeat = GetPedInVehicleSeat(vehicle, seat) - if pedInSeat ~= 0 and not IsPedAPlayer(pedInSeat) then - otherPeds[#otherPeds + 1] = pedInSeat - end - end - return otherPeds -end - local function getVehicleInDirection(coordFromOffset, coordToOffset) local coordFrom = GetOffsetFromEntityInWorldCoords(cache.ped, coordFromOffset.x, coordFromOffset.y, coordFromOffset.z) local coordTo = GetOffsetFromEntityInWorldCoords(cache.ped, coordToOffset.x, coordToOffset.y, coordToOffset.z) diff --git a/client/main.lua b/client/main.lua index e34a8f8..b9498a8 100644 --- a/client/main.lua +++ b/client/main.lua @@ -11,13 +11,10 @@ local toggleEngine = functions.toggleEngine local lockpickDoor = functions.lockpickDoor local areKeysJobShared = functions.areKeysJobShared local getVehicleInFront = functions.getVehicleInFront -local getNPCPedsInVehicle = functions.getNPCPedsInVehicle local sendPoliceAlertAttempt = functions.sendPoliceAlertAttempt local getIsVehicleAccessible = functions.getIsVehicleAccessible local getIsVehicleShared = sharedFunctions.getIsVehicleShared -local getIsCloseToCoords = sharedFunctions.getIsCloseToCoords -local getIsBlacklistedWeapon = sharedFunctions.getIsBlacklistedWeapon local getIsVehicleAlwaysUnlocked = sharedFunctions.getIsVehicleAlwaysUnlocked local getIsVehicleCarjackingImmune = sharedFunctions.getIsVehicleCarjackingImmune @@ -149,133 +146,6 @@ local function showHotwiringLabel(vehicle) end) end -local function makePedFlee(ped) - ClearPedTasks(ped) - SetPedFleeAttributes(ped, 0, false) - TaskReactAndFleePed(ped, cache.ped) - TaskSmartFleePed(ped, cache.ped, 100.0, -1, false, false) - ResetPedLastVehicle(ped) -- make ped forget about his last car, so he cant return to it -end - -local function makePedsPutHandsUpAndScream(occupants, vehicle) - for p = 1, #occupants do - local occupant = occupants[p] - CreateThread(function() - 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 -end - -local function onCarjackSuccess(occupants, vehicle) - local plate = qbx.getVehiclePlate(vehicle) - for p = 1, #occupants do - local ped = occupants[p] - CreateThread(function() - TaskLeaveVehicle(ped, vehicle, 256) -- flag 256 to leave door open - PlayPain(ped, 6, 0) - Wait(1250) - PlayPain(ped, math.random(7, 8), 0) - makePedFlee(ped) - end) - end - TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) - TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), 1) - TriggerServerEvent('qb-vehiclekeys:server:AcquireVehicleKeys', plate) -end - -local function onCarjackFail(driver) - exports.qbx_core:Notify(locale('notify.carjack_failed'), 'error') - makePedFlee(driver) - TriggerServerEvent('hud:server:GainStress', math.random(1, 4)) -end - -local function carjackVehicle(driver, vehicle) - local isCarjacking = true - local occupants = getNPCPedsInVehicle(vehicle) - - CreateThread(function() - while isCarjacking do - TaskVehicleTempAction(occupants[1], vehicle, 6, 1) - Wait(0) - end - end) - - makePedsPutHandsUpAndScream(occupants, vehicle) - - --Cancel progress bar if: Ped dies during robbery, car gets too far away - CreateThread(function() - while isCarjacking do - local distance = #(GetEntityCoords(cache.ped) - GetEntityCoords(driver)) - if (IsPedDeadOrDying(driver, false) or distance > 7.5) and lib.progressActive() then - lib.cancelProgress() - end - Wait(100) - end - end) - - if lib.progressCircle({ - duration = config.carjackingTimeInMs, - label = locale('progress.attempting_carjack'), - position = 'bottom', - useWhileDead = false, - canCancel = true, - disable = { - car = true, - }, - }) then - if cache.weapon and isCarjacking then - local carjackChance = config.carjackChance[GetWeapontypeGroup(cache.weapon) --[[@as string]]] or 0.5 - isCarjacking = false -- make this false to stop TaskVehicleTempAction from preventing ped to leave the car - - if math.random() <= carjackChance then - onCarjackSuccess(occupants, vehicle) - else - onCarjackFail(driver) - end - Wait(2000) - sendPoliceAlertAttempt('carjack') - end - else - makePedFlee(driver) - end - - Wait(config.delayBetweenCarjackingsInMs) - isCarjacking = false -end - -local isWatchCarjackingAttemptRunning = false -local function watchCarjackingAttempts() - if isWatchCarjackingAttemptRunning then return end - isWatchCarjackingAttemptRunning = true - CreateThread(function() - 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 GetPedInVehicleSeat(targetveh, -1) == target - and not getIsVehicleCarjackingImmune(targetveh) - and getIsCloseToCoords(GetEntityCoords(cache.ped), GetEntityCoords(target), 5.0) - then - carjackVehicle(target, targetveh) - end - end - Wait(100) - end - isWatchCarjackingAttemptRunning = false - end) -end - ----------------------- ------ Key Binds ------ ----------------------- @@ -410,12 +280,6 @@ for _, info in pairs(config.sharedKeys) do end end -if config.carjackEnable then - AddEventHandler('ox_lib:cache:weapon', function() - watchCarjackingAttempts() - end) -end - qbx.entityStateHandler('doorslockstate', function(entity, _, value) if entity == 0 then return end SetVehicleDoorsLocked(entity, value) @@ -425,10 +289,6 @@ AddEventHandler('onResourceStart', function(resourceName) if (GetCurrentResourceName() ~= resourceName) then return end showHotwiringLabel(cache.vehicle) - - if config.carjackEnable then - watchCarjackingAttempts() - end end) RegisterNetEvent('qb-vehiclekeys:client:GiveKeys', function(id, plate) diff --git a/fxmanifest.lua b/fxmanifest.lua index 03a0586..fe5b4f5 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -15,7 +15,8 @@ shared_scripts { client_scripts { '@qbx_core/modules/playerdata.lua', - 'client/main.lua' + 'client/main.lua', + 'client/carjack.lua', } server_scripts {