260 lines
9.0 KiB
Lua
260 lines
9.0 KiB
Lua
local config = require 'config.client'
|
|
local sharedConfig = require 'config.shared'
|
|
local houseLoot = {}
|
|
local house = 1
|
|
local ITEMS = exports.ox_inventory:Items()
|
|
|
|
local function dropFingerprint()
|
|
if qbx.isWearingGloves() then return end
|
|
|
|
local coords = GetEntityCoords(cache.ped)
|
|
if config.fingerprintChance > math.random(0, 100) then
|
|
TriggerServerEvent('evidence:server:CreateFingerDrop', coords)
|
|
end
|
|
end
|
|
|
|
-- Handle pickup of objects in an IPL. These are props that are part of the IPL
|
|
-- currentDistance is used because
|
|
---@param pickup CPoint Loot pickup point
|
|
local function handleHousePickup(pickup)
|
|
local pickupId = pickup.housePickup
|
|
if pickup.currentDistance < 0.8 and not sharedConfig.houses[house].pickups[pickupId].isOpened then
|
|
if config.showPrompts then
|
|
local rewardLabel = ITEMS[sharedConfig.houses[house].pickups[pickupId].reward]['label']
|
|
local label = locale('text.pickup', rewardLabel)
|
|
if config.useDrawText then
|
|
qbx.drawText3d({ text = label, coords = sharedConfig.houses[house].pickups[pickupId].coords })
|
|
elseif not lib.isTextUIOpen() then
|
|
lib.showTextUI(label, { position = 'left-center' })
|
|
end
|
|
end
|
|
if IsControlJustReleased(0, 38) then
|
|
dropFingerprint()
|
|
local canStart = lib.callback.await('qbx_houserobbery:server:checkPickup', false, house, pickupId)
|
|
if not canStart then return end
|
|
if lib.progressCircle({
|
|
duration = math.random(4000, 8000),
|
|
position = 'bottom',
|
|
canCancel = true,
|
|
disable = {
|
|
move = true,
|
|
combat = true,
|
|
},
|
|
anim = {
|
|
dict = 'missexile3',
|
|
clip = 'ex03_dingy_search_case_base_michael',
|
|
flag = 1,
|
|
blendIn = 1.0
|
|
},
|
|
}) then
|
|
TriggerServerEvent('qbx_houserobbery:server:pickupFinished', house, pickupId)
|
|
else
|
|
TriggerServerEvent('qbx_houserobbery:server:pickupCancelled', house, pickupId)
|
|
end
|
|
end
|
|
elseif sharedConfig.houses[house].pickups[pickupId].isOpened then
|
|
local pickupProp = sharedConfig.houses[house].pickups[pickupId]
|
|
local entity = GetClosestObjectOfType(pickup.coords.x, pickup.coords.y, pickup.coords.z, 3.0, joaat(pickupProp.prop), false, false, false)
|
|
if DoesEntityExist(entity) then
|
|
SetEntityVisible(entity, false, false)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Function for handling loot pickup and display inside interiors.
|
|
---@param lootId number Index number for loot point
|
|
local function handleHouseLoot(lootId)
|
|
if not sharedConfig.houses[house].opened then return end
|
|
if not sharedConfig.houses[house].loot[lootId].isOpened then
|
|
local label = locale('text.search')
|
|
if config.useDrawText then
|
|
qbx.drawText3d({ text = label, coords = sharedConfig.houses[house].loot[lootId].coords })
|
|
elseif not lib.isTextUIOpen() then
|
|
lib.showTextUI(locale('text.search'), { position = 'left-center' })
|
|
end
|
|
if IsControlJustReleased(0, 38) then
|
|
dropFingerprint()
|
|
local canStart = lib.callback.await('qbx_houserobbery:server:checkLoot', false, house, lootId)
|
|
if not canStart then return end
|
|
if lib.progressCircle({
|
|
duration = math.random(4000, 8000),
|
|
position = 'bottom',
|
|
canCancel = true,
|
|
disable = {
|
|
move = true,
|
|
combat = true,
|
|
},
|
|
anim = {
|
|
dict = 'missexile3',
|
|
clip = 'ex03_dingy_search_case_base_michael',
|
|
flag = 1,
|
|
blendIn = 1.0
|
|
},
|
|
}) then
|
|
TriggerServerEvent('qbx_houserobbery:server:lootFinished', house, lootId)
|
|
else
|
|
TriggerServerEvent('qbx_houserobbery:server:lootCancelled', house, lootId)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Setup loot on entrance since we reuse ipl interiors
|
|
local function setupLoot()
|
|
for k, v in pairs(sharedConfig.houses[house].loot) do
|
|
local point = lib.points.new({
|
|
coords = v.coords.xyz,
|
|
distance = 0.8,
|
|
houseLoot = k
|
|
})
|
|
function point:onExit()
|
|
lib.hideTextUI()
|
|
end
|
|
|
|
function point:nearby()
|
|
handleHouseLoot(self.houseLoot)
|
|
end
|
|
|
|
houseLoot[#houseLoot + 1] = point
|
|
end
|
|
for k, v in pairs(sharedConfig.houses[house].pickups) do
|
|
local point = lib.points.new({
|
|
coords = v.coords.xyz,
|
|
distance = 30,
|
|
housePickup = k
|
|
})
|
|
function point:onExit()
|
|
lib.hideTextUI()
|
|
end
|
|
|
|
function point:nearby()
|
|
handleHousePickup(self)
|
|
end
|
|
houseLoot[#houseLoot + 1] = point
|
|
end
|
|
end
|
|
|
|
-- Removes loot from interiors on exit and unload
|
|
local function removeLoot()
|
|
for _, v in pairs(houseLoot) do
|
|
v:remove()
|
|
end
|
|
end
|
|
|
|
-- Handles showing house entrance text and processing entrance for opened houses
|
|
---@param houseId CPoint
|
|
local function handleHouseEntrance(houseId)
|
|
local id = houseId.id
|
|
local isOpen = sharedConfig.houses[id].opened
|
|
if isOpen then
|
|
if IsControlJustReleased(0, 38) then
|
|
lib.playAnim(cache.ped, 'anim@heists@keycard@', 'exit', 5.0, 1.0, -1, 16, 0, false, false, false)
|
|
house = houseId.id
|
|
TriggerServerEvent('qbx_houserobbery:server:enterHouse', houseId.id)
|
|
end
|
|
end
|
|
local displayMessage = isOpen and locale('text.enter_house') or locale('text.enter_requirements')
|
|
if config.useDrawText then
|
|
qbx.drawText3d({ text = displayMessage, coords = houseId.coords })
|
|
elseif not lib.isTextUIOpen() then
|
|
lib.showTextUI(displayMessage, { position = 'left-center' })
|
|
end
|
|
end
|
|
|
|
-- Handles showing house exit text and processing exit
|
|
---@param interiorId CPoint
|
|
local function handleHouseExits(interiorId)
|
|
|
|
local label = locale('text.leave_house')
|
|
if config.useDrawText then
|
|
qbx.drawText3d({ text = label, coords = interiorId.coords })
|
|
elseif not lib.isTextUIOpen() then
|
|
lib.showTextUI(label, { position = 'left-center' })
|
|
end
|
|
if IsControlJustReleased(0, 38) then
|
|
lib.playAnim(cache.ped, 'anim@heists@keycard@', 'exit', 5.0, 1.0, -1, 16, 0, false, false, false)
|
|
TriggerServerEvent('qbx_houserobbery:server:leaveHouse')
|
|
removeLoot()
|
|
end
|
|
end
|
|
|
|
-- Setup house entrance and exit points using ox_lib points
|
|
local function setupHouses()
|
|
for i = 1, #sharedConfig.houses do
|
|
local point = lib.points.new({
|
|
id = i,
|
|
coords = sharedConfig.houses[i].coords.xyz,
|
|
distance = config.debugPoints and 50 or 1.6,
|
|
interior = sharedConfig.houses[i].interior
|
|
})
|
|
function point:onEnter()
|
|
house = self.id
|
|
end
|
|
|
|
function point:onExit()
|
|
lib.hideTextUI()
|
|
end
|
|
|
|
function point:nearby()
|
|
handleHouseEntrance(self)
|
|
end
|
|
end
|
|
for i = 1, #sharedConfig.interiors do
|
|
local point = lib.points.new({
|
|
id = i,
|
|
coords = sharedConfig.interiors[i].exit.xyz,
|
|
distance = 1.6,
|
|
})
|
|
function point:onExit()
|
|
lib.hideTextUI()
|
|
end
|
|
|
|
function point:nearby()
|
|
handleHouseExits(self)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
---@param difficulty SkillCheckDifficulity[] Ox_lib skillcheck difficulty table
|
|
lib.callback.register('qbx_houserobbery:client:startSkillcheck', function(difficulty)
|
|
lib.playAnim(cache.ped, 'veh@break_in@0h@p_m_one@', 'std_force_entry_rds', 3.0, 3.0, -1, 17, 0, false, false, false)
|
|
local success = lib.skillCheck(difficulty)
|
|
ClearPedTasks(cache.ped)
|
|
return success
|
|
end)
|
|
|
|
lib.callback.register('qbx_houserobbery:client:checkTime', function()
|
|
local currentHour = GetClockHours()
|
|
return currentHour >= config.startHours or currentHour <= config.endHours
|
|
end)
|
|
|
|
RegisterNetEvent('qbx_houserobbery:client:enterHouse', setupLoot)
|
|
|
|
---@param data table Table of loot data for houses
|
|
---@param index number Used to sync just a specific house number
|
|
RegisterNetEvent('qbx_houserobbery:client:syncconfig', function(data, index)
|
|
if index then
|
|
sharedConfig.houses[index] = data
|
|
else
|
|
sharedConfig.houses = data
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
|
setupHouses()
|
|
end)
|
|
|
|
-- Remove all points created by script to prevent duplicate points
|
|
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
|
|
for _, v in pairs(lib.points.getAllPoints()) do
|
|
v:remove()
|
|
end
|
|
end)
|
|
|
|
AddEventHandler('onResourceStart', function(resource)
|
|
if GetCurrentResourceName() ~= resource then return end
|
|
|
|
setupHouses()
|
|
end)
|