422 lines
16 KiB
Lua
422 lines
16 KiB
Lua
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||
|
local isLoggedIn = LocalPlayer.state['isLoggedIn']
|
||
|
local zones = {}
|
||
|
local currentArea = 0
|
||
|
local inSellerZone = false
|
||
|
local iswearingsuit = false
|
||
|
local oxgenlevell = 0
|
||
|
|
||
|
local currentDivingLocation = {
|
||
|
area = 0,
|
||
|
blip = {
|
||
|
radius = nil,
|
||
|
label = nil
|
||
|
}
|
||
|
}
|
||
|
local currentGear = {
|
||
|
mask = 0,
|
||
|
tank = 0,
|
||
|
oxygen = 0,
|
||
|
enabled = false
|
||
|
}
|
||
|
|
||
|
-- Functions
|
||
|
local function callCops()
|
||
|
local call = math.random(1, 3)
|
||
|
local chance = math.random(1, 3)
|
||
|
local ped = PlayerPedId()
|
||
|
local coords = GetEntityCoords(ped)
|
||
|
if call == chance then
|
||
|
TriggerServerEvent('qb-diving:server:CallCops', coords)
|
||
|
end
|
||
|
end
|
||
|
local function deleteGear()
|
||
|
if currentGear.mask ~= 0 then
|
||
|
DetachEntity(currentGear.mask, 0, 1)
|
||
|
DeleteEntity(currentGear.mask)
|
||
|
currentGear.mask = 0
|
||
|
end
|
||
|
if currentGear.tank ~= 0 then
|
||
|
DetachEntity(currentGear.tank, 0, 1)
|
||
|
DeleteEntity(currentGear.tank)
|
||
|
currentGear.tank = 0
|
||
|
end
|
||
|
|
||
|
end
|
||
|
local function gearAnim()
|
||
|
RequestAnimDict("clothingshirt")
|
||
|
while not HasAnimDictLoaded("clothingshirt") do
|
||
|
Wait(0)
|
||
|
end
|
||
|
TaskPlayAnim(PlayerPedId(), "clothingshirt", "try_shirt_positive_d", 8.0, 1.0, -1, 49, 0, 0, 0, 0)
|
||
|
end
|
||
|
local function takeCoral(coral)
|
||
|
if Config.CoralLocations[currentDivingLocation.area].coords.Coral[coral].PickedUp then return end
|
||
|
local ped = PlayerPedId()
|
||
|
local times = math.random(2, 5)
|
||
|
if math.random() > Config.CopsChance then callCops() end
|
||
|
FreezeEntityPosition(ped, true)
|
||
|
QBCore.Functions.Progressbar("take_coral", Lang:t("info.collecting_coral"), times * 1000, false, true, {
|
||
|
disableMovement = true,
|
||
|
disableCarMovement = true,
|
||
|
disableMouse = false,
|
||
|
disableCombat = true,
|
||
|
}, {
|
||
|
animDict = "weapons@first_person@aim_rng@generic@projectile@thermal_charge@",
|
||
|
anim = "plant_floor",
|
||
|
flags = 16,
|
||
|
}, {}, {}, function() -- Done
|
||
|
Config.CoralLocations[currentDivingLocation.area].coords.Coral[coral].PickedUp = true
|
||
|
TriggerServerEvent('qb-diving:server:TakeCoral', currentDivingLocation.area, coral, true)
|
||
|
ClearPedTasks(ped)
|
||
|
FreezeEntityPosition(ped, false)
|
||
|
end, function() -- Cancel
|
||
|
ClearPedTasks(ped)
|
||
|
FreezeEntityPosition(ped, false)
|
||
|
end)
|
||
|
end
|
||
|
local function setDivingLocation(divingLocation)
|
||
|
if currentDivingLocation.area ~= 0 then
|
||
|
for k in pairs(Config.CoralLocations[currentDivingLocation.area].coords.Coral) do
|
||
|
if Config.UseTarget then
|
||
|
exports['qb-target']:RemoveZone(k)
|
||
|
else
|
||
|
if next(zones) then zones[k]:destroy() end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
currentDivingLocation.area = divingLocation
|
||
|
for _, blip in pairs(currentDivingLocation.blip) do if blip then RemoveBlip(blip) end end
|
||
|
local radiusBlip = AddBlipForRadius(Config.CoralLocations[currentDivingLocation.area].coords.Area, 100.0)
|
||
|
SetBlipRotation(radiusBlip, 0)
|
||
|
SetBlipColour(radiusBlip, 47)
|
||
|
currentDivingLocation.blip.radius = radiusBlip
|
||
|
local labelBlip = AddBlipForCoord(Config.CoralLocations[currentDivingLocation.area].coords.Area)
|
||
|
SetBlipSprite(labelBlip, 597)
|
||
|
SetBlipDisplay(labelBlip, 4)
|
||
|
SetBlipScale(labelBlip, 0.7)
|
||
|
SetBlipColour(labelBlip, 0)
|
||
|
SetBlipAsShortRange(labelBlip, true)
|
||
|
BeginTextCommandSetBlipName('STRING')
|
||
|
AddTextComponentSubstringPlayerName(Lang:t("info.diving_area"))
|
||
|
EndTextCommandSetBlipName(labelBlip)
|
||
|
currentDivingLocation.blip.label = labelBlip
|
||
|
for k, v in pairs(Config.CoralLocations[currentDivingLocation.area].coords.Coral) do
|
||
|
if Config.UseTarget then
|
||
|
exports['qb-target']:AddBoxZone('diving_coral_zone_'..k, v.coords, v.length, v.width, {
|
||
|
name = 'diving_coral_zone_'..k,
|
||
|
heading = v.heading,
|
||
|
debugPoly = false,
|
||
|
minZ = v.coords.z - 3,
|
||
|
maxZ = v.coords.z + 2
|
||
|
}, {
|
||
|
options = {
|
||
|
{
|
||
|
label = Lang:t("info.collect_coral"),
|
||
|
icon = 'fa-solid fa-water',
|
||
|
action = function()
|
||
|
takeCoral(k)
|
||
|
end
|
||
|
}
|
||
|
},
|
||
|
distance = 2.0
|
||
|
})
|
||
|
else
|
||
|
zones[k] = BoxZone:Create(v.coords, v.length, v.width, {
|
||
|
name = 'diving_coral_zone_'..k,
|
||
|
heading = v.heading,
|
||
|
debugPoly = false,
|
||
|
minZ = v.coords.z - 3,
|
||
|
maxZ = v.coords.z + 2
|
||
|
})
|
||
|
zones[k]:onPlayerInOut(function(inside)
|
||
|
if inside then
|
||
|
currentArea = k
|
||
|
exports['qb-core']:DrawText(Lang:t("info.collect_coral_dt"), 'top')
|
||
|
else
|
||
|
currentArea = 0
|
||
|
exports['qb-core']:HideText()
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function sellCoral()
|
||
|
local playerPed = PlayerPedId()
|
||
|
LocalPlayer.state:set("inv_busy", true, true)
|
||
|
TaskStartScenarioInPlace(playerPed, "WORLD_HUMAN_STAND_IMPATIENT", 0, true)
|
||
|
QBCore.Functions.Progressbar("sell_coral_items", Lang:t("info.checking_pockets"), math.random(2000, 4000), false, true, {}, {}, {}, {}, function() -- Done
|
||
|
ClearPedTasks(playerPed)
|
||
|
TriggerServerEvent('qb-diving:server:SellCoral')
|
||
|
LocalPlayer.state:set("inv_busy", false, true)
|
||
|
end, function() -- Cancel
|
||
|
ClearPedTasksImmediately(playerPed)
|
||
|
QBCore.Functions.Notify(Lang:t("error.canceled"), "error")
|
||
|
LocalPlayer.state:set("inv_busy", false, true)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
local function createSeller()
|
||
|
for i = 1, #Config.SellLocations do
|
||
|
local current = Config.SellLocations[i]
|
||
|
current.model = type(current.model) == 'string' and GetHashKey(current.model) or current.model
|
||
|
RequestModel(current.model)
|
||
|
while not HasModelLoaded(current.model) do
|
||
|
Wait(0)
|
||
|
end
|
||
|
local currentCoords = vector4(current.coords.x, current.coords.y, current.coords.z - 1, current.coords.w)
|
||
|
local ped = CreatePed(0, current.model, currentCoords, false, false)
|
||
|
FreezeEntityPosition(ped, true)
|
||
|
SetEntityInvincible(ped, true)
|
||
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
||
|
if Config.UseTarget then
|
||
|
exports['qb-target']:AddTargetEntity(ped, {
|
||
|
options = {
|
||
|
{
|
||
|
label = Lang:t("info.sell_coral"),
|
||
|
icon = 'fa-solid fa-dollar-sign',
|
||
|
action = function()
|
||
|
sellCoral()
|
||
|
end
|
||
|
}
|
||
|
},
|
||
|
distance = 2.0
|
||
|
})
|
||
|
else
|
||
|
local zone = BoxZone:Create(current.coords.xyz, current.zoneOptions.length, current.zoneOptions.width, {
|
||
|
name = 'diving_coral_seller_'..i,
|
||
|
heading = current.coords.w,
|
||
|
debugPoly = false,
|
||
|
minZ = current.coords.z - 1.5,
|
||
|
maxZ = current.coords.z + 1.5
|
||
|
})
|
||
|
zone:onPlayerInOut(function(inside)
|
||
|
if inside then
|
||
|
inSellerZone = true
|
||
|
exports['qb-core']:DrawText(Lang:t("info.sell_coral_dt"), 'top')
|
||
|
else
|
||
|
inSellerZone = false
|
||
|
exports['qb-core']:HideText()
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Events
|
||
|
|
||
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||
|
QBCore.Functions.TriggerCallback('qb-diving:server:GetDivingConfig', function(config, area)
|
||
|
Config.CoralLocations = config
|
||
|
setDivingLocation(area)
|
||
|
createSeller()
|
||
|
isLoggedIn = true
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
|
||
|
isLoggedIn = false
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('qb-diving:client:NewLocations', function()
|
||
|
QBCore.Functions.TriggerCallback('qb-diving:server:GetDivingConfig', function(config, area)
|
||
|
Config.CoralLocations = config
|
||
|
setDivingLocation(area)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('qb-diving:client:UpdateCoral', function(area, coral, bool)
|
||
|
Config.CoralLocations[area].coords.Coral[coral].PickedUp = bool
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('qb-diving:client:CallCops', function(coords, msg)
|
||
|
PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1)
|
||
|
TriggerEvent("chatMessage", Lang:t("error.911_chatmessage"), "error", msg)
|
||
|
local transG = 100
|
||
|
local blip = AddBlipForRadius(coords.x, coords.y, coords.z, 100.0)
|
||
|
SetBlipSprite(blip, 9)
|
||
|
SetBlipColour(blip, 1)
|
||
|
SetBlipAlpha(blip, transG)
|
||
|
SetBlipAsShortRange(blip, false)
|
||
|
BeginTextCommandSetBlipName('STRING')
|
||
|
AddTextComponentString(Lang:t("info.blip_text"))
|
||
|
EndTextCommandSetBlipName(blip)
|
||
|
while transG ~= 0 do
|
||
|
Wait(180 * 4)
|
||
|
transG = transG - 1
|
||
|
SetBlipAlpha(blip, transG)
|
||
|
if transG == 0 then
|
||
|
SetBlipSprite(blip, 2)
|
||
|
RemoveBlip(blip)
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-diving:client:setoxygenlevel", function()
|
||
|
if oxgenlevell == 0 then
|
||
|
oxgenlevell = Config.oxygenlevel -- oxygenlevel
|
||
|
QBCore.Functions.Notify(Lang:t("success.tube_filled"), 'success')
|
||
|
TriggerServerEvent('qb-diving:server:removeItemAfterFill')
|
||
|
else
|
||
|
QBCore.Functions.Notify(Lang:t("error.oxygenlevel", {oxygenlevel = oxgenlevell}), 'error')
|
||
|
end
|
||
|
end)
|
||
|
function DrawText2(text)
|
||
|
SetTextFont(4)
|
||
|
SetTextProportional(1)
|
||
|
SetTextScale(0.0, 0.45)
|
||
|
SetTextDropshadow(1, 0, 0, 0, 255)
|
||
|
SetTextEdge(1, 0, 0, 0, 255)
|
||
|
SetTextDropShadow()
|
||
|
SetTextOutline()
|
||
|
SetTextEntry("STRING")
|
||
|
AddTextComponentString(text)
|
||
|
DrawText(0.45, 0.90)
|
||
|
end
|
||
|
|
||
|
RegisterNetEvent('qb-diving:client:UseGear', function()
|
||
|
local ped = PlayerPedId()
|
||
|
if iswearingsuit == false then
|
||
|
if oxgenlevell > 0 then
|
||
|
iswearingsuit = true
|
||
|
if not IsPedSwimming(ped) and not IsPedInAnyVehicle(ped) then
|
||
|
gearAnim()
|
||
|
QBCore.Functions.Progressbar("equip_gear", Lang:t("info.put_suit"), 5000, false, true, {}, {}, {}, {},
|
||
|
function() -- Done
|
||
|
deleteGear()
|
||
|
local maskModel = `p_d_scuba_mask_s`
|
||
|
local tankModel = `p_s_scuba_tank_s`
|
||
|
RequestModel(tankModel)
|
||
|
while not HasModelLoaded(tankModel) do
|
||
|
Wait(0)
|
||
|
end
|
||
|
currentGear.tank = CreateObject(tankModel, 1.0, 1.0, 1.0, 1, 1, 0)
|
||
|
local bone1 = GetPedBoneIndex(ped, 24818)
|
||
|
AttachEntityToEntity(currentGear.tank, ped, bone1, -0.25, -0.25, 0.0, 180.0, 90.0, 0.0, 1, 1, 0,
|
||
|
0, 2, 1)
|
||
|
|
||
|
RequestModel(maskModel)
|
||
|
while not HasModelLoaded(maskModel) do
|
||
|
Wait(0)
|
||
|
end
|
||
|
currentGear.mask = CreateObject(maskModel, 1.0, 1.0, 1.0, 1, 1, 0)
|
||
|
local bone2 = GetPedBoneIndex(ped, 12844)
|
||
|
AttachEntityToEntity(currentGear.mask, ped, bone2, 0.0, 0.0, 0.0, 180.0, 90.0, 0.0, 1, 1, 0, 0, 2
|
||
|
, 1)
|
||
|
SetEnableScuba(ped, true)
|
||
|
SetPedMaxTimeUnderwater(ped, 2000.00)
|
||
|
currentGear.enabled = true
|
||
|
ClearPedTasks(ped)
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
oxgenlevell = oxgenlevell
|
||
|
Citizen.CreateThread(function()
|
||
|
while currentGear.enabled do
|
||
|
if IsPedSwimmingUnderWater(PlayerPedId()) then
|
||
|
oxgenlevell = oxgenlevell - 1
|
||
|
if oxgenlevell == 90 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 80 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 70 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 60 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 50 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 40 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 30 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 20 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 10 then
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", "breathdivingsuit", 0.25)
|
||
|
elseif oxgenlevell == 0 then
|
||
|
-- deleteGear()
|
||
|
SetEnableScuba(ped, false)
|
||
|
SetPedMaxTimeUnderwater(ped, 1.00)
|
||
|
currentGear.enabled = false
|
||
|
iswearingsuit = false
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", nil, 0.25)
|
||
|
end
|
||
|
end
|
||
|
Wait(1000)
|
||
|
end
|
||
|
end)
|
||
|
end)
|
||
|
else
|
||
|
QBCore.Functions.Notify(Lang:t("error.not_standing_up"), 'error')
|
||
|
end
|
||
|
else
|
||
|
QBCore.Functions.Notify(Lang:t("error.need_otube"), 'error')
|
||
|
end
|
||
|
elseif iswearingsuit == true then
|
||
|
gearAnim()
|
||
|
QBCore.Functions.Progressbar("remove_gear", Lang:t("info.pullout_suit"), 5000, false, true, {}, {}, {}, {},
|
||
|
function() -- Done
|
||
|
SetEnableScuba(ped, false)
|
||
|
SetPedMaxTimeUnderwater(ped, 50.00)
|
||
|
currentGear.enabled = false
|
||
|
ClearPedTasks(ped)
|
||
|
deleteGear()
|
||
|
QBCore.Functions.Notify(Lang:t("success.took_out"))
|
||
|
TriggerServerEvent("InteractSound_SV:PlayOnSource", nil, 0.25)
|
||
|
iswearingsuit = false
|
||
|
oxgenlevell = oxgenlevell
|
||
|
end)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- Threads
|
||
|
|
||
|
CreateThread(function()
|
||
|
if isLoggedIn then
|
||
|
QBCore.Functions.TriggerCallback('qb-diving:server:GetDivingConfig', function(config, area)
|
||
|
Config.CoralLocations = config
|
||
|
setDivingLocation(area)
|
||
|
createSeller()
|
||
|
end)
|
||
|
end
|
||
|
if Config.UseTarget then return end
|
||
|
while true do
|
||
|
local sleep = 1000
|
||
|
if isLoggedIn then
|
||
|
if currentArea ~= 0 then
|
||
|
sleep = 0
|
||
|
if IsControlJustPressed(0, 51) then -- E
|
||
|
takeCoral(currentArea)
|
||
|
exports['qb-core']:KeyPressed()
|
||
|
Wait(500)
|
||
|
exports['qb-core']:HideText()
|
||
|
sleep = 3000
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if inSellerZone then
|
||
|
sleep = 0
|
||
|
if IsControlJustPressed(0, 51) then -- E
|
||
|
sellCoral()
|
||
|
exports['qb-core']:KeyPressed()
|
||
|
Wait(500)
|
||
|
exports['qb-core']:HideText()
|
||
|
sleep = 3000
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
Wait(sleep)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
CreateThread(function()
|
||
|
while true do
|
||
|
Wait(0)
|
||
|
if currentGear.enabled == true and iswearingsuit == true then
|
||
|
if IsPedSwimmingUnderWater(PlayerPedId()) then
|
||
|
DrawText2(oxgenlevell..'⏱')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end)
|