forked from Simnation/Main
Update main.lua
This commit is contained in:
parent
a71624a6ba
commit
d3f4114333
1 changed files with 165 additions and 250 deletions
|
@ -1,8 +1,7 @@
|
|||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
local isRobbing = false
|
||||
local currentPoint = nil
|
||||
local containerBlip = nil
|
||||
local nearbyPoint = nil
|
||||
local pointCooldowns = {}
|
||||
local playerCooldowns = {}
|
||||
local globalCooldowns = {}
|
||||
|
||||
-- Debug function
|
||||
local function Debug(msg)
|
||||
|
@ -11,286 +10,202 @@ local function Debug(msg)
|
|||
end
|
||||
end
|
||||
|
||||
-- Helper function to draw 3D text
|
||||
function DrawText3D(x, y, z, text)
|
||||
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
|
||||
local px, py, pz = table.unpack(GetGameplayCamCoords())
|
||||
-- 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
|
||||
|
||||
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, 41, 11, 41, 68)
|
||||
end
|
||||
-- Check for required flex tool
|
||||
local hasItem = exports['tgiann-inventory']:HasItem(src, Config.RequiredItems.flex.name, Config.RequiredItems.flex.amount)
|
||||
return hasItem
|
||||
end)
|
||||
|
||||
-- Function to find the nearest container point
|
||||
local function GetNearestContainerPoint()
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
local closestPoint = nil
|
||||
local minDistance = 3.0 -- Maximum interaction distance
|
||||
-- Check cooldowns
|
||||
lib.callback.register('container_heist:server:checkCooldown', function(source, pointId)
|
||||
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 point cooldown
|
||||
if pointCooldowns[pointId] and (currentTime - pointCooldowns[pointId]) < (Config.CooldownTime * 60) then
|
||||
return {success = false, message = Config.Notifications.alreadyRobbed}
|
||||
end
|
||||
|
||||
-- Find point type
|
||||
local pointType = nil
|
||||
for _, point in pairs(Config.ContainerPoints) do
|
||||
local distance = #(playerCoords - point.coords)
|
||||
if distance < minDistance then
|
||||
minDistance = distance
|
||||
closestPoint = point
|
||||
if point.id == pointId then
|
||||
pointType = point.type
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return closestPoint, minDistance
|
||||
end
|
||||
if not pointType then
|
||||
return {success = false, message = "Invalid point!"}
|
||||
end
|
||||
|
||||
-- Check global cooldown for container type
|
||||
if globalCooldowns[pointType] and (currentTime - globalCooldowns[pointType]) < (Config.GlobalCooldown * 60) then
|
||||
local timeLeft = math.ceil(((globalCooldowns[pointType] + (Config.GlobalCooldown * 60)) - currentTime) / 60)
|
||||
return {success = false, message = Config.Notifications.globalCooldown .. " (" .. timeLeft .. " minutes left)"}
|
||||
end
|
||||
|
||||
return {success = true}
|
||||
end)
|
||||
|
||||
-- Function to create a blip at the robbery location
|
||||
local function CreateRobberyBlip(coords)
|
||||
if containerBlip then
|
||||
RemoveBlip(containerBlip)
|
||||
end
|
||||
-- Get police count
|
||||
lib.callback.register('container_heist:server:getPoliceCount', function()
|
||||
local policeCount = 0
|
||||
local players = QBCore.Functions.GetPlayers()
|
||||
|
||||
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
|
||||
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)
|
||||
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
|
||||
return policeCount
|
||||
end)
|
||||
|
||||
-- Function to start container robbery
|
||||
local function StartContainerRobbery(point)
|
||||
if isRobbing then return end
|
||||
-- Alert police
|
||||
RegisterNetEvent('container_heist:server:alertPolice', function(coords, streetName, containerLabel)
|
||||
local src = source
|
||||
local players = QBCore.Functions.GetPlayers()
|
||||
|
||||
isRobbing = true
|
||||
currentPoint = point
|
||||
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, containerLabel)
|
||||
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(pointId, containerTypeName)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
|
||||
-- Get container type from point
|
||||
local containerType = Config.ContainerTypes[point.type]
|
||||
local citizenId = Player.PlayerData.citizenid
|
||||
local currentTime = os.time()
|
||||
|
||||
-- Set cooldowns
|
||||
playerCooldowns[citizenId] = currentTime
|
||||
pointCooldowns[pointId] = currentTime
|
||||
globalCooldowns[containerTypeName] = currentTime
|
||||
|
||||
-- Get container type
|
||||
local containerType = Config.ContainerTypes[containerTypeName]
|
||||
if not containerType then
|
||||
QBCore.Functions.Notify("Invalid container type!", "error")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
Debug("Container type not found: " .. containerTypeName)
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if player has required tools
|
||||
local hasTools = lib.callback.await('container_heist:server:checkRequiredItems', false)
|
||||
if not hasTools then
|
||||
QBCore.Functions.Notify(Config.Notifications.noTools, "error")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
return
|
||||
-- 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
|
||||
|
||||
-- Check cooldowns
|
||||
local cooldownCheck = lib.callback.await('container_heist:server:checkCooldown', false, point.id)
|
||||
if not cooldownCheck.success then
|
||||
QBCore.Functions.Notify(cooldownCheck.message, "error")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
return
|
||||
-- Give rewards based on chances
|
||||
local rewardsGiven = 0
|
||||
for _, reward in pairs(containerType.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
|
||||
|
||||
-- Check police count
|
||||
local policeCount = lib.callback.await('container_heist:server:getPoliceCount', false)
|
||||
if policeCount < Config.PoliceRequired then
|
||||
QBCore.Functions.Notify(Config.Notifications.notEnoughPolice, "error")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
return
|
||||
if rewardsGiven == 0 then
|
||||
TriggerClientEvent('QBCore:Notify', src, "The container was empty!", "error")
|
||||
end
|
||||
|
||||
-- Position player for animation
|
||||
SetEntityCoords(PlayerPedId(), point.coords.x, point.coords.y, point.coords.z)
|
||||
SetEntityHeading(PlayerPedId(), point.heading)
|
||||
|
||||
-- Alert police if configured
|
||||
if containerType.policeAlert then
|
||||
local streetName = GetStreetNameFromHashKey(GetStreetNameAtCoord(point.coords.x, point.coords.y, point.coords.z))
|
||||
TriggerServerEvent('container_heist:server:alertPolice', point.coords, streetName, containerType.label)
|
||||
end
|
||||
|
||||
-- Start robbery progress bar
|
||||
PlayRobberyAnimation(containerType)
|
||||
|
||||
QBCore.Functions.Progressbar("container_robbery", 'Breaking into ' .. containerType.label, containerType.animation.duration, false, true, {
|
||||
disableMovement = true,
|
||||
disableCarMovement = true,
|
||||
disableMouse = false,
|
||||
disableCombat = true,
|
||||
}, {}, {}, {}, function() -- Done
|
||||
-- Success
|
||||
TriggerServerEvent('container_heist:server:finishRobbery', point.id, point.type)
|
||||
QBCore.Functions.Notify(Config.Notifications.success, "success")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
end, function() -- Cancel
|
||||
-- Cancelled
|
||||
QBCore.Functions.Notify(Config.Notifications.failed, "error")
|
||||
isRobbing = false
|
||||
currentPoint = nil
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Command to start container robbery
|
||||
RegisterCommand('robcontainer', function()
|
||||
local point, distance = GetNearestContainerPoint()
|
||||
|
||||
if point then
|
||||
StartContainerRobbery(point)
|
||||
else
|
||||
QBCore.Functions.Notify("No container nearby!", "error")
|
||||
end
|
||||
end, false)
|
||||
|
||||
-- Command to toggle debug mode
|
||||
RegisterCommand('containerdebug', function()
|
||||
Config.Debug = not Config.Debug
|
||||
|
||||
if Config.Debug then
|
||||
QBCore.Functions.Notify("Container Debug mode enabled", "primary")
|
||||
else
|
||||
QBCore.Functions.Notify("Container Debug mode disabled", "primary")
|
||||
end
|
||||
end, false)
|
||||
|
||||
-- Main thread for checking nearby container points
|
||||
-- Clean up cooldowns periodically
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
local wait = 1000
|
||||
local point, distance = GetNearestContainerPoint()
|
||||
Wait(60000) -- Check every minute
|
||||
local currentTime = os.time()
|
||||
|
||||
if point and distance < 3.0 then
|
||||
wait = 0
|
||||
nearbyPoint = point
|
||||
|
||||
-- Draw marker
|
||||
DrawMarker(1, point.coords.x, point.coords.y, point.coords.z - 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.8, 0.8, 0.8, 0, 255, 0, 100, false, true, 2, false, nil, nil, false)
|
||||
|
||||
-- Draw text
|
||||
DrawText3D(point.coords.x, point.coords.y, point.coords.z, point.label .. " [E]")
|
||||
|
||||
-- Check for interaction
|
||||
if IsControlJustReleased(0, 38) and distance < 1.5 then -- E key
|
||||
StartContainerRobbery(point)
|
||||
-- Clean up player cooldowns
|
||||
for citizenId, cooldownTime in pairs(playerCooldowns) do
|
||||
if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
|
||||
playerCooldowns[citizenId] = nil
|
||||
end
|
||||
else
|
||||
nearbyPoint = nil
|
||||
end
|
||||
|
||||
Wait(wait)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Debug thread for showing all container points
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(0)
|
||||
|
||||
if Config.Debug then
|
||||
for _, point in pairs(Config.ContainerPoints) do
|
||||
DrawMarker(1, point.coords.x, point.coords.y, point.coords.z - 1.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)
|
||||
DrawText3D(point.coords.x, point.coords.y, point.coords.z + 0.5, point.id .. " (" .. point.type .. ")")
|
||||
-- Clean up point cooldowns
|
||||
for pointId, cooldownTime in pairs(pointCooldowns) do
|
||||
if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
|
||||
pointCooldowns[pointId] = nil
|
||||
end
|
||||
else
|
||||
Wait(1000)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Event to show police alert
|
||||
RegisterNetEvent('container_heist:client:policeAlert', function(coords, streetName, containerLabel)
|
||||
local playerJob = QBCore.Functions.GetPlayerData().job.name
|
||||
local alertTitle = Config.Notifications.policeTitle
|
||||
|
||||
-- Customize alert based on job
|
||||
if playerJob == "marshal" then
|
||||
alertTitle = "MARSHAL SERVICE ALERT"
|
||||
elseif playerJob == "sheriff" then
|
||||
alertTitle = "SHERIFF DEPARTMENT ALERT"
|
||||
end
|
||||
|
||||
-- Create alert for police officers
|
||||
QBCore.Functions.Notify(alertTitle .. ": " .. string.format(Config.Notifications.policeMessage, streetName), "police", 10000)
|
||||
|
||||
-- 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 then
|
||||
StopAnimTask(PlayerPedId(), "amb@world_human_welding@male@base", "base", 1.0)
|
||||
-- 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