forked from Simnation/Main
ed
This commit is contained in:
parent
30e6c02a2f
commit
515271cff0
4 changed files with 684 additions and 0 deletions
308
resources/[jobs]/[crime]/nordi_containerheist/client/main.lua
Normal file
308
resources/[jobs]/[crime]/nordi_containerheist/client/main.lua
Normal file
|
@ -0,0 +1,308 @@
|
|||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
local containerCooldowns = {}
|
||||
local isRobbing = false
|
||||
local currentContainer = nil
|
||||
local containerBlip = nil
|
||||
|
||||
-- Debug function
|
||||
local function Debug(msg)
|
||||
if Config.Debug then
|
||||
print("[Container Heist] " .. msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Function to check if player is near a valid container
|
||||
local function IsNearValidContainer()
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
|
||||
-- Check for containers in the area
|
||||
local objects = GetGamePool('CObject')
|
||||
for _, object in ipairs(objects) do
|
||||
if DoesEntityExist(object) and not IsEntityDead(object) then
|
||||
local model = GetEntityModel(object)
|
||||
local objectCoords = GetEntityCoords(object)
|
||||
local distance = #(playerCoords - objectCoords)
|
||||
|
||||
if distance <= 5.0 then
|
||||
for _, containerType in pairs(Config.ContainerTypes) do
|
||||
if model == GetHashKey(containerType.model) then
|
||||
return object, containerType
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for trailers in the area
|
||||
local vehicles = GetGamePool('CVehicle')
|
||||
for _, vehicle in ipairs(vehicles) do
|
||||
if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then
|
||||
local model = GetEntityModel(vehicle)
|
||||
local vehicleCoords = GetEntityCoords(vehicle)
|
||||
local distance = #(playerCoords - vehicleCoords)
|
||||
|
||||
if distance <= 5.0 then
|
||||
for _, containerType in pairs(Config.ContainerTypes) do
|
||||
if model == GetHashKey(containerType.model) then
|
||||
return vehicle, containerType
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
-- Function to create a blip at the robbery location
|
||||
local function CreateRobberyBlip(coords)
|
||||
if containerBlip then
|
||||
RemoveBlip(containerBlip)
|
||||
end
|
||||
|
||||
containerBlip = AddBlipForCoord(coords)
|
||||
SetBlipSprite(containerBlip, Config.Blip.sprite)
|
||||
SetBlipColour(containerBlip, Config.Blip.color)
|
||||
SetBlipScale(containerBlip, Config.Blip.scale)
|
||||
SetBlipAsShortRange(containerBlip, true)
|
||||
BeginTextCommandSetBlipName("STRING")
|
||||
AddTextComponentString(Config.Blip.label)
|
||||
EndTextCommandSetBlipName(containerBlip)
|
||||
|
||||
if Config.Blip.flash then
|
||||
SetBlipFlashes(containerBlip, true)
|
||||
end
|
||||
|
||||
-- Remove blip after duration
|
||||
SetTimeout(Config.Blip.duration * 1000, function()
|
||||
if containerBlip then
|
||||
RemoveBlip(containerBlip)
|
||||
containerBlip = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Function to play container robbery animation
|
||||
local function PlayRobberyAnimation(containerType)
|
||||
local playerPed = PlayerPedId()
|
||||
local animDict = containerType.animation.dict
|
||||
local animName = containerType.animation.name
|
||||
|
||||
RequestAnimDict(animDict)
|
||||
while not HasAnimDictLoaded(animDict) do
|
||||
Wait(10)
|
||||
end
|
||||
|
||||
TaskPlayAnim(playerPed, animDict, animName, 8.0, -8.0, containerType.animation.duration, containerType.animation.flag, 0, false, false, false)
|
||||
|
||||
-- Add particle effects for welding
|
||||
local boneIndex = GetPedBoneIndex(playerPed, 28422)
|
||||
local particleDict = "core"
|
||||
local particleName = "ent_amb_welding"
|
||||
|
||||
RequestNamedPtfxAsset(particleDict)
|
||||
while not HasNamedPtfxAssetLoaded(particleDict) do
|
||||
Wait(10)
|
||||
end
|
||||
|
||||
UseParticleFxAssetNextCall(particleDict)
|
||||
local particleHandle = StartParticleFxLoopedOnPedBone(particleName, playerPed, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, boneIndex, 0.5, false, false, false)
|
||||
|
||||
-- Clean up after animation
|
||||
SetTimeout(containerType.animation.duration, function()
|
||||
StopParticleFxLooped(particleHandle, 0)
|
||||
StopAnimTask(playerPed, animDict, animName, 1.0)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Function to start container robbery
|
||||
local function StartContainerRobbery(container, containerType)
|
||||
if isRobbing then return end
|
||||
|
||||
isRobbing = true
|
||||
currentContainer = container
|
||||
|
||||
-- Check if player has required tools
|
||||
local hasTools = lib.callback.await('container_heist:server:checkRequiredItems', false)
|
||||
if not hasTools then
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = Config.Notifications.noTools,
|
||||
type = 'error'
|
||||
})
|
||||
isRobbing = false
|
||||
currentContainer = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Check cooldowns
|
||||
local cooldownCheck = lib.callback.await('container_heist:server:checkCooldown', false, NetworkGetNetworkIdFromEntity(container))
|
||||
if not cooldownCheck.success then
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = cooldownCheck.message,
|
||||
type = 'error'
|
||||
})
|
||||
isRobbing = false
|
||||
currentContainer = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Check police count
|
||||
local policeCount = lib.callback.await('container_heist:server:getPoliceCount', false)
|
||||
if policeCount < Config.PoliceRequired then
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = Config.Notifications.notEnoughPolice,
|
||||
type = 'error'
|
||||
})
|
||||
isRobbing = false
|
||||
currentContainer = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Position player for animation
|
||||
local containerCoords = GetEntityCoords(container)
|
||||
local containerHeading = GetEntityHeading(container)
|
||||
local offsetCoords = GetOffsetFromEntityInWorldCoords(container, containerType.offset.x, containerType.offset.y, containerType.offset.z)
|
||||
|
||||
-- Set player position and heading
|
||||
SetEntityCoords(PlayerPedId(), offsetCoords.x, offsetCoords.y, offsetCoords.z)
|
||||
SetEntityHeading(PlayerPedId(), containerHeading + containerType.heading)
|
||||
|
||||
-- Alert police if configured
|
||||
if containerType.policeAlert then
|
||||
local streetName = GetStreetNameFromHashKey(GetStreetNameAtCoord(containerCoords.x, containerCoords.y, containerCoords.z))
|
||||
TriggerServerEvent('container_heist:server:alertPolice', containerCoords, streetName, containerType.label)
|
||||
end
|
||||
|
||||
-- Start robbery progress bar
|
||||
PlayRobberyAnimation(containerType)
|
||||
|
||||
if lib.progressBar({
|
||||
duration = containerType.animation.duration,
|
||||
label = 'Breaking into ' .. containerType.label,
|
||||
useWhileDead = false,
|
||||
canCancel = true,
|
||||
disable = {
|
||||
car = true,
|
||||
move = true,
|
||||
combat = true,
|
||||
},
|
||||
anim = {
|
||||
dict = containerType.animation.dict,
|
||||
clip = containerType.animation.name,
|
||||
},
|
||||
}) then
|
||||
-- Success
|
||||
TriggerServerEvent('container_heist:server:finishRobbery', NetworkGetNetworkIdFromEntity(container), containerType.type)
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = Config.Notifications.success,
|
||||
type = 'success'
|
||||
})
|
||||
else
|
||||
-- Cancelled
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = Config.Notifications.failed,
|
||||
type = 'error'
|
||||
})
|
||||
end
|
||||
|
||||
isRobbing = false
|
||||
currentContainer = nil
|
||||
end
|
||||
|
||||
-- Command to start container robbery
|
||||
RegisterCommand('robcontainer', function()
|
||||
local container, containerType = IsNearValidContainer()
|
||||
if container and containerType then
|
||||
StartContainerRobbery(container, containerType)
|
||||
else
|
||||
lib.notify({
|
||||
title = Config.Notifications.title,
|
||||
description = "No valid container nearby!",
|
||||
type = 'error'
|
||||
})
|
||||
end
|
||||
end, false)
|
||||
|
||||
-- Setup target interactions for containers
|
||||
CreateThread(function()
|
||||
-- Wait for target system to be ready
|
||||
Wait(1000)
|
||||
|
||||
-- Add target for all container types
|
||||
for _, containerType in pairs(Config.ContainerTypes) do
|
||||
exports['qb-target']:AddTargetModel(containerType.model, {
|
||||
options = {
|
||||
{
|
||||
type = "client",
|
||||
event = "container_heist:client:startRobbery",
|
||||
icon = "fas fa-angle-double-right",
|
||||
label = "Break into " .. containerType.label,
|
||||
containerType = containerType,
|
||||
}
|
||||
},
|
||||
distance = 3.0
|
||||
})
|
||||
end
|
||||
|
||||
-- Spawn containers at fixed locations if configured
|
||||
for _, location in pairs(Config.ContainerLocations) do
|
||||
if location.spawnContainer then
|
||||
local hash = GetHashKey(location.model)
|
||||
RequestModel(hash)
|
||||
while not HasModelLoaded(hash) do
|
||||
Wait(10)
|
||||
end
|
||||
|
||||
local container = CreateObject(hash, location.coords.x, location.coords.y, location.coords.z, true, false, false)
|
||||
SetEntityHeading(container, location.heading)
|
||||
FreezeEntityPosition(container, true)
|
||||
SetModelAsNoLongerNeeded(hash)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Event handler for target interaction
|
||||
RegisterNetEvent('container_heist:client:startRobbery', function(data)
|
||||
local container, _ = IsNearValidContainer()
|
||||
if container then
|
||||
StartContainerRobbery(container, data.containerType)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Event to show police alert
|
||||
RegisterNetEvent('container_heist:client:policeAlert', function(coords, streetName, containerType)
|
||||
-- Create alert for police officers
|
||||
lib.notify({
|
||||
title = Config.Notifications.policeTitle,
|
||||
description = string.format(Config.Notifications.policeMessage, streetName),
|
||||
type = 'inform',
|
||||
position = 'top',
|
||||
icon = 'fas fa-exclamation-triangle',
|
||||
iconColor = '#ff0000'
|
||||
})
|
||||
|
||||
-- Add blip to map
|
||||
CreateRobberyBlip(coords)
|
||||
|
||||
-- Play alert sound
|
||||
PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1)
|
||||
end)
|
||||
|
||||
-- Clean up on resource stop
|
||||
AddEventHandler('onResourceStop', function(resourceName)
|
||||
if resourceName == GetCurrentResourceName() then
|
||||
if containerBlip then
|
||||
RemoveBlip(containerBlip)
|
||||
end
|
||||
|
||||
if isRobbing and currentContainer then
|
||||
StopAnimTask(PlayerPedId(), "amb@world_human_welding@male@base", "base", 1.0)
|
||||
end
|
||||
end
|
||||
end)
|
155
resources/[jobs]/[crime]/nordi_containerheist/config.lua
Normal file
155
resources/[jobs]/[crime]/nordi_containerheist/config.lua
Normal file
|
@ -0,0 +1,155 @@
|
|||
Config = {}
|
||||
|
||||
-- General Settings
|
||||
Config.Debug = false -- Set to true for debug prints
|
||||
Config.CooldownTime = 30 -- Minutes between heists (per player)
|
||||
Config.GlobalCooldown = 15 -- Minutes between heists (server-wide)
|
||||
Config.PoliceRequired = 1 -- Minimum police required
|
||||
Config.PoliceJobName = "police" -- Police job name
|
||||
|
||||
-- Required Items
|
||||
Config.RequiredItems = {
|
||||
flex = {
|
||||
name = "angle_grinder", -- Item name in your inventory
|
||||
label = "Angle Grinder", -- Display name
|
||||
amount = 1, -- How many required
|
||||
remove = false, -- Whether to remove the item after use
|
||||
durability = false, -- Whether the item has durability
|
||||
durabilityDecrease = 20, -- How much durability to decrease per use (%)
|
||||
},
|
||||
-- You can add more required items here
|
||||
}
|
||||
|
||||
-- Notification Settings
|
||||
Config.Notifications = {
|
||||
title = "Container Heist",
|
||||
policeTitle = "DISPATCH ALERT",
|
||||
success = "You successfully broke into the container!",
|
||||
failed = "You failed to break into the container!",
|
||||
noTools = "You don't have the required tools!",
|
||||
cooldown = "You need to wait before attempting another heist!",
|
||||
globalCooldown = "This type of heist is currently on cooldown!",
|
||||
notEnoughPolice = "Not enough police in the city!",
|
||||
policeMessage = "Container robbery in progress at %s",
|
||||
alreadyRobbed = "This container has already been robbed recently!",
|
||||
}
|
||||
|
||||
-- Blip Settings
|
||||
Config.Blip = {
|
||||
sprite = 67,
|
||||
color = 1,
|
||||
scale = 0.8,
|
||||
label = "Container Robbery",
|
||||
duration = 180, -- seconds
|
||||
flash = true,
|
||||
}
|
||||
|
||||
-- Container Types
|
||||
Config.ContainerTypes = {
|
||||
-- Regular shipping containers
|
||||
{
|
||||
model = "prop_container_01a", -- Container model
|
||||
type = "shipping",
|
||||
label = "Shipping Container",
|
||||
offset = vector3(0.0, -4.0, 0.0), -- Player position offset for interaction
|
||||
heading = 180.0, -- Player heading for interaction
|
||||
animation = {
|
||||
dict = "amb@world_human_welding@male@base",
|
||||
name = "base",
|
||||
flag = 1,
|
||||
duration = 30000, -- milliseconds
|
||||
},
|
||||
rewards = {
|
||||
-- Each reward has a chance (total should be <= 100)
|
||||
{item = "phone", label = "Phone", min = 1, max = 3, chance = 30},
|
||||
{item = "rolex", label = "Rolex Watch", min = 1, max = 2, chance = 20},
|
||||
{item = "goldchain", label = "Gold Chain", min = 1, max = 3, chance = 25},
|
||||
{item = "diamond", label = "Diamond", min = 1, max = 1, chance = 5},
|
||||
{item = "laptop", label = "Laptop", min = 1, max = 1, chance = 15},
|
||||
-- Cash reward
|
||||
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
|
||||
},
|
||||
policeAlert = true,
|
||||
},
|
||||
{
|
||||
model = "prop_container_01b",
|
||||
type = "shipping",
|
||||
label = "Shipping Container",
|
||||
offset = vector3(0.0, -4.0, 0.0),
|
||||
heading = 180.0,
|
||||
animation = {
|
||||
dict = "amb@world_human_welding@male@base",
|
||||
name = "base",
|
||||
flag = 1,
|
||||
duration = 30000,
|
||||
},
|
||||
rewards = {
|
||||
{item = "weapon_pistol", label = "Pistol", min = 1, max = 1, chance = 10},
|
||||
{item = "pistol_ammo", label = "Pistol Ammo", min = 10, max = 30, chance = 25},
|
||||
{item = "armor", label = "Body Armor", min = 1, max = 2, chance = 20},
|
||||
{item = "weapon_knife", label = "Knife", min = 1, max = 1, chance = 30},
|
||||
{item = "cash", label = "Cash", min = 2000, max = 7000, chance = 35},
|
||||
},
|
||||
policeAlert = true,
|
||||
},
|
||||
-- Trailer containers
|
||||
{
|
||||
model = "trailers",
|
||||
type = "trailer",
|
||||
label = "Cargo Trailer",
|
||||
offset = vector3(0.0, -5.0, 0.0),
|
||||
heading = 180.0,
|
||||
animation = {
|
||||
dict = "amb@world_human_welding@male@base",
|
||||
name = "base",
|
||||
flag = 1,
|
||||
duration = 45000,
|
||||
},
|
||||
rewards = {
|
||||
{item = "electronics", label = "Electronics", min = 3, max = 8, chance = 40},
|
||||
{item = "plastic", label = "Plastic", min = 10, max = 20, chance = 60},
|
||||
{item = "aluminum", label = "Aluminum", min = 10, max = 20, chance = 50},
|
||||
{item = "copper", label = "Copper", min = 5, max = 15, chance = 30},
|
||||
{item = "cash", label = "Cash", min = 3000, max = 10000, chance = 25},
|
||||
},
|
||||
policeAlert = true,
|
||||
},
|
||||
{
|
||||
model = "trailers2",
|
||||
type = "trailer",
|
||||
label = "Box Trailer",
|
||||
offset = vector3(0.0, -5.0, 0.0),
|
||||
heading = 180.0,
|
||||
animation = {
|
||||
dict = "amb@world_human_welding@male@base",
|
||||
name = "base",
|
||||
flag = 1,
|
||||
duration = 40000,
|
||||
},
|
||||
rewards = {
|
||||
{item = "food", label = "Food", min = 5, max = 15, chance = 70},
|
||||
{item = "water", label = "Water", min = 5, max = 15, chance = 70},
|
||||
{item = "firstaid", label = "First Aid Kit", min = 1, max = 3, chance = 30},
|
||||
{item = "cash", label = "Cash", min = 500, max = 3000, chance = 20},
|
||||
},
|
||||
policeAlert = false, -- No police alert for food trailers
|
||||
},
|
||||
-- Add more container types as needed
|
||||
}
|
||||
|
||||
-- Locations where containers can be found (optional, for target setup)
|
||||
Config.ContainerLocations = {
|
||||
{
|
||||
coords = vector3(1000.0, -3000.0, 5.0),
|
||||
heading = 0.0,
|
||||
model = "prop_container_01a",
|
||||
spawnContainer = true, -- Whether to spawn a container at this location
|
||||
},
|
||||
{
|
||||
coords = vector3(980.0, -3000.0, 5.0),
|
||||
heading = 0.0,
|
||||
model = "prop_container_01b",
|
||||
spawnContainer = true,
|
||||
},
|
||||
-- Add more fixed locations as needed
|
||||
}
|
26
resources/[jobs]/[crime]/nordi_containerheist/fxmanifest.lua
Normal file
26
resources/[jobs]/[crime]/nordi_containerheist/fxmanifest.lua
Normal file
|
@ -0,0 +1,26 @@
|
|||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
description 'Container Heist Script'
|
||||
author 'Your Name'
|
||||
version '1.0.0'
|
||||
|
||||
shared_scripts {
|
||||
'@ox_lib/init.lua',
|
||||
'config.lua'
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'client/main.lua'
|
||||
}
|
||||
|
||||
server_scripts {
|
||||
'server/main.lua'
|
||||
}
|
||||
|
||||
lua54 'yes'
|
||||
|
||||
dependencies {
|
||||
'ox_lib',
|
||||
'tgiann-inventory'
|
||||
}
|
195
resources/[jobs]/[crime]/nordi_containerheist/server/main.lua
Normal file
195
resources/[jobs]/[crime]/nordi_containerheist/server/main.lua
Normal file
|
@ -0,0 +1,195 @@
|
|||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
local containerCooldowns = {}
|
||||
local playerCooldowns = {}
|
||||
local globalCooldowns = {}
|
||||
|
||||
-- Debug function
|
||||
local function Debug(msg)
|
||||
if Config.Debug then
|
||||
print("[Container Heist] " .. msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if player has required items
|
||||
lib.callback.register('container_heist:server:checkRequiredItems', function(source)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return false end
|
||||
|
||||
-- Check for required flex tool
|
||||
local hasItem = exports['tgiann-inventory']:HasItem(src, Config.RequiredItems.flex.name, Config.RequiredItems.flex.amount)
|
||||
return hasItem
|
||||
end)
|
||||
|
||||
-- Check cooldowns
|
||||
lib.callback.register('container_heist:server:checkCooldown', function(source, containerId)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return {success = false, message = "Player not found"} end
|
||||
|
||||
local citizenId = Player.PlayerData.citizenid
|
||||
local currentTime = os.time()
|
||||
|
||||
-- Check player cooldown
|
||||
if playerCooldowns[citizenId] and (currentTime - playerCooldowns[citizenId]) < (Config.CooldownTime * 60) then
|
||||
local timeLeft = math.ceil(((playerCooldowns[citizenId] + (Config.CooldownTime * 60)) - currentTime) / 60)
|
||||
return {success = false, message = "You need to wait " .. timeLeft .. " more minutes before attempting another heist!"}
|
||||
end
|
||||
|
||||
-- Check container cooldown
|
||||
if containerCooldowns[containerId] and (currentTime - containerCooldowns[containerId]) < (Config.CooldownTime * 60) then
|
||||
return {success = false, message = Config.Notifications.alreadyRobbed}
|
||||
end
|
||||
|
||||
-- Check global cooldown for container type
|
||||
for containerType, cooldownTime in pairs(globalCooldowns) do
|
||||
if (currentTime - cooldownTime) < (Config.GlobalCooldown * 60) then
|
||||
local timeLeft = math.ceil(((cooldownTime + (Config.GlobalCooldown * 60)) - currentTime) / 60)
|
||||
return {success = false, message = Config.Notifications.globalCooldown .. " (" .. timeLeft .. " minutes left)"}
|
||||
end
|
||||
end
|
||||
|
||||
return {success = true}
|
||||
end)
|
||||
|
||||
-- Get police count
|
||||
lib.callback.register('container_heist:server:getPoliceCount', function()
|
||||
local policeCount = 0
|
||||
local players = QBCore.Functions.GetPlayers()
|
||||
|
||||
for _, playerId in ipairs(players) do
|
||||
local Player = QBCore.Functions.GetPlayer(playerId)
|
||||
if Player and Player.PlayerData.job.name == Config.PoliceJobName and Player.PlayerData.job.onduty then
|
||||
policeCount = policeCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
return policeCount
|
||||
end)
|
||||
|
||||
-- Alert police
|
||||
RegisterNetEvent('container_heist:server:alertPolice', function(coords, streetName, containerType)
|
||||
local src = source
|
||||
local players = QBCore.Functions.GetPlayers()
|
||||
|
||||
for _, playerId in ipairs(players) do
|
||||
local Player = QBCore.Functions.GetPlayer(playerId)
|
||||
if Player and Player.PlayerData.job.name == Config.PoliceJobName and Player.PlayerData.job.onduty then
|
||||
TriggerClientEvent('container_heist:client:policeAlert', playerId, coords, streetName, containerType)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Finish robbery and give rewards
|
||||
RegisterNetEvent('container_heist:server:finishRobbery', function(containerId, containerType)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
|
||||
local citizenId = Player.PlayerData.citizenid
|
||||
local currentTime = os.time()
|
||||
|
||||
-- Set cooldowns
|
||||
playerCooldowns[citizenId] = currentTime
|
||||
containerCooldowns[containerId] = currentTime
|
||||
globalCooldowns[containerType] = currentTime
|
||||
|
||||
-- Decrease durability of flex tool if configured
|
||||
if Config.RequiredItems.flex.durability then
|
||||
local itemData = exports['tgiann-inventory']:GetItemByName(src, Config.RequiredItems.flex.name)
|
||||
if itemData and itemData.info and itemData.info.durabilityPercent then
|
||||
local newDurability = math.max(0, itemData.info.durabilityPercent - Config.RequiredItems.flex.durabilityDecrease)
|
||||
exports['tgiann-inventory']:UpdateItemMetadata(src, Config.RequiredItems.flex.name, itemData.slot, {
|
||||
durabilityPercent = newDurability,
|
||||
serie = itemData.info.serie,
|
||||
usedTotalAmmo = itemData.info.usedTotalAmmo or 0,
|
||||
ammo = itemData.info.ammo or 0
|
||||
})
|
||||
|
||||
-- Remove item if durability reaches 0
|
||||
if newDurability <= 0 and Config.RequiredItems.flex.remove then
|
||||
exports['tgiann-inventory']:RemoveItem(src, Config.RequiredItems.flex.name, 1)
|
||||
TriggerClientEvent('QBCore:Notify', src, "Your " .. Config.RequiredItems.flex.label .. " broke!", "error")
|
||||
end
|
||||
end
|
||||
elseif Config.RequiredItems.flex.remove then
|
||||
-- Remove item if configured
|
||||
exports['tgiann-inventory']:RemoveItem(src, Config.RequiredItems.flex.name, Config.RequiredItems.flex.amount)
|
||||
end
|
||||
|
||||
-- Find the container type in config
|
||||
local containerConfig = nil
|
||||
for _, config in pairs(Config.ContainerTypes) do
|
||||
if config.type == containerType then
|
||||
containerConfig = config
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not containerConfig then
|
||||
Debug("Container type not found in config: " .. containerType)
|
||||
return
|
||||
end
|
||||
|
||||
-- Give rewards based on chances
|
||||
local rewardsGiven = 0
|
||||
for _, reward in pairs(containerConfig.rewards) do
|
||||
if math.random(1, 100) <= reward.chance then
|
||||
local amount = math.random(reward.min, reward.max)
|
||||
|
||||
if reward.item == "cash" then
|
||||
Player.Functions.AddMoney("cash", amount)
|
||||
TriggerClientEvent('QBCore:Notify', src, "Found $" .. amount, "success")
|
||||
else
|
||||
-- Add item with proper metadata for weapons
|
||||
if string.match(reward.item, "weapon_") then
|
||||
exports['tgiann-inventory']:AddItem(src, reward.item, amount, nil, {
|
||||
serie = "HEIST-" .. math.random(100000, 999999),
|
||||
durabilityPercent = 100,
|
||||
usedTotalAmmo = 0,
|
||||
ammo = 0
|
||||
})
|
||||
else
|
||||
exports['tgiann-inventory']:AddItem(src, reward.item, amount)
|
||||
end
|
||||
|
||||
TriggerClientEvent('QBCore:Notify', src, "Found " .. amount .. "x " .. reward.label, "success")
|
||||
end
|
||||
|
||||
rewardsGiven = rewardsGiven + 1
|
||||
end
|
||||
end
|
||||
|
||||
if rewardsGiven == 0 then
|
||||
TriggerClientEvent('QBCore:Notify', src, "The container was empty!", "error")
|
||||
end
|
||||
end)
|
||||
|
||||
-- Clean up cooldowns periodically
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(60000) -- Check every minute
|
||||
local currentTime = os.time()
|
||||
|
||||
-- Clean up player cooldowns
|
||||
for citizenId, cooldownTime in pairs(playerCooldowns) do
|
||||
if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
|
||||
playerCooldowns[citizenId] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean up container cooldowns
|
||||
for containerId, cooldownTime in pairs(containerCooldowns) do
|
||||
if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
|
||||
containerCooldowns[containerId] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean up global cooldowns
|
||||
for containerType, cooldownTime in pairs(globalCooldowns) do
|
||||
if (currentTime - cooldownTime) > (Config.GlobalCooldown * 60) then
|
||||
globalCooldowns[containerType] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
Loading…
Add table
Add a link
Reference in a new issue