Main/resources/[jobs]/[crime]/lation_247robbery/server/main.lua
2025-07-02 07:48:15 +02:00

324 lines
No EOL
13 KiB
Lua

-- Initialize config(s)
local shared = require 'config.shared'
local sv_config = require 'config.server'
-- Initialize global state for cooldowns
GlobalState.cooldown = false
GlobalState.started = false
-- Initialize proper coordinates
local gabz = GetResourceState('cfx-gabz-247') == 'started'
local fm = GetResourceState('cfx-fm-supermarkets') == 'started'
local stores = gabz and require 'data.gabz' or fm and require 'data.fmshop' or require 'data.default'
-- Initialize table to store known locations & robbery states
local locations, states = {}, {}
-- Builds local table containing all locations categorized
local function InitializeStores()
for type, coords in pairs(stores) do
for _, location in pairs(coords) do
if not locations[type:lower()] then locations[type:lower()] = {} end
locations[type:lower()][#locations[type:lower()] + 1] = location
end
end
end
-- Returns boolean if player is nearby defined coords based on location type
--- @param source number
--- @param location string registers, computers, safes
--- @return boolean
local function IsPlayerNearby(source, location)
if not source or not location then return false end
local playerPos = GetEntityCoords(GetPlayerPed(source))
for _, coords in pairs(locations[location]) do
if #(playerPos - coords) <= 2.5 then
return true
end
end
return false
end
-- Returns boolean if player can start robbery
--- @param identifier string
--- @return boolean
local function CanPlayerRob(identifier)
if not identifier then return false end
local currentTime = os.time()
if shared.setup.global.enable then
if GlobalState.cooldown or GlobalState.started then
return false
end
end
if not states[identifier] then return true end
local lastCompleted = states[identifier].completed
if lastCompleted then
if (currentTime - lastCompleted) < shared.setup.cooldown then
return false
end
end
return true
end
-- Starts & ends global cooldown if enabled
local function StartCooldown()
GlobalState.cooldown = true
local wait = math.floor(shared.setup.global.duration * 1000)
SetTimeout(wait, function()
GlobalState.cooldown = false
end)
end
-- Callback to initialize store robbery
--- @param source number
--- @return boolean
lib.callback.register('lation_247robbery:StartRobbery', function(source)
if not source then
EventLog('[main.lua]: lation_247robbery:StartRobbery: unable to retrieve source', 'error')
return false
end
local source = source
local identifier = GetIdentifier(source)
if not identifier then
EventLog('[main.lua]: lation_247robbery:StartRobbery: unable to retrieve player identifier', 'error')
return false
end
local isNearRegister = IsPlayerNearby(source, 'registers')
if not isNearRegister then
EventLog('[main.lua]: lation_247robbery:StartRobbery: player not nearby any registers', 'error')
return false
end
local hasRequiredItem = GetItemCount(source, shared.registers.item) >= 1
if not hasRequiredItem then
TriggerClientEvent('lation_247robbery:Notify', source, locale('notify.missing-item'), 'error')
EventLog('[main.lua]: lation_247robbery:StartRobbery: player missing required item', 'error')
return false
end
if shared.police.count > 0 then
local police = GetPoliceCount()
if not police or police < shared.police.count then
TriggerClientEvent('lation_247robbery:Notify', source, locale('notify.no-police'), 'error')
EventLog('[main.lua]: lation_247robbery:StartRobbery: not enough police to start robbery', 'error')
return false
end
end
if not CanPlayerRob(identifier) then
TriggerClientEvent('lation_247robbery:Notify', source, locale('notify.cooldown'), 'error')
EventLog('[main.lua]: lation_247robbery:StartRobbery: cooldown is still active (for player or global)', 'error')
return false
end
GlobalState.started = true
if not states[identifier] then states[identifier] = {} end
states[identifier].state = 'in_progress'
states[identifier].started = os.time()
-- Fallback to reset states if not completed in a reasonable amount of time
SetTimeout(600000, function() -- 10 minute timeout
if states[identifier] and states[identifier].state == 'in_progress' then
states[identifier] = nil
end
if GlobalState.started then
GlobalState.started = false
end
end)
return true
end)
-- Event to handle lockpick breaking chance
RegisterNetEvent('lation_247robbery:DoesLockpickBreak', function()
if not source then
EventLog('[main.lua]: lation_247robbery:DoesLockpickBreak: unable to retrieve source', 'error')
return
end
local source = source
local identifier = GetIdentifier(source)
if not identifier then
EventLog('[main.lua]: lation_247robbery:DoesLockpickBreak: unable to retrieve player identifier', 'error')
return
end
if not GlobalState.started then
EventLog('[main.lua]: lation_247robbery:RegisterIncomplete: global state wasnt initiated', 'error')
return
end
if not states[identifier] or states[identifier].state ~= 'in_progress' then
EventLog('[main.lua]: lation_247robbery:DoesLockpickBreak: robbery wasnt initiated for player', 'error')
return
end
local isNearRegister = IsPlayerNearby(source, 'registers')
if not isNearRegister then
EventLog('[main.lua]: lation_247robbery:DoesLockpickBreak: player not nearby any registers', 'error')
return
end
if math.random(100) <= shared.registers.breakChance then
RemoveItem(source, shared.registers.item, 1)
TriggerClientEvent('lation_247robbery:Notify', source, locale('notify.item-broke'), 'error')
end
if GlobalState.started then GlobalState.started = false end
end)
-- Event to handle robbery completion and rewards
RegisterNetEvent('lation_247robbery:CompleteRegisterRobbery', function()
if not source then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: unable to retrieve source', 'error')
return
end
local source = source
local identifier = GetIdentifier(source)
if not identifier then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: unable to retrieve player identifier', 'error')
return
end
local name = GetName(source)
if not name then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: unable to retrieve player name', 'error')
return
end
if not states[identifier] or states[identifier].state ~= 'in_progress' then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: robbery wasnt initiated for player', 'error')
return
end
if not GlobalState.started then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: global state wasnt initiated', 'error')
return
end
local isNearRegister = IsPlayerNearby(source, 'registers')
if not isNearRegister then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: player not nearby any registers', 'error')
return
end
local police = shared.police.risk and GetPoliceCount() or 0
local items = {}
for _, add in pairs(shared.registers.reward) do
if math.random(100) <= add.chance then
local quantity = math.random(add.min, add.max)
if police > 0 then
local increase = 1 + (police * shared.police.percent / 100)
quantity = math.floor(quantity * increase)
end
if add.metadata then
AddItem(source, add.item, quantity, add.metadata)
else
if add.item == 'cash' or add.item == 'money' or add.item == 'bank' then
AddMoney(source, add.item, quantity)
else
AddItem(source, add.item, quantity)
end
end
items[#items + 1] = { item = add.item, quantity = quantity }
end
end
local rewards = ''
for _, reward in ipairs(items) do
rewards = rewards .. 'x' .. reward.quantity .. ' ' ..reward.item .. ', '
end
rewards = rewards:sub(1, -3)
states[identifier].state = 'completed'
states[identifier].completed = os.time()
if sv_config.logs.events.register_robbed and #items > 0 then
---@diagnostic disable-next-line: undefined-field
PlayerLog(source, locale('logs.register-robbed-title'), locale('logs.register-robbed-message', name, identifier, rewards))
end
end)
-- Event to handle robbery completion and rewards
RegisterNetEvent('lation_247robbery:CompleteSafeRobbery', function()
if not source then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: unable to retrieve source', 'error')
return
end
local source = source
local identifier = GetIdentifier(source)
if not identifier then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: unable to retrieve player identifier', 'error')
return
end
local name = GetName(source)
if not name then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: unable to retrieve player name', 'error')
return
end
if not GlobalState.started then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: global state wasnt initiated', 'error')
return
end
if not states[identifier] or states[identifier].state ~= 'completed' then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: player has not completed the register robbery', 'error')
return
end
local isNearSafe = IsPlayerNearby(source, 'safes')
if not isNearSafe then
EventLog('[main.lua]: lation_247robbery:CompleteSafeRobbery: player not nearby any safes', 'error')
return
end
local police = shared.police.risk and GetPoliceCount() or 0
local items = {}
for _, add in pairs(shared.safes.reward) do
if math.random(100) <= add.chance then
local quantity = math.random(add.min, add.max)
if police > 0 then
local increase = 1 + (police * shared.police.percent / 100)
quantity = math.floor(quantity * increase)
end
if add.metadata then
AddItem(source, add.item, quantity, add.metadata)
else
if add.item == 'cash' or add.item == 'money' or add.item == 'bank' then
AddMoney(source, add.item, quantity)
else
AddItem(source, add.item, quantity)
end
end
items[#items + 1] = { item = add.item, quantity = quantity }
end
end
local rewards = ''
for _, reward in ipairs(items) do
rewards = rewards .. 'x' .. reward.quantity .. ' ' ..reward.item .. ', '
end
rewards = rewards:sub(1, -3)
GlobalState.started = false
states[identifier].state = nil
states[identifier].completed = os.time()
StartCooldown()
if sv_config.logs.events.safe_robbed and #items > 0 then
---@diagnostic disable-next-line: undefined-field
PlayerLog(source, locale('logs.safe-robbed-title'), locale('logs.safe-robbed-message', name, identifier, rewards))
end
end)
-- Event to handle failed robbery
RegisterNetEvent('lation_247robbery:FailedRobbery', function()
if not source then
EventLog('[main.lua]: lation_247robbery:FailedRobbery: unable to retrieve source', 'error')
return
end
local source = source
local identifier = GetIdentifier(source)
if not identifier then
EventLog('[main.lua]: lation_247robbery:FailedRobbery: unable to retrieve player identifier', 'error')
return
end
local name = GetName(source)
if not name then
EventLog('[main.lua]: lation_247robbery:FailedRobbery: unable to retrieve player name', 'error')
return
end
if not GlobalState.started then
EventLog('[main.lua]: lation_247robbery:FailedRobbery: global state wasnt initiated', 'error')
return
end
if not states[identifier] or states[identifier].state ~= 'completed' then
EventLog('[main.lua]: lation_247robbery:FailedRobbery: robbery wasnt initiated for player', 'error')
return
end
local isNearRegister = IsPlayerNearby(source, 'computers')
if not isNearRegister then
EventLog('[main.lua]: lation_247robbery:CompleteRegisterRobbery: player not nearby any registers', 'error')
return
end
GlobalState.started = false
states[identifier].state = nil
states[identifier].completed = os.time()
StartCooldown()
end)
InitializeStores()