share
did you manage to add the blip
I have not, i need to get back to work on it. i’ve been off to long.
Code
local pilot, aircraft, parachute, crate, pickup, blip, soundID
local requiredModels = {“p_cargo_chute_s”, “ex_prop_adv_case_sm”, “cuban800”, “s_m_m_pilot_02”, “prop_box_wood02a_pu”} – parachute, pickup case, plane, pilot, crate
RegisterCommand(“cratedrop”, function(playerServerID, args, rawString)
local playerCoords = GetOffsetFromEntityInWorldCoords(PlayerPedId(), 0.0, 10.0, 0.0) – ISN’T THIS A TABLE ALREADY?
TriggerEvent(“crateDrop”, args[1], tonumber(args[2]), args[3] or false, args[4] or 400.0, {[“x”] = playerCoords.x, [“y”] = playerCoords.y, [“z”] = playerCoords.z})
end, false)
RegisterNetEvent(“crateDrop”)
AddEventHandler(“crateDrop”, function(weapon, ammo, roofCheck, planeSpawnDistance, dropCoords) – all of the error checking is done here before passing the parameters to the function itself
Citizen.CreateThread(function()
if IsWeaponValid(GetHashKey(weapon)) then -- only supports weapon pickups for now, use the function directly to bypass this
weapon = "pickup_" .. weapon
-- print("WEAPON VALIDITY: true, after concatenating 'pickup_'")
elseif IsWeaponValid(GetHashKey("weapon_" .. weapon)) then
weapon = "pickup_weapon_" .. weapon
-- print("WEAPON VALIDITY: true, after concatenating 'pickup_weapon_'")
elseif IsWeaponValid(GetHashKey(weapon:sub(8))) then
-- print("WEAPON VALIDITY: true")
else
-- print("WEAPON VALIDITY: false")
return
end
-- print("WEAPON: " .. string.lower(weapon))
local ammo = (ammo and tonumber(ammo)) or 250
if ammo > 9999 then
ammo = 9999
elseif ammo < -1 then
ammo = -1
end
-- print("AMMO: " .. ammo)
if dropCoords.x and dropCoords.y and dropCoords.z and tonumber(dropCoords.x) and tonumber(dropCoords.y) and tonumber(dropCoords.z) then
-- print(("DROP COORDS: success, X = %.4f; Y = %.4f; Z = %.4f"):format(dropCoords.x, dropCoords.y, dropCoords.z))
else
dropCoords = {0.0, 0.0, 72.0}
-- print("DROP COORDS: fail, defaulting to X = 0; Y = 0")
end
if roofCheck and roofCheck ~= "false" then -- if roofCheck is not false then a check will be performed if a plane can drop a crate to the specified location before actually spawning a plane, if it can't, function won't be called
-- print("ROOFCHECK: true")
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)
-- print("HIT: " .. hit)
-- print(("IMPACT COORDS: X = %.4f; Y = %.4f; Z = %.4f"):format(impactCoords.x, impactCoords.y, impactCoords.z))
-- print("DISTANCE BETWEEN DROP AND IMPACT COORDS: " .. #(vector3(dropCoords.x, dropCoords.y, dropCoords.z) - vector3(impactCoords)))
if hit == 0 or (hit == 1 and #(vector3(dropCoords.x, dropCoords.y, dropCoords.z) - vector3(impactCoords)) < 10.0) then -- ± 10 units
-- print("ROOFCHECK: success")
CrateDrop(weapon, ammo, planeSpawnDistance, dropCoords)
else
-- print("ROOFCHECK: fail")
return
end
else
-- print("ROOFCHECK: false")
CrateDrop(weapon, ammo, planeSpawnDistance, dropCoords)
end
end)
end)
function CrateDrop(weapon, ammo, planeSpawnDistance, dropCoords)
Citizen.CreateThread(function()
for i = 1, #requiredModels do
RequestModel(GetHashKey(requiredModels[i]))
while not HasModelLoaded(GetHashKey(requiredModels[i])) do
Wait(0)
end
end
--[[
RequestAnimDict("P_cargo_chute_S")
while not HasAnimDictLoaded("P_cargo_chute_S") do -- wasn't able to get animations working
Wait(0)
end
]]
RequestWeaponAsset(GetHashKey("weapon_flare")) -- flare won't spawn later in the script if we don't request it right now
while not HasWeaponAssetLoaded(GetHashKey("weapon_flare")) do
Wait(0)
end
local rHeading = math.random(0, 360) + 0.0
local planeSpawnDistance = (planeSpawnDistance and tonumber(planeSpawnDistance) + 0.0) or 400.0 -- this defines how far away the plane is spawned
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) -- the plane is spawned at
-- print(("PLANE COORDS: X = %.4f; Y = %.4f; Z = %.4f"):format(rPlaneSpawn.x, rPlaneSpawn.y, rPlaneSpawn.z))
-- print("PLANE SPAWN DISTANCE: " .. #(vector2(rPlaneSpawn.x, rPlaneSpawn.y) - vector2(dropCoords.x, dropCoords.y)))
local dx = dropCoords.x - rPlaneSpawn.x
local dy = dropCoords.y - rPlaneSpawn.y
local heading = GetHeadingFromVector_2d(dx, dy) -- determine plane heading from coordinates
aircraft = CreateVehicle(GetHashKey("cuban800"), rPlaneSpawn, heading, true, true)
SetEntityHeading(aircraft, heading)
SetVehicleDoorsLocked(aircraft, 2) -- lock the doors so pirates don't get in
SetEntityDynamic(aircraft, true)
ActivatePhysics(aircraft)
SetVehicleForwardSpeed(aircraft, 60.0)
SetHeliBladesFullSpeed(aircraft) -- works for planes I guess
SetVehicleEngineOn(aircraft, true, true, false)
ControlLandingGear(aircraft, 3) -- retract the landing gear
OpenBombBayDoors(aircraft) -- opens the hatch below the plane for added realism
SetEntityProofs(aircraft, true, false, true, false, false, false, false, false)
pilot = CreatePedInsideVehicle(aircraft, 1, GetHashKey("s_m_m_pilot_02"), -1, true, true)
SetBlockingOfNonTemporaryEvents(pilot, true) -- ignore explosions and other shocking events
SetPedRandomComponentVariation(pilot, false)
SetPedKeepTask(pilot, true)
SetPlaneMinHeightAboveTerrain(aircraft, 50) -- the plane shouldn't dip below the defined altitude
TaskVehicleDriveToCoord(pilot, aircraft, vector3(dropCoords.x, dropCoords.y, dropCoords.z) + vector3(0.0, 0.0, 500.0), 60.0, 0, GetHashKey("cuban800"), 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 for when the plane reaches the dropCoords ± 5 units
Wait(100)
planeLocation = vector2(GetEntityCoords(aircraft).x, GetEntityCoords(aircraft).y) -- update plane coords for the loop
end
if IsEntityDead(pilot) then -- I think this will end the script if the pilot dies, no idea how to return works
print("PILOT: dead")
do return end
end
TaskVehicleDriveToCoord(pilot, aircraft, 0.0, 0.0, 500.0, 60.0, 0, GetHashKey("cuban800"), 262144, -1.0, -1.0) -- disposing of the plane like Rockstar does, send it to 0; 0 coords with -1.0 stop range, so the plane won't be able to achieve its task
SetEntityAsNoLongerNeeded(pilot)
SetEntityAsNoLongerNeeded(aircraft)
local crateSpawn = vector3(dropCoords.x, dropCoords.y, GetEntityCoords(aircraft).z - 5.0) -- crate will drop to the exact position as planned, not at the plane's current position
crate = CreateObject(GetHashKey("prop_box_wood02a_pu"), crateSpawn, true, true, true) -- a breakable crate to be spawned directly under the plane, probably could be spawned closer to the plane
SetEntityLodDist(crate, 1000) -- so we can see it from the distance
ActivatePhysics(crate)
SetDamping(crate, 2, 0.1) -- no idea but Rockstar uses it
SetEntityVelocity(crate, 0.0, 0.0, -0.2) -- I think this makes the crate drop down, not sure if it's needed as many times in the script as I'm using
parachute = CreateObject(GetHashKey("p_cargo_chute_s"), crateSpawn, true, true, true) -- create the parachute for the crate, location isn't too important as it'll be later attached properly
SetEntityLodDist(parachute, 1000)
SetEntityVelocity(parachute, 0.0, 0.0, -0.2)
-- PlayEntityAnim(parachute, "P_cargo_chute_S_deploy", "P_cargo_chute_S", 1000.0, false, false, false, 0, 0)
-- ForceEntityAiAndAnimationUpdate(parachute)
pickup = CreateAmbientPickup(GetHashKey(weapon), crateSpawn, 0, ammo, GetHashKey("ex_prop_adv_case_sm"), true, true) -- create the pickup itself, location isn't too important as it'll be later attached properly
ActivatePhysics(pickup)
SetDamping(pickup, 2, 0.0245)
SetEntityVelocity(pickup, 0.0, 0.0, -0.2)
soundID = GetSoundId() -- we need a sound ID for calling the native below, otherwise we won't be able to stop the sound later
PlaySoundFromEntity(soundID, "Crate_Beeps", pickup, "MP_CRATE_DROP_SOUNDS", true, 0) -- crate beep sound emitted from the pickup
blip = AddBlipForEntity(pickup)
SetBlipSprite(blip, 408) -- 351 or 408 are both fine, 408 is just bigger
SetBlipNameFromTextFile(blip, "AMD_BLIPN")
SetBlipScale(blip, 0.7)
SetBlipColour(blip, 2)
SetBlipAlpha(blip, 120) -- blip will be semi-transparent
-- local crateBeacon = StartParticleFxLoopedOnEntity_2("scr_crate_drop_beacon", pickup, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 1065353216, 0, 0, 0, 1065353216, 1065353216, 1065353216, 0)--1.0, false, false, false)
-- SetParticleFxLoopedColour(crateBeacon, 0.8, 0.18, 0.19, false)
AttachEntityToEntity(parachute, pickup, 0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, false, false, false, false, 2, true) -- attach the crate to the pickup
AttachEntityToEntity(pickup, crate, 0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, false, false, true, false, 2, true) -- attach the pickup to the crate, doing it in any other order makes the crate drop spazz out
while HasObjectBeenBroken(crate) == false do -- wait till the crate gets broken (probably on impact), then continue with the script
Wait(0)
end
local parachuteCoords = vector3(GetEntityCoords(parachute)) -- we get the parachute dropCoords so we know where to drop the flare
ShootSingleBulletBetweenCoords(parachuteCoords, parachuteCoords - vector3(0.0001, 0.0001, 0.0001), 0, false, GetHashKey("weapon_flare"), 0, true, false, -1.0) -- flare needs to be dropped with dropCoords like that, otherwise it remains static and won't remove itself later
DetachEntity(parachute, true, true)
-- SetEntityCollision(parachute, false, true) -- pointless right now but would be cool if animations would work and you'll be able to walk through the parachute while it's disappearing
-- PlayEntityAnim(parachute, "P_cargo_chute_S_crumple", "P_cargo_chute_S", 1000.0, false, false, false, 0, 0)
DeleteEntity(parachute)
DetachEntity(pickup) -- will despawn on its own
SetBlipAlpha(blip, 255) -- make the blip fully visible
while DoesEntityExist(pickup) do -- wait till the pickup gets picked up, then the script can continue
Wait(0)
end
while DoesObjectOfTypeExistAtCoords(parachuteCoords, 10.0, GetHashKey("w_am_flare"), true) do
Wait(0)
local prop = GetClosestObjectOfType(parachuteCoords, 10.0, GetHashKey("w_am_flare"), false, false, false)
RemoveParticleFxFromEntity(prop)
SetEntityAsMissionEntity(prop, true, true)
DeleteObject(prop)
end
if DoesBlipExist(blip) then -- remove the blip, should get removed when the pickup gets picked up anyway, but isn't a bad idea to make sure of it
RemoveBlip(blip)
end
StopSound(soundID) -- stop the crate beeping sound
ReleaseSoundId(soundID) -- won't need this sound ID any longer
for i = 1, #requiredModels do
Wait(0)
SetModelAsNoLongerNeeded(GetHashKey(requiredModels[i]))
end
RemoveWeaponAsset(GetHashKey("weapon_flare"))
end)
end
AddEventHandler(“onResourceStop”, function(resource)
if resource == GetCurrentResourceName() then
-- print("RESOURCE: stopped")
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, #requiredModels do
Wait(0)
SetModelAsNoLongerNeeded(GetHashKey(requiredModels[i]))
end
end
end)
can we delete the box breaking ?
How to make this auto drop crates at a certain time?
how do I open the crate to get the weapon?