Page cover

Open Files Preview

Here you can see the open files of the airdrop

config.lua
--[[ 
  _   _  _____     ___      ____   ____ ____  ___ ____ _____ ____  
 | \ | |/ _ \ \   / / \    / ___| / ___|  _ \|_ _|  _ \_   _/ ___| 
 |  \| | | | \ \ / / _ \   \___ \| |   | |_) || || |_) || | \___ \ 
 | |\  | |_| |\ V / ___ \   ___) | |___|  _ < | ||  __/ | |  ___) |
 |_| \_|\___/  \_/_/   \_\ |____/ \____|_| \_\___|_|    |_| |____/ 
                                                                                                                                                              
                 https://nova-scripting.tebex.io/ 
              https://nova-scripting.gitbook.io/docs 
]]  

-- ============================================================================
-- GLOBAL CONFIGURATION
-- ============================================================================

Locales = {}
Config = {}     

-- Debug Mode: Enable/disable console debug prints
Config.DebugMode = false -- Set to true to see debug messages in console

-- Framework Configuration
Config.Framework = 'esx' -- Choose your framework: 'esx', 'qbcore', 'qbox', or 'custom'
Config.Locale = 'en' -- Language: 'en' (English) or 'nl' (Dutch)

-- ============================================================================
-- AIRDROP CORE SETTINGS
-- ============================================================================

-- Airdrop Spawn Behavior
Config.AirdropGroundSpawn = false -- If true, airdrop spawns directly on ground (no plane/parachute)
Config.AirdropFallSpeed = 25.0 -- How fast the airdrop falls (1-100, only works when AirdropGroundSpawn = false)
Config.AirDropInRadius = true -- If true, airdrop drops randomly within the location radius

-- Visual Effects
Config.SmokeEffect = true -- Enable smoke/flare effect at airdrop location

-- Timing Settings
Config.AutoSpawn = { 
    enabled = true, -- Enable automatic airdrop spawning
    time = 30 * 60 -- Time between auto spawns in seconds (30 minutes)
}
Config.AirdropLock = { 
    enabled = true, -- Lock airdrop for a period after landing
    time = 25 -- Lock duration in seconds
}
Config.AirdropRemoveTime = 15 * 60 -- Time before airdrop self-destructs in seconds (15 minutes)

-- ============================================================================
-- INTERACTION SETTINGS
-- ============================================================================

-- Target System
Config.Use_Target = true -- Use target system for interaction (ox_target or qb-target)
Config.Target = "ox_target" -- Choose target system: "ox_target" or "qb-target"

-- Inventory System
Config.Ox_Inventory = false -- Enable ox_inventory stash system (requires ox_inventory)

-- ============================================================================
-- COMMAND CONFIGURATION
-- ============================================================================

Config.Command = {
    enabled = true, -- Enable /airdrop command
    name = "airdrop", -- Command name (without /)
    description = "Spawn an airdrop at a random location", -- Command description shown in help
    allowedRoles = {
        "admin", 
        "superadmin"
    }, -- Roles that can use the command (ESX groups)
    allowedJobs = {
        --'exampleJob' -- Jobs that can use the command (leave empty for no job restriction)
    }, 
    cooldown = 300 -- Cooldown between command uses in seconds (5 minutes)
}

-- ============================================================================
-- FLARE ITEM CONFIGURATION
-- ============================================================================

Config.FlareItem = {
    enabled = true, -- Enable flare item functionality
    itemName = "flare", -- Item name that can be used to call airdrop
    animation = {
        enabled = true, -- Enable animation when using flare
        dict = "amb@world_human_clipboard@male@idle_a", -- Animation dictionary
        anim = "idle_c", -- Animation name
        duration = 4000, -- Animation duration in milliseconds
        prop = {
            enabled = true, -- Enable flare prop in hand during animation
            model = "w_am_flare", -- Flare prop model
            bone = 28422, -- Hand bone to attach prop to (28422 = right hand)
            offset = { x = 0.0, y = 0.0, z = 0.0 }, -- Prop position offset
            rotation = { x = 0.0, y = -15.0, z = 0.0 } -- Prop rotation in degrees
        }
    }
}

-- ============================================================================
-- PLANE CONFIGURATION
-- ============================================================================

Config.Plane = {
    distance = 1000, -- Spawn distance from drop location (will be clamped to 1000-2000)
    speed = 50.0, -- Flight speed (will be clamped to 20-100)
}

-- ============================================================================
-- MODEL CONFIGURATION
-- ============================================================================

Config.Models = {
    -- Entity Models
    crate = "xm_prop_rsply_crate04a", -- Airdrop crate model
    parachute = "p_parachute1_mp_dec", -- Parachute model
    plane = "titan", -- Plane model
    npc_pilot = "s_m_m_pilot_01", -- Pilot model
    
    -- Parachute Attachment Settings
    parachuteOffset = { x = 0.0, y = 0.0, z = 4.0 }, -- Offset from crate center
    parachuteRotation = { x = 0.0, y = 0.0, z = 0.0 }, -- Rotation in degrees
    parachuteScale = 1.0 -- Scale of the parachute
}

-- ============================================================================
-- BLIP CONFIGURATION
-- ============================================================================

Config.blips = {
    main = { 
        ['enabled'] = true, -- Enable main airdrop blip
        ['scale'] = 1.2, -- Blip size
        ['blipId'] = 568, -- Blip icon ID
        ['color'] = 81, -- Blip color
        ['type'] = 6, -- Blip display type
        ['name'] = "Airdrop" -- Blip name
    },
    radius = { 
        ['enabled'] = true, -- Enable radius blip (only shown if location has radius > 0)
        ['color'] = 81, -- Radius blip color
        ['alpha'] = 100 -- Radius blip transparency
    },
}

-- ============================================================================
-- LOCATION CONFIGURATION
-- ============================================================================

Config.Locations = {
    -- Airdrop spawn locations with coordinates and drop radius
    [1] = { coords = vector3(3678.45, 4983.75, 15.83), radius = 50.0}, -- North area
    [2] = { coords = vector3(1450.03, 4408.11, 46.77), radius = 50.0}, -- Mountain area
    [3] = { coords = vector3(112.3445, 6827.7622, 17.0759), radius = 80.0}, -- Beach area
    [4] = { coords = vector3(2504.6265, 3264.5303, 52.1214), radius = 50.0}, -- Forest area
    [5] = { coords = vector3(1573.6575, 3196.3611, 40.5308), radius = 70.0}, -- Desert area
    [6] = { coords = vector3(334.0565, 2849.8423, 43.4093), radius = 60.0}, -- Rural area
    [7] = { coords = vector3(-2171.0454, 3063.4260, 32.9654), radius = 60.0}, -- Military area
    [8] = { coords = vector3(-1334.5094, -3040.9614, 13.9444), radius = 100.0}, -- Airport area
    [9] = { coords = vector3(1373.5991, -745.4987, 67.2328), radius = 60.0}, -- City outskirts
    [10] = { coords = vector3(3517.1577, 3789.0044, 29.9937), radius = 60.0}, -- Industrial area
}

-- ============================================================================
-- LOOT CONFIGURATION
-- ============================================================================

Config.Loot = {
    -- Medical Supplies Category
    [1] = {
        ['label'] = "Medical", 
        ['loot'] = { 
            {ItemName = "bandage", Min = 5, Max = 10, Chance = 100}, -- 100% chance, 5-10 items
            {ItemName = "medikit", Min = 5, Max = 10, Chance = 50}, -- 50% chance, 5-10 items
        },
    },
    
    -- Weapons Category
    [2] = {
        ['label'] = "Weapons",
        ['loot'] = { 
            {ItemName = "weapon_pistol", Min = 5, Max = 10, Chance = 100}, -- 100% chance, 5-10 items
            {ItemName = "weapon_pistol50", Min = 5, Max = 10, Chance = 50}, -- 50% chance, 5-10 items
        },
    },
    
    -- Drugs Category
    [3] = {
        ['label'] = "Drugs", 
        ['loot'] = {
            {ItemName = "weed", Min = 5, Max = 10, Chance = 100}, -- 100% chance, 5-10 items
            {ItemName = "coke", Min = 5, Max = 10, Chance = 50}, -- 50% chance, 5-10 items
        },
    },
    
    -- Example of how to add more categories:
    --[4] = {
    --  ['label'] = "Choose a name", 
    --  ['loot'] = {
    --      {ItemName = "itemname", Min = 1, Max = 2, Chance = 100}, -- (itemname, min, max, chance in %)
    --      {ItemName = "itemname", Min = 5, Max = 10, Chance = 50},
    --    },
    --},
}
client-utils.lua
function notification(title, text, time, type)
    TriggerEvent('nv-airdrop:client:DefaultNotify', title, text, time, type)
end

RegisterNetEvent('nv-airdrop:client:DefaultNotify')
AddEventHandler('nv-airdrop:client:DefaultNotify', function(title, text, time, type)
        SetNotificationTextEntry("STRING")
        AddTextComponentString(text)
        DrawNotification(0,1)

        -- exports['mdev-notify']:SendNotify(title, text, time, type)

        -- Default ESX Notify:
        -- TriggerEvent('esx:showNotification', text)

        -- Default QB Notify:
        --TriggerEvent('QBCore:Notify', text, 'info', 5000)

        -- OKOK Notify:
        -- exports['okokNotify']:Alert(title, text, time, type, false)
end)

function showhelptext(text) 
    SetTextComponentFormat('STRING') 
    AddTextComponentString(text)
    DisplayHelpTextFromStringLabel(0, 0, 1, -1) 
end

function Draw3DText(x, y, z, scl_factor, text)
    local onScreen, _x, _y = World3dToScreen2d(x, y, z + 1.0)
    local p = GetGameplayCamCoords()
    local distance = GetDistanceBetweenCoords(p.x, p.y, p.z, x, y, z + 1.0, 1)
    local scale = (1 / distance) * 2
    local fov = (1 / GetGameplayCamFov()) * 100
    local scale = scale * fov * scl_factor
    if onScreen then
        SetTextScale(0.0, scale)
        SetTextFont(4)
        SetTextProportional(1)
        SetTextColour(255, 255, 255, 215)
        SetTextDropshadow(0, 0, 0, 0, 255)
        SetTextEdge(2, 0, 0, 0, 150)
        SetTextDropShadow()
        SetTextOutline()
        SetTextEntry("STRING")
        SetTextCentre(1)
        AddTextComponentString(text)
        DrawText(_x, _y)
    end
end

-- Debug print function
function debugPrint(message, color)
    if Config.DebugMode then
        color = color or "^3" -- Default to yellow if no color specified
        print(color .. "[Nova Airdrop Debug] ^7" .. message)
    end
end
server-utils.lua
function notification(source, title, text, time, type)
    TriggerClientEvent('nv-airdrop:client:DefaultNotify', source, title, text, time, type)
end

-- Debug print function (only shows when Config.DebugMode is true)
function debugPrint(message, color)
    if Config.DebugMode then
        color = color or "^3" -- Default to yellow if no color specified
        print(color .. "[Nova Airdrop Debug] ^7" .. message)
    end
end
framework/server-framework.lua
Framework = nil

if Config['Framework']:upper() == 'ESX' then
    Framework = exports['es_extended']:getSharedObject()

    RegisterServerCallback = Framework.RegisterServerCallback
    GetPlayerFromId = Framework.GetPlayerFromId
    RegisterUsableItem = Framework.RegisterUsableItem

   function GetName(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return "Unknown" end
        return xPlayer.getName()
    end

    function isInGroup(source, groupList)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return false end
        local playerGroup = xPlayer.getGroup()
        for _, group in ipairs(groupList) do
            if group == playerGroup then
                return true
            end
        end
        return false
    end

    function GetPlayersFunction()
        return Framework.GetPlayers()
    end

    function GetPlayerJobFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        local PlayerJob = xPlayer.job.name
        return PlayerJob
    end

    function AddMoneyFunction(source, type, amount)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return end
        xPlayer.addAccountMoney(type, amount)
    end

    function RemoveMoneyFunction(source, type, amount)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return end
        xPlayer.removeAccountMoney(type, amount)
    end

    function GetMoneyFunction(source, type)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return 0 end
        return xPlayer.getAccount(type).money
    end

    function GetIdentifierFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        return xPlayer.identifier
    end

    function AddItemFunction(source, itemName, amount)
        local xPlayer = GetPlayerFromId(source)
        if xPlayer then
            xPlayer.addInventoryItem(itemName, amount)
            return true
        end
        return false
    end
elseif Config['Framework']:upper() == 'QBCORE' then
    Framework = exports['qb-core']:GetCoreObject()

    RegisterServerCallback = Framework.Functions.CreateCallback
    GetPlayerFromId = Framework.Functions.GetPlayer
    RegisterUsableItem = Framework.Functions.CreateUseableItem

    function GetName(source)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return "Unknown" end
        return xPlayer.Functions.GetName()
    end

    function isInGroup(source, groupList)
        for _, group in ipairs(groupList) do
            if Framework.Functions.HasPermission(source, group) then
                return true
            end
        end
        return false
    end

    function GetPlayersFunction()
        return Framework.Functions.GetPlayers()
    end

    function GetPlayerJobFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        local PlayerJob = xPlayer.PlayerData.job.name
        return PlayerJob
    end

    function AddMoneyFunction(source, type, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return end
        xPlayer.Functions.AddMoney(type, amount)
    end

    function RemoveMoneyFunction(source, type, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return end
        xPlayer.Functions.RemoveMoney(type, amount) 
    end

    function GetMoneyFunction(source, type)
        local xPlayer = Framework.Functions.GetPlayer(source) 
        if not xPlayer then return 0 end
        return xPlayer.Functions.GetMoney(type) 
    end

    function GetIdentifierFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        return xPlayer.PlayerData.citizenid
    end

    function AddItemFunction(source, itemName, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if xPlayer then
            xPlayer.Functions.AddItem(itemName, amount)
            return true
        end
        return false
    end
elseif Config['Framework']:upper() == 'QBOX' then
    Framework = exports['qbox-core']:GetCoreObject()

    RegisterServerCallback = Framework.Functions.CreateCallback
    GetPlayerFromId = Framework.Functions.GetPlayer
    RegisterUsableItem = Framework.Functions.CreateUseableItem

    function GetName(src)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return "Unknown" end
        return xPlayer.Functions.GetName()
    end

    function isInGroup(src, groupList)
        for _, group in ipairs(groupList) do
            if Framework.Functions.HasPermission(src, group) then
                return true
            end
        end
        return false
    end

    function GetPlayersFunction()
        return Framework.Functions.GetPlayers()
    end

    function GetPlayerJobFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        local PlayerJob = xPlayer.PlayerData.job.name
        return PlayerJob
    end

    function AddMoneyFunction(source, type, amount)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return end
        xPlayer.Functions.AddMoney(type, amount)
    end

    function RemoveMoneyFunction(source, type, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return end
        xPlayer.Functions.RemoveMoney(type, amount) 
    end

    function GetMoneyFunction(source, type)
        local xPlayer = Framework.Functions.GetPlayer(source) 
        if not xPlayer then return 0 end
        return xPlayer.Functions.GetMoney(type) 
    end
    
    function GetIdentifierFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        return xPlayer.PlayerData.citizenid
    end

    function AddItemFunction(source, itemName, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if xPlayer then
            xPlayer.Functions.AddItem(itemName, amount)
            return true
        end
        return false
    end

elseif Config['Framework']:upper() == 'CUSTOM' then
    -- Uncomment the following lines if you have a custom framework

    --[[Framework = exports['custom-framework']:GetCoreObject()

    RegisterServerCallback = Framework.Functions.CreateCallback
    GetPlayerFromId = Framework.Functions.GetPlayer
    RegisterUsableItem = Framework.Functions.CreateUseableItem

    function GetName(src)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return "Unknown" end
        return xPlayer.Functions.GetName()
    end

    function isInGroup(src, groupList)
        for _, group in ipairs(groupList) do
            if Framework.Functions.HasPermission(src, group) then
                return true
            end
        end
        return false
    end

    function GetPlayersFunction()
        return Framework.Functions.GetPlayers()
    end

    function GetPlayerJobFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        local PlayerJob = xPlayer.PlayerData.job.name
        return PlayerJob
    end

    function AddMoneyFunction(source, type, amount)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return end
        xPlayer.Functions.AddMoney(type, amount)
    end

    function RemoveMoneyFunction(source, type, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if not xPlayer then return end
        xPlayer.Functions.RemoveMoney(type, amount) 
    end

    function GetMoneyFunction(source, type)
        local xPlayer = Framework.Functions.GetPlayer(source) 
        if not xPlayer then return 0 end
        return xPlayer.Functions.GetMoney(type) 
    end
    
    function GetIdentifierFunction(source)
        local xPlayer = GetPlayerFromId(source)
        if not xPlayer then return nil end
        return xPlayer.PlayerData.citizenid
    end

    function AddItemFunction(source, itemName, amount)
        local xPlayer = Framework.Functions.GetPlayer(source)
        if xPlayer then
            xPlayer.Functions.AddItem(itemName, amount)
            return true
        end
        return false
    end --]]

    print('Custom framework support is not implemented yet. Please implement your custom framework logic.')
else
    print('Invalid framework specified in Config.lua. Please check your configuration.')
end
framework/client-framework.lua
Framework = nil

if Config['Framework']:upper() == 'ESX' then
    Framework = exports['es_extended']:getSharedObject()
    TriggerServerCallback = Framework.TriggerServerCallback

    -- //Functions\\ --
    function GetPlayerData()
        return Framework.GetPlayerData()
    end

    function GetIdentifierFunction()
        local xPlayer = GetPlayerData()
        return xPlayer.identifier
    end
elseif Config['Framework']:upper() == 'QBCORE' then
    Framework = exports['qb-core']:GetCoreObject()
    TriggerServerCallback = Framework.Functions.TriggerCallback

    -- //Functions\\ --
    function GetPlayerData()
        return Framework.Functions.GetPlayerData()
    end

    function GetIdentifierFunction()
        local xPlayer = GetPlayerData()
        return xPlayer.citizenid
    end
elseif Config['Framework']:upper() == 'QBOX' then
    Framework = exports['qbox-core']:GetCoreObject()
    TriggerServerCallback = Framework.Functions.TriggerCallback

    -- //Functions\\ --
    function GetPlayerData()
        return Framework.Functions.GetPlayerData()
    end

    function GetIdentifierFunction()
        local xPlayer = GetPlayerData()
        return xPlayer.citizenid
    end
elseif Config['Framework']:upper() == 'CUSTOM' then
    -- Uncomment the following lines if you have a custom framework

    --[[ Framework = exports['custom-framework']:GetCoreObject()
 TriggerServerCallback = Framework.Functions.TriggerCallback

     -- //Functions\\ --
     function GetPlayerData()
        return Framework.Functions.GetPlayerData()
    end

     function GetIdentifierFunction()
         local xPlayer = GetPlayerData()
         return xPlayer.citizenid
     end --]]
    debugPrint('Custom framework support is not implemented yet. Please implement your custom framework logic.', "^1")
else
    debugPrint('Invalid framework specified in Config.lua. Please check your configuration.', "^1")
end

Last updated