local QBCore = exports[Config.CoreName]:GetCoreObject() local pilot, aircraft, parachute, crate, soundID local crate = nil -- Clear crate variable on cooldown end. RegisterNetEvent('qb-gunheist:crate:clearcrate', function() crate = nil end) -- reward on open crate function OpenCrate(entity, crate, item, amount) local ped = PlayerPedId() RequestAnimDict("pickup_object") while not HasAnimDictLoaded("pickup_object") do Wait(10) end TaskPlayAnim(ped, "pickup_object", "pickup_low", 8.0, -8.0, -1, 1, 0, false, false, false) local netId = NetworkGetNetworkIdFromEntity(entity) TriggerServerEvent('qb-gunheist:crate:deleteCrate', netId) TriggerServerEvent("qb-gunheist:server:ItemHandler", "add", item, amount) QBCore.Functions.Notify(Config.Lang["item_recieved"]) -- Finish Wait(1000) ClearPedTasks(ped) end -- Apply Natives RegisterNetEvent("qb-gunheist:crate:applyNatives") AddEventHandler("qb-gunheist:crate:applyNatives", function(netId) crate = NetworkGetEntityFromNetworkId(netId) SetEntityLodDist(crate, 1000) ActivatePhysics(crate) SetEntityVelocity(crate, 0.0, 0.0, -0.2) end) -- Crate Drop function function CrateDrop(item, amount, planeSpawnDistance, dropCoords) CreateThread(function() QBCore.Functions.Notify(Config.Lang["pilot_dropping_soon"], "success", 15000) -- Notify the pilot that we are preparing the crate with the plane SetTimeout(Config.TimeUntilDrop * 60 * 1000, function() for i = 1, #Config.LoadModels do RequestModel(GetHashKey(Config.LoadModels[i])) while not HasModelLoaded(GetHashKey(Config.LoadModels[i])) do Wait(0) end end RequestAnimDict(Config.ParachuteModel) while not HasAnimDictLoaded(Config.ParachuteModel) do Wait(0) end RequestWeaponAsset(GetHashKey(Config.FlareName)) while not HasWeaponAssetLoaded(GetHashKey(Config.FlareName)) do Wait(0) end local rHeading = math.random(0, 360) + 0.0 local planeSpawnDistance = (planeSpawnDistance and tonumber(planeSpawnDistance) + 0.0) or 400.0 local theta = (rHeading / 180.0) * 3.14 local rPlaneSpawn = vector3(dropCoords.x, dropCoords.y, dropCoords.z) - vector3(math.cos(theta) * planeSpawnDistance, math.sin(theta) * planeSpawnDistance, -500.0) local dx = dropCoords.x - rPlaneSpawn.x local dy = dropCoords.y - rPlaneSpawn.y local heading = GetHeadingFromVector_2d(dx, dy) aircraft = CreateVehicle(GetHashKey(Config.PlaneModel), rPlaneSpawn, heading, true, true) SetEntityHeading(aircraft, heading) SetVehicleDoorsLocked(aircraft, 2) SetEntityDynamic(aircraft, true) ActivatePhysics(aircraft) SetVehicleForwardSpeed(aircraft, 60.0) SetHeliBladesFullSpeed(aircraft) SetVehicleEngineOn(aircraft, true, true, false) ControlLandingGear(aircraft, 3) OpenBombBayDoors(aircraft) SetEntityProofs(aircraft, true, false, true, false, false, false, false, false) pilot = CreatePedInsideVehicle(aircraft, 1, GetHashKey(Config.PlanePilotModel), -1, true, true) SetBlockingOfNonTemporaryEvents(pilot, true) SetPedRandomComponentVariation(pilot, false) SetPedKeepTask(pilot, true) SetPlaneMinHeightAboveTerrain(aircraft, 50) TaskVehicleDriveToCoord(pilot, aircraft, vector3(dropCoords.x, dropCoords.y, dropCoords.z) + vector3(0.0, 0.0, 500.0), 60.0, 0, GetHashKey(Config.PlaneModel), 262144, 15.0, -1.0) -- to the dropsite, could be replaced with a task sequence local droparea = vector2(dropCoords.x, dropCoords.y) local planeLocation = vector2(GetEntityCoords(aircraft).x, GetEntityCoords(aircraft).y) while not IsEntityDead(pilot) and #(planeLocation - droparea) > 5.0 do Wait(100) planeLocation = vector2(GetEntityCoords(aircraft).x, GetEntityCoords(aircraft).y) end if IsEntityDead(pilot) then QBCore.Functions.Notify(Config.Lang["pilot_crashed"], "error") -- Notify the pilot that the plane has crashed return end TaskVehicleDriveToCoord(pilot, aircraft, 0.0, 0.0, 500.0, 60.0, 0, GetHashKey(Config.PlaneModel), 262144, -1.0, -1.0) SetEntityAsNoLongerNeeded(pilot) SetEntityAsNoLongerNeeded(aircraft) QBCore.Functions.Notify(Config.Lang["crate_dropping"], "success") -- Notify the pilot that we are preparing the crate with the plane local crateSpawn = vector3(dropCoords.x, dropCoords.y, GetEntityCoords(aircraft).z - 5.0) TriggerServerEvent("qb-gunheist:crate:spawnCrate", crateSpawn, item, amount) while crate == nil do Wait(250) end parachute = CreateObject(GetHashKey(Config.ParachuteModel), crateSpawn, true, true, true) AttachEntityToEntity(parachute, crate, 0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, false, false, false, false, 2, true) SetEntityLodDist(parachute, 1000) SetEntityVelocity(parachute, 0.0, 0.0, -0.2) AttachEntityToEntity(parachute, crate, 0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, false, false, false, false, 2, true) -- Sound soundID = GetSoundId() PlaySoundFromEntity(soundID, "Crate_Beeps", parachute, "MP_CRATE_DROP_SOUNDS", true, 0) -- Checks when the crate is at the dropsite and delete the parachute local parachuteCoords = vector3(GetEntityCoords(parachute)) while #(parachuteCoords - dropCoords) > 5.0 do Wait(250) parachuteCoords = vector3(GetEntityCoords(parachute)) end ShootSingleBulletBetweenCoords(dropCoords, dropCoords - vector3(0.0001, 0.0001, 0.0001), 0, false, GetHashKey(Config.FlareName), 0, true, false, -1.0) DetachEntity(parachute, true, true) DeleteEntity(parachute) StopSound(soundID) ReleaseSoundId(soundID) for i = 1, #Config.LoadModels do Wait(0) SetModelAsNoLongerNeeded(GetHashKey(Config.LoadModels[i])) end RemoveWeaponAsset(GetHashKey(Config.FlareName)) end) end) end RegisterNetEvent("qb-gunheist:crate:createQbTarget") AddEventHandler("qb-gunheist:crate:createQbTarget", function(crate, item, amount) exports[Config.TargetName]:AddTargetModel('ex_prop_adv_case_sm', { options = { { icon = Config.TargetIcon, label = Config.TargetLabel, action = function(entity) OpenCrate(entity, crate, item, amount) end, } }, distance = 2.5, }) end) -- notify police functions function PoliceAlert() -- exports['ps-dispatch']:AirDrop() end -- Give random item from given list of the item used function GetRandomItemData(item) if Config.ItemDrops[item] then local Items = Config.ItemDrops[item] local randomItem = Items[math.random(#Items)] return randomItem["name"], randomItem["amount"] end end -- Start the AirDrop RegisterNetEvent("qb-gunheist:client:StartDrop", function(item, amount, roofCheck, planeSpawnDistance, dropCoords) CreateThread(function() if dropCoords.x and dropCoords.y and dropCoords.z and tonumber(dropCoords.x) and tonumber(dropCoords.y) and tonumber(dropCoords.z) then else dropCoords = {0.0, 0.0, 72.0} end RequestWeaponAsset(GetHashKey(Config.FlareName)) while not HasWeaponAssetLoaded(GetHashKey(Config.FlareName)) do Wait(0) end ShootSingleBulletBetweenCoords(GetEntityCoords(PlayerPedId()), GetEntityCoords(PlayerPedId()) - vector3(0.0001, 0.0001, 0.0001), 0, false, GetHashKey(Config.FlareName), 0, true, false, -1.0) TriggerServerEvent('dropCoords:server:setPoly', dropCoords) if roofCheck and roofCheck ~= "false" then local ray = StartShapeTestRay(vector3(dropCoords.x, dropCoords.y, dropCoords.z) + vector3(0.0, 0.0, 500.0), vector3(dropCoords.x, dropCoords.y, dropCoords.z), -1, -1, 0) local _, hit, impactCoords = GetShapeTestResult(ray) if hit == 0 or (hit == 1 and #(vector3(dropCoords.x, dropCoords.y, dropCoords.z) - vector3(impactCoords)) < 10.0) then CrateDrop(item, amount, planeSpawnDistance, dropCoords) else return end else CrateDrop(item, amount, planeSpawnDistance, dropCoords) end end) end) RegisterNetEvent('dropCoords:client:setPoly', function(dropCoords) local radiusBlipSize = 175.0 -- Create blip at dropCoords dropBlip = AddBlipForCoord(dropCoords.x, dropCoords.y, dropCoords.z) SetBlipSprite(dropBlip, 94) SetBlipColour(dropBlip, 1) SetBlipAsShortRange(dropBlip, true) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Airdrop") EndTextCommandSetBlipName(dropBlip) -- Create radius blip around dropCoords radiusBlip = AddBlipForRadius(dropCoords.x, dropCoords.y, dropCoords.z, radiusBlipSize) SetBlipColour(radiusBlip, 1) SetBlipAlpha(radiusBlip, 80) DropZone = BoxZone:Create(vector3(dropCoords.x, dropCoords.y, dropCoords.z), 175.0, 175.0, { name="AtDrop", heading=335.31, minZ=dropCoords.z-10, maxZ=dropCoords.z+100, debugPoly = false }) DropZone:onPlayerInOut(function(isPointInside) if isPointInside then QBCore.Functions.Notify("Du er i dropzonen. Hver mand for sig selv.", "error") else end end) end) RegisterNetEvent('qb-gunheist:crate:destroyzone', function() SetTimeout(200000, function() DropZone:destroy() RemoveBlip(dropBlip) RemoveBlip(radiusBlip) end) end) -- Create the AirDrop RegisterNetEvent("qb-gunheist:client:CreateDrop", function(useditem, roofCheck, planeSpawnDistance) local playerCoords = GetOffsetFromEntityInWorldCoords(PlayerPedId(), 0.0, 10.0, 0.0) local item, amount = GetRandomItemData(useditem) QBCore.Functions.TriggerCallback("qb-gunheist:server:cooldown", function(cooldown) if not cooldown then QBCore.Functions.TriggerCallback("qb-gunheist:server:getCops", function(CurrentCops) if CurrentCops >= Config.RequiredCops then TriggerServerEvent('qb-gunheist:server:startCooldown') QBCore.Functions.Notify(Config.Lang["pilot_contact"], "success", 10000) PoliceAlert() TriggerServerEvent("qb-gunheist:server:ItemHandler", "remove", useditem, 1) TriggerEvent("qb-gunheist:client:StartDrop", item, amount, roofCheck or false, planeSpawnDistance or 400.0, vector3(playerCoords.x, playerCoords.y, playerCoords.z)) else QBCore.Functions.Notify(Config.Lang["no_cops"], "error") end end) else QBCore.Functions.Notify("Der er for mange ting i luftrummet.", "error") end end) end) -- On resource stop do things AddEventHandler("onResourceStop", function(resource) if resource == GetCurrentResourceName() then SetEntityAsMissionEntity(pilot, false, true) DeleteEntity(pilot) SetEntityAsMissionEntity(aircraft, false, true) DeleteEntity(aircraft) DeleteEntity(parachute) DeleteEntity(crate) RemovePickup(pickup) RemoveBlip(blip) StopSound(soundID) ReleaseSoundId(soundID) for i = 1, #Config.LoadModels do Wait(0) SetModelAsNoLongerNeeded(GetHashKey(Config.LoadModels[i])) end end end)