1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-20 17:41:10 +02:00
parent c00df8dec6
commit 4676cbfc6d
4 changed files with 1386 additions and 250 deletions

View file

@ -1,7 +1,8 @@
local QBCore = exports['qb-core']:GetCoreObject()
local isRobbing = false
local inZone = false
local currentZoneId = nil
local currentContainer = nil
local containerBlip = nil
local addedEntities = {}
-- Debug function
local function Debug(msg)
@ -10,167 +11,544 @@ local function Debug(msg)
end
end
-- Function to check if a point is inside a polygon
local function IsPointInPolygon(point, polygon)
local x, y = point.x, point.y
local inside = false
local j = #polygon
for i = 1, #polygon do
if (polygon[i].y > y) ~= (polygon[j].y > y) and
x < (polygon[j].x - polygon[i].x) * (y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x then
inside = not inside
-- Function to get model name from hash
local function GetModelNameFromHash(hash)
for _, containerType in pairs(Config.ContainerTypes) do
if GetHashKey(containerType.model) == hash then
return containerType.model
end
j = i
end
return inside
return "Unknown"
end
-- Function to check if player is in any container zone
local function GetCurrentZone()
-- Function to check if player is near a valid container
local function IsNearValidContainer()
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local foundEntity = nil
local foundType = nil
local closestDistance = 999.0
for _, zone in pairs(Config.ContainerZones) do
if IsPointInPolygon(playerCoords, zone.points) and
playerCoords.z >= zone.minZ and playerCoords.z <= zone.maxZ then
return zone
end
end
return nil
end
-- Simple command to test if the script is working
RegisterCommand('containertest', function()
local playerCoords = GetEntityCoords(PlayerPedId())
print("Player coords: " .. playerCoords.x .. ", " .. playerCoords.y .. ", " .. playerCoords.z)
local zone = GetCurrentZone()
if zone then
QBCore.Functions.Notify("You are in zone: " .. zone.id, "success")
print("In zone: " .. zone.id)
else
QBCore.Functions.Notify("You are not in any container zone", "error")
print("Not in any zone")
end
end, false)
-- Command to start robbery (for testing)
RegisterCommand('robcontainer', function()
local zone = GetCurrentZone()
if zone then
QBCore.Functions.Notify("Starting robbery in zone: " .. zone.id, "success")
TriggerServerEvent('container_heist:server:testRobbery', zone.id, zone.type)
else
QBCore.Functions.Notify("You are not in any container zone", "error")
end
end, false)
-- Register usable item event handler
RegisterNetEvent('container_heist:client:useFlexItem', function()
print("useFlexItem event triggered")
local zone = GetCurrentZone()
if zone then
print("Player is in zone: " .. zone.id)
QBCore.Functions.Notify("Starting robbery with flex tool in zone: " .. zone.id, "success")
TriggerServerEvent('container_heist:server:testRobbery', zone.id, zone.type)
else
QBCore.Functions.Notify(Config.Notifications.notInZone, "error")
end
end)
-- Main thread for checking if player is in a zone
CreateThread(function()
while true do
local sleep = 1000
local zone = GetCurrentZone()
if zone then
if not inZone or currentZoneId ~= zone.id then
inZone = true
currentZoneId = zone.id
QBCore.Functions.Notify("You entered " .. zone.label .. ". Use your flex tool to break in.", "primary")
print("Entered zone: " .. zone.id)
end
sleep = 500
else
if inZone then
inZone = false
currentZoneId = nil
print("Left zone")
end
end
Wait(sleep)
end
end)
-- Debug thread for visualizing zones
CreateThread(function()
while true do
if Config.Debug then
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
-- Check for containers in the area (objects)
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)
for _, zone in pairs(Config.ContainerZones) do
-- Draw lines connecting the points to visualize the zone
for i = 1, #zone.points do
local j = i % #zone.points + 1
local point1 = zone.points[i]
local point2 = zone.points[j]
-- Draw line at ground level
DrawLine(
point1.x, point1.y, zone.minZ,
point2.x, point2.y, zone.minZ,
255, 0, 0, 255
)
if distance <= 5.0 and distance < closestDistance then
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
foundEntity = object
foundType = containerType
closestDistance = distance
break
end
end
-- Calculate center of zone for label
local centerX, centerY = 0, 0
for _, point in ipairs(zone.points) do
centerX = centerX + point.x
centerY = centerY + point.y
end
centerX = centerX / #zone.points
centerY = centerY / #zone.points
-- Draw zone label
local centerZ = (zone.minZ + zone.maxZ) / 2
DrawTextOnCoord(centerX, centerY, centerZ, zone.id .. " (" .. zone.type .. ")")
end
Wait(0)
else
Wait(1000)
end
end
-- Check for trailers in the area (vehicles)
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 and distance < closestDistance then
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
foundEntity = vehicle
foundType = containerType
closestDistance = distance
break
end
end
end
end
end
return foundEntity, foundType
end
-- Function to create a blip at the robbery location
local function CreateRobberyBlip(coords)
if containerBlip then
RemoveBlip(containerBlip)
end
containerBlip = AddBlipForCoord(coords)
-- Set blip color based on job
local playerJob = QBCore.Functions.GetPlayerData().job.name
if playerJob == "marshal" then
SetBlipColour(containerBlip, 38) -- Purple for Marshal
elseif playerJob == "sheriff" then
SetBlipColour(containerBlip, 16) -- Orange for Sheriff
else
SetBlipColour(containerBlip, Config.Blip.color) -- Default color for regular police
end
SetBlipSprite(containerBlip, Config.Blip.sprite)
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
-- Function to scan and add all nearby containers to target system
local function ScanAndAddContainersToTarget()
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local count = 0
-- Check for containers in the area (objects)
local objects = GetGamePool('CObject')
for _, object in ipairs(objects) do
if DoesEntityExist(object) and not IsEntityDead(object) then
local objectCoords = GetEntityCoords(object)
local distance = #(playerCoords - objectCoords)
if distance <= 50.0 then
local model = GetEntityModel(object)
if not addedEntities[object] then
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
exports['qb-target']:AddTargetEntity(object, {
options = {
{
type = "client",
event = "container_heist:client:startRobbery",
icon = "fas fa-angle-double-right",
label = "Break into " .. containerType.label,
containerType = containerType,
}
},
distance = 3.0
})
addedEntities[object] = true
count = count + 1
break
end
end
end
end
end
end
-- Check for trailers in the area (vehicles)
local vehicles = GetGamePool('CVehicle')
for _, vehicle in ipairs(vehicles) do
if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then
local vehicleCoords = GetEntityCoords(vehicle)
local distance = #(playerCoords - vehicleCoords)
if distance <= 50.0 then
local model = GetEntityModel(vehicle)
if not addedEntities[vehicle] then
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
exports['qb-target']:AddTargetEntity(vehicle, {
options = {
{
type = "client",
event = "container_heist:client:startRobbery",
icon = "fas fa-angle-double-right",
label = "Break into " .. containerType.label,
containerType = containerType,
}
},
distance = 3.0
})
addedEntities[vehicle] = true
count = count + 1
break
end
end
end
end
end
end
return count
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)
-- Command to scan and add all nearby containers to target system
RegisterCommand('scancontainers', function()
local count = ScanAndAddContainersToTarget()
lib.notify({
title = "Container Scanner",
description = "Added " .. count .. " containers/trailers to target system",
type = 'success',
position = 'top',
duration = 3000
})
end, false)
-- Debug command to show all nearby containers and trailers
RegisterCommand('containersdebug', function()
if not Config.Debug then return end
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local foundContainers = 0
-- Check for containers in the area (objects)
local objects = GetGamePool('CObject')
for _, object in ipairs(objects) do
if DoesEntityExist(object) and not IsEntityDead(object) then
local objectCoords = GetEntityCoords(object)
local distance = #(playerCoords - objectCoords)
if distance <= 20.0 then
local model = GetEntityModel(object)
local modelName = "Unknown"
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
modelName = containerType.model
break
end
end
print("Found container object: " .. modelName .. " (Hash: " .. model .. ") at distance: " .. distance)
foundContainers = foundContainers + 1
end
end
end
-- Check for trailers in the area (vehicles)
local vehicles = GetGamePool('CVehicle')
for _, vehicle in ipairs(vehicles) do
if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then
local vehicleCoords = GetEntityCoords(vehicle)
local distance = #(playerCoords - vehicleCoords)
if distance <= 20.0 then
local model = GetEntityModel(vehicle)
local modelName = "Unknown"
for _, containerType in pairs(Config.ContainerTypes) do
if model == GetHashKey(containerType.model) then
modelName = containerType.model
break
end
end
print("Found trailer vehicle: " .. modelName .. " (Hash: " .. model .. ") at distance: " .. distance)
foundContainers = foundContainers + 1
end
end
end
print("Total containers/trailers found: " .. foundContainers)
end, false)
-- Command to identify the model of what you're looking at
RegisterCommand('identifycontainer', function()
local playerPed = PlayerPedId()
local success, entity = GetEntityPlayerIsFreeAimingAt(PlayerId())
if success and DoesEntityExist(entity) then
local model = GetEntityModel(entity)
local modelName = GetModelNameFromHash(model)
local entityType = GetEntityType(entity)
local entityTypeStr = "Unknown"
if entityType == 1 then
entityTypeStr = "Ped"
elseif entityType == 2 then
entityTypeStr = "Vehicle"
elseif entityType == 3 then
entityTypeStr = "Object"
end
print("Entity Type: " .. entityTypeStr)
print("Model Hash: " .. model)
print("Model Name: " .. modelName)
-- Add visual indicator
local coords = GetEntityCoords(entity)
DrawMarker(0, coords.x, coords.y, coords.z + 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 255, 0, 0, 100, false, true, 2, false, nil, nil, false)
-- Show notification
lib.notify({
title = "Container Identification",
description = "Type: " .. entityTypeStr .. "\nModel: " .. modelName .. "\nHash: " .. model,
type = 'inform',
position = 'top',
duration = 5000
})
else
lib.notify({
title = "Container Identification",
description = "No entity found. Aim at a container or trailer.",
type = 'error',
position = 'top',
duration = 3000
})
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)
-- Function to draw text in 3D space
function DrawTextOnCoord(x, y, z, text)
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
if onScreen then
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(text)
DrawText(_x, _y)
local factor = (string.len(text)) / 370
DrawRect(_x, _y + 0.0125, 0.015 + factor, 0.03, 0, 0, 0, 75)
end
end
-- Print message when resource starts
AddEventHandler('onClientResourceStart', function(resourceName)
if (GetCurrentResourceName() == resourceName) then
print("^2[Container Heist]^7: Client script started successfully")
-- Automatically scan for containers periodically
CreateThread(function()
while true do
ScanAndAddContainersToTarget()
Wait(30000) -- Scan every 30 seconds
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)
local playerJob = QBCore.Functions.GetPlayerData().job.name
local alertTitle = Config.Notifications.policeTitle
local alertIcon = 'fas fa-exclamation-triangle'
-- Customize alert based on job
if playerJob == "marshal" then
alertTitle = "MARSHAL SERVICE ALERT"
alertIcon = 'fas fa-star' -- Marshal badge icon
elseif playerJob == "sheriff" then
alertTitle = "SHERIFF DEPARTMENT ALERT"
alertIcon = 'fas fa-shield-alt' -- Sheriff badge icon
end
-- Create alert for police officers
lib.notify({
title = alertTitle,
description = string.format(Config.Notifications.policeMessage, streetName),
type = 'inform',
position = 'top',
icon = alertIcon,
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)

View file

@ -2,8 +2,8 @@ Config = {}
-- General Settings
Config.Debug = true -- Set to true for debug prints
Config.CooldownTime = 30 -- Minutes between heists (per player)
Config.GlobalCooldown = 15 -- Minutes between heists (server-wide)
Config.CooldownTime = 1 -- Minutes between heists (per player)
Config.GlobalCooldown = 1 -- Minutes between heists (server-wide)
Config.PoliceRequired = 1 -- Minimum police required
Config.PoliceJobs = {
"police", -- Regular police
@ -35,7 +35,6 @@ Config.Notifications = {
notEnoughPolice = "Not enough police in the city!",
policeMessage = "Container robbery in progress at %s",
alreadyRobbed = "This container has already been robbed recently!",
notInZone = "You need to be in a container area to use this tool!",
}
-- Blip Settings
@ -43,38 +42,42 @@ Config.Blip = {
sprite = 67,
color = 1,
scale = 0.8,
label = "Container Robbery",
label = "Container Einbruch",
duration = 180, -- seconds
flash = true,
}
-- Container Types (for rewards and animations)
Config.ContainerTypes = {
-- Regular shipping containers
shipping = {
{
model = "prop_container_01a",
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, -- milliseconds
duration = 30000,
},
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,
},
-- Weapons container
weapons = {
label = "Weapons Container",
{
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",
@ -90,10 +93,340 @@ Config.ContainerTypes = {
},
policeAlert = true,
},
{
model = "prop_container_01c",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_01d",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_01e",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_01f",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_01g",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_01h",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_02a",
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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_03a",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_03b",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_03mb",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_04a",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_04mb",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_05mb",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_ld",
type = "shipping",
label = "Shipping Container",
offset = vector3(0.0, -2.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 30000,
},
rewards = {
{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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "prop_container_door_mb",
type = "shipping",
label = "Container Door",
offset = vector3(0.0, -1.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 20000,
},
rewards = {
{item = "phone", label = "Phone", min = 1, max = 1, chance = 20},
{item = "cash", label = "Cash", min = 500, max = 2000, chance = 30},
},
policeAlert = false,
},
-- Cargo trailer
cargo = {
-- Trailer models
{
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",
@ -109,10 +442,12 @@ Config.ContainerTypes = {
},
policeAlert = true,
},
-- Food trailer
food = {
label = "Food Trailer",
{
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",
@ -127,69 +462,320 @@ Config.ContainerTypes = {
},
policeAlert = false,
},
{
model = "trailers3",
type = "trailer",
label = "Transport 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 = "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},
{item = "cash", label = "Cash", min = 1000, max = 5000, chance = 40},
},
policeAlert = true,
},
{
model = "trailers4",
type = "trailer",
label = "Car 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 = "carparts", label = "Car Parts", min = 3, max = 8, chance = 60},
{item = "toolbox", label = "Toolbox", min = 1, max = 2, chance = 40},
{item = "cash", label = "Cash", min = 1000, max = 3000, chance = 30},
},
policeAlert = true,
},
{
model = "trailerlogs",
type = "trailer",
label = "Logging 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 = "wood", label = "Wood", min = 10, max = 20, chance = 80},
{item = "cash", label = "Cash", min = 500, max = 2000, chance = 20},
},
policeAlert = false,
},
{
model = "tanker",
type = "trailer",
label = "Fuel Tanker",
offset = vector3(0.0, -5.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 50000,
},
rewards = {
{item = "petrol", label = "Petrol", min = 10, max = 20, chance = 70},
{item = "cash", label = "Cash", min = 2000, max = 5000, chance = 30},
},
policeAlert = true,
},
{
model = "tanker2",
type = "trailer",
label = "Chemical Tanker",
offset = vector3(0.0, -5.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 50000,
},
rewards = {
{item = "chemicals", label = "Chemicals", min = 5, max = 15, chance = 60},
{item = "cash", label = "Cash", min = 3000, max = 8000, chance = 40},
},
policeAlert = true,
},
{
model = "docktrailer",
type = "trailer",
label = "Dock 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 = "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 = "tr2",
type = "trailer",
label = "Car Carrier 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 = "carparts", label = "Car Parts", min = 3, max = 8, chance = 60},
{item = "toolbox", label = "Toolbox", min = 1, max = 2, chance = 40},
{item = "cash", label = "Cash", min = 1000, max = 3000, chance = 30},
},
policeAlert = true,
},
{
model = "tr3",
type = "trailer",
label = "Large 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 = "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 = "tr4",
type = "trailer",
label = "Training 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 = "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 = "tvtrailer",
type = "trailer",
label = "TV 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 = "electronics", label = "Electronics", min = 5, max = 10, chance = 70},
{item = "wires", label = "Wires", min = 5, max = 15, chance = 60},
{item = "cash", label = "Cash", min = 2000, max = 6000, chance = 30},
},
policeAlert = true,
},
{
model = "armytanker",
type = "trailer",
label = "Military Tanker",
offset = vector3(0.0, -5.0, 0.0),
heading = 180.0,
animation = {
dict = "amb@world_human_welding@male@base",
name = "base",
flag = 1,
duration = 50000,
},
rewards = {
{item = "weapon_pistol", label = "Pistol", min = 1, max = 1, chance = 15},
{item = "pistol_ammo", label = "Pistol Ammo", min = 10, max = 30, chance = 30},
{item = "armor", label = "Body Armor", min = 1, max = 3, chance = 25},
{item = "cash", label = "Cash", min = 5000, max = 15000, chance = 20},
},
policeAlert = true,
},
{
model = "armytrailer",
type = "trailer",
label = "Military 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 = 50000,
},
rewards = {
{item = "weapon_pistol", label = "Pistol", min = 1, max = 1, chance = 15},
{item = "pistol_ammo", label = "Pistol Ammo", min = 10, max = 30, chance = 30},
{item = "armor", label = "Body Armor", min = 1, max = 3, chance = 25},
{item = "cash", label = "Cash", min = 5000, max = 15000, chance = 20},
},
policeAlert = true,
},
{
model = "freighttrailer",
type = "trailer",
label = "Freight 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 = "graintrailer",
type = "trailer",
label = "Grain 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 = "grain", label = "Grain", min = 10, max = 20, chance = 80},
{item = "cash", label = "Cash", min = 500, max = 2000, chance = 20},
},
policeAlert = false,
},
{
model = "proptrailer",
type = "trailer",
label = "Prop 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 = "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,
},
}
-- Container Zones (defined by 4 points)
Config.ContainerZones = {
-- Port area shipping containers
-- Locations where containers can be found (optional, for target setup)
Config.ContainerLocations = {
{
id = "port_containers",
type = "shipping", -- References the container type above for rewards
label = "Port Containers",
points = {
vector3(992.49, -3048.93, 5.9), -- Point 1
vector3(991.28, -3018.97, 5.9), -- Point 2
vector3(1063.13, -3016.99, 5.9), -- Point 3
vector3(1061.97, -3050.63, 5.9) -- Point 4
},
minZ = 4.0,
maxZ = 15.0,
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
},
-- Weapons containers
{
id = "weapons_containers",
type = "weapons",
label = "Weapons Containers",
points = {
vector3(905.45, -3200.67, 5.90), -- Point 1
vector3(905.45, -3190.67, 5.90), -- Point 2
vector3(895.45, -3190.67, 5.90), -- Point 3
vector3(895.45, -3200.67, 5.90) -- Point 4
},
minZ = 4.0,
maxZ = 15.0,
coords = vector3(980.0, -3000.0, 5.0),
heading = 0.0,
model = "prop_container_01b",
spawnContainer = true,
},
-- Cargo trailers
{
id = "cargo_trailers",
type = "cargo",
label = "Cargo Trailers",
points = {
vector3(825.34, -3125.45, 5.90), -- Point 1
vector3(825.34, -3115.45, 5.90), -- Point 2
vector3(815.34, -3115.45, 5.90), -- Point 3
vector3(815.34, -3125.45, 5.90) -- Point 4
},
minZ = 4.0,
maxZ = 15.0,
},
-- Food trailers
{
id = "food_trailers",
type = "food",
label = "Food Trailers",
points = {
vector3(765.23, -3165.34, 5.90), -- Point 1
vector3(765.23, -3155.34, 5.90), -- Point 2
vector3(755.23, -3155.34, 5.90), -- Point 3
vector3(755.23, -3165.34, 5.90) -- Point 4
},
minZ = 4.0,
maxZ = 15.0,
},
-- Add more zones as needed
-- Add more fixed locations as needed
}

View file

@ -6,21 +6,21 @@ author 'Your Name'
version '1.0.0'
shared_scripts {
'@ox_lib/init.lua',
'config.lua'
}
client_scripts {
'client.lua'
'client/main.lua'
}
server_scripts {
'server.lua'
'server/main.lua'
}
lua54 'yes'
dependencies {
'qb-core',
'ox_lib',
'tgiann-inventory'
}

View file

@ -1,4 +1,7 @@
local QBCore = exports['qb-core']:GetCoreObject()
local containerCooldowns = {}
local playerCooldowns = {}
local globalCooldowns = {}
-- Debug function
local function Debug(msg)
@ -7,30 +10,199 @@ local function Debug(msg)
end
end
-- Register usable item
QBCore.Functions.CreateUseableItem(Config.RequiredItems.flex.name, function(source)
print("Player " .. source .. " used item: " .. Config.RequiredItems.flex.name)
TriggerClientEvent('container_heist:client:useFlexItem', source)
-- 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)
-- Test robbery event
RegisterNetEvent('container_heist:server:testRobbery', function(zoneId, zoneType)
-- 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 then
-- Check if player's job is in the list of police jobs
for _, jobName in ipairs(Config.PoliceJobs) do
if Player.PlayerData.job.name == jobName and Player.PlayerData.job.onduty then
policeCount = policeCount + 1
break -- No need to check other job names for this player
end
end
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 then
-- Check if player's job is in the list of police jobs
for _, jobName in ipairs(Config.PoliceJobs) do
if Player.PlayerData.job.name == jobName and Player.PlayerData.job.onduty then
TriggerClientEvent('container_heist:client:policeAlert', playerId, coords, streetName, containerType)
break -- No need to send multiple alerts to the same player
end
end
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
print("Player " .. src .. " started robbery in zone: " .. zoneId .. " of type: " .. zoneType)
TriggerClientEvent('QBCore:Notify', src, "Robbery started in zone: " .. zoneId, "success")
local citizenId = Player.PlayerData.citizenid
local currentTime = os.time()
-- Give a test reward
exports['tgiann-inventory']:AddItem(src, "cash", 1000)
TriggerClientEvent('QBCore:Notify', src, "You found $1000!", "success")
end)
-- Print message when resource starts
AddEventHandler('onResourceStart', function(resourceName)
if (GetCurrentResourceName() == resourceName) then
print("^2[Container Heist]^7: Server script started successfully")
print("^2[Container Heist]^7: Registered usable item: " .. Config.RequiredItems.flex.name)
-- 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 then
local newDurability = math.max(0, (itemData.info.durabilityPercent or 100) - Config.RequiredItems.flex.durabilityDecrease)
exports['tgiann-inventory']:UpdateItemMetadata(src, Config.RequiredItems.flex.name, itemData.slot, {
durabilityPercent = newDurability,
serie = itemData.info.serie or "TOOL-" .. math.random(100000, 999999),
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 -- <-- This end statement was missing
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)