config.lua

Config = {}

---------------------------------------------
-- Fiveous Drone | Setup
---------------------------------------------

Config.Setup = {
    framework      = 'qbcore',       -- 'qbcore'  (more coming soon)
    inventory      = 'tgiann',           -- 'ox' | 'tgiann'  (qb-inventory NOT supported — requires metadata)
    target         = 'qb-target',    -- 'qb-target' | 'ox_target'
    debug          = false,           -- Print debug messages to server console
    imageProvider  = 'fivemanage',   -- 'fivemanage' | 'fivemerr' | 'discord'
    -- Discord webhook URL (only used when imageProvider = 'discord')
    -- Note: Discord has a 25MB file limit; videos may fail if too large
    webhookUrl     = '',
}

---------------------------------------------
-- Fiveous Drone | Items
---------------------------------------------

Config.Items = {
    drone      = 'fiveous_drone',       -- Useable item: places drone on ground
    policeDrone = 'fiveous_police_drone',   -- Useable item: places police drone (requires police job)
    controller = 'fiveous_controller',   -- Useable item: pairs to placed drone & starts flight
    battery    = 'fiveous_battery',      -- Battery item: swappable, has charge metadata
    crashParts = 'fiveous_drone_parts',  -- Salvaged parts from a crashed/shot-down drone
}

---------------------------------------------
-- Fiveous Drone | Prop & Model
---------------------------------------------

Config.Drone = {
    model              = 'fiveous_drone',         -- Civilian drone prop
    policeModel        = 'fiveous_police_drone',         -- Police drone prop (can be different)
    crashModel         = 'fiveous_drone_broken',   -- Civilian broken prop at crash site
    policeCrashModel   = 'fiveous_police_drone_broken',   -- Police broken prop at crash site
    placeCooldown      = 5000,            -- Milliseconds between placing drones
    placeDistance       = 2.0,            -- Metres in front of player to place the drone
    placeGroundOffset  = -0.2,            -- Height offset from ground when placed
    startupTime        = 2000,           -- Milliseconds for "spin-up" before flight (visual delay)
    maxPairDistance     = 15.0,          -- Max metres from drone to pair with controller
}

---------------------------------------------
-- Fiveous Drone | Flight Physics
---------------------------------------------

Config.Flight = {
    defaultSpeed       = 0.50,           -- Base movement speed (metres per tick)
    fastMultiplier     = 1.5,            -- SHIFT speed multiplier
    slowMultiplier     = 0.3,            -- CTRL speed multiplier
    scrollSpeedStep    = 0.05,           -- Speed change per scroll tick
    minSpeed           = 0.02,           -- Minimum speed
    maxSpeed           = 1.0,            -- Maximum speed (absolute cap for all drones)
    trackingMaxSpeed   = 0.5,            -- Maximum speed while in PD Tracking mode
    verticalSpeed      = 0.18,           -- Up/down speed
    sensitivity        = 2.0,            -- Mouse look sensitivity
    smoothFactor       = 0.30,           -- Position lerp (0-1, higher = snappier)
    rotSmoothFactor    = 0.40,           -- Rotation lerp
    rollSpeed          = 1.2,            -- Camera roll speed (Q/E) degrees per tick
    maxTiltDeg         = 25.0,           -- Max visual tilt of drone when moving
    tiltLerp           = 0.12,           -- How fast the drone tilts
    hoverAmplitude     = 0.015,          -- Subtle hover bobbing (metres)
    hoverFrequency     = 2.0,            -- Bobbing speed (Hz)
    maxAltitude        = 250.0,          -- Maximum height above ground (metres, relative to terrain below)
    landingDescentSpeed = 0.02,          -- Speed when auto-landing (per frame, slow descent)
    maxRange           = 250.0,          -- Maximum distance from pilot (metres) — drone disconnects beyond this
    policeMaxRange     = 500.0,          -- Maximum range for police drones (metres)
    rangeWarning       = 0.80,           -- Fraction of maxRange to start warning (0.80 = warn at 400m)
    returnSpeed        = 15.0,           -- Speed (m/s) when drone auto-returns to home (horizontal)
    returnDescentSpeed = 5.0,            -- Speed (m/s) when drone descends at home during return
    returnMinAltitude  = 125.0,          -- Altitude AGL during return-to-home (metres above ground)
    returnAscendSpeed  = 8.0,            -- Speed (m/s) when drone climbs to safe altitude before RTH
}

---------------------------------------------
-- Fiveous Drone | Camera
---------------------------------------------

Config.Camera = {
    defaultFov         = 70.0,
    fovMin             = 10.0,
    fovMax             = 120.0,
    fovStep            = 2.0,
    attachOffset       = vector3(0.0, 0.0, 0.15),  -- Camera offset from drone centre
}

---------------------------------------------
-- Fiveous Drone | Battery
---------------------------------------------

Config.Battery = {
    enabled            = true,           -- Set to false to completely disable the battery system (infinite flight)
    drainRate          = 5.0,            -- Percent per minute during flight (idle / hovering) ~20min hover
    moveDrainMult      = 2.5,            -- Multiplier when moving at default speed (~8min flying)
    sprintDrainMult    = 5.0,            -- Multiplier when sprinting (SHIFT) (~4min at full speed)
    warningLevel       = 20,             -- Percent — orange warning
    criticalLevel      = 10,             -- Percent — red pulsing critical
    defaultCharge      = 100,            -- Default charge for new batteries/drones
}

---------------------------------------------
-- Fiveous Drone | Collision & Crash
---------------------------------------------

Config.Collision = {
    enabled            = true,           -- Detect collisions during flight (raycasts)
    crashOnCollision   = true,           -- true = drone crashes on impact, false = drone stops
    destroyOnCrash     = true,           -- Drone item is lost on crash (false = drone returns to inventory)
    probeDistance      = 2.0,            -- How far ahead to raycast (scaled by speed)
    crashThreshold     = 0.1,            -- Distance to surface that triggers collision (metres)
    groundPadding      = 0.4,            -- Min altitude above ground during flight
    -- Shape test flags: 1=world, 2=vehicles, 4=peds, 8=objects, 16=water, 256=vegetation
    traceFlags         = (1 + 2 + 4 + 8 + 16 + 256),
    crashExplosion     = true,           -- Small spark explosion on crash (requires crashOnCollision = true)
    crashExplosionType = 36,             -- GTA explosion type (36 = small, no damage)
    crashExplosionScale = 0.0,           -- Explosion damage radius (0 = visual only)
}

---------------------------------------------
-- Fiveous Drone | Player Animation
---------------------------------------------

Config.Animation = {
    -- Animation played while piloting the drone
    scenario           = 'WORLD_HUMAN_STAND_MOBILE',   -- Ped stands & holds phone (looks like controller)
    -- Alternative: set scenario to nil and use dict/anim for a custom animation
    dict               = nil,
    anim               = nil,
}

---------------------------------------------
-- Fiveous Drone | Sound
---------------------------------------------

Config.Sound = {
    enabled            = true,
    volume             = 1.0,             -- Base volume (0.0 - 1.0)
    maxDistance         = 80.0,            -- Max distance (metres) to hear a drone
}

---------------------------------------------
-- Fiveous Drone | Voice (pma-voice)
---------------------------------------------

Config.Voice = {
    droneProximity     = true,            -- Hear players near the drone while flying
    droneVoiceRange    = 20.0,            -- Range (metres) around drone to pick up voices
    defaultOutputDist  = 100.0,           -- pma-voice default output distance (restored on land)
}

---------------------------------------------
-- Fiveous Drone | HUD & Display
---------------------------------------------

Config.HUD = {
    showControls       = true,
    controlsFadeSec    = 10.0,           -- Seconds before control hints fade (0 = never)
    showSpeed          = true,
    showFov            = true,
    showAltitude       = true,

    -- External HUD toggle for cinematic mode
    -- Some HUD resources (e.g. wais-hudv6) use a single toggle export
    -- rather than separate show/hide, so we call the same export for both
    externalHud = {
        enabled    = true,                       -- Set false to disable external HUD toggling
        resource   = 'wais-hudv6',               -- Resource name to check / call exports on
        toggleOn   = 'showHud',                  -- Export to call when ENTERING cinematic (hides external HUD)
        toggleOff  = 'hideHud',                  -- Export to call when EXITING  cinematic (shows external HUD)
    },
}

---------------------------------------------
-- Fiveous Drone | Filters / Post-FX
---------------------------------------------

Config.Filters = {
    enabled = true,
    available = {
        -- Clean / Neutral
        { name = 'None',              timecycle = nil },
        { name = 'Natural',           timecycle = 'default' },
        { name = 'Soft HDR',          timecycle = 'MP_Powerplay_blend' },
        { name = 'Warm Daylight',     timecycle = 'MP_Bull_tost' },

        -- Cinematic / Film
        { name = 'Cinematic',         timecycle = 'cinema' },
        { name = 'Hollywood',         timecycle = 'MP_Heist_BigScore' },
        { name = 'Film Grain',        timecycle = 'NG_filmic01' },
        { name = 'Dramatic',          timecycle = 'NG_filmic07' },

        -- Color Styles
        { name = 'Vibrant',           timecycle = 'MP_Arena_theme_storm' },
        { name = 'Ultra Color',       timecycle = 'PSYCHEDELIC_kick_p2' },
        { name = 'Teal & Orange',     timecycle = 'MP_Powerplay' },
        { name = 'Pastel',            timecycle = 'MP_Powerplay_blend' },

        -- Dark / Gritty
        { name = 'Urban Grit',        timecycle = 'MP_lowgarage' },
        { name = 'Crime Scene',       timecycle = 'MP_death_grade_blend01' },
        { name = 'Bleached',          timecycle = 'NG_filmic09' },

        -- Weather / Mood
        { name = 'Cold Blue',         timecycle = 'MP_Celeb_Loss_Out' },
        { name = 'Rainy',             timecycle = 'MP_heli_cam' },
        { name = 'Foggy',             timecycle = 'NG_foggy_night' },
        { name = 'Vibrant',           timecycle = 'MP_Powerplay' },
        { name = 'Storm',             timecycle = 'MP_Arena_theme_storm' },

        -- Night / Neon
        { name = 'Night Film',        timecycle = 'NG_filmic08' },
        { name = 'Neon City',         timecycle = 'li' },
        { name = 'Cyberpunk',         timecycle = 'MP_Arena_theme_night' },
        { name = 'Night Vision Lite', timecycle = 'NG_filmnoir_BW01' },

        -- Vintage / Stylized
        { name = 'Sepia',             timecycle = 'bank_heist_sepia' },
        { name = 'Retro',             timecycle = 'NG_filmic02' },
        { name = 'Washed',            timecycle = 'NG_filmic04' },
    }
}

---------------------------------------------
-- Fiveous Drone | Target
---------------------------------------------

Config.Target = {
    pickupIcon         = 'fas fa-helicopter',
    pickupLabel        = 'Pick Up Drone',
    pickupDistance      = 2.5,
    connectIcon        = 'fas fa-wifi',
    connectLabel       = 'Connect to Drone',
    connectDistance     = 3.0,
    crashPickupIcon    = 'fas fa-screwdriver-wrench',
    crashPickupLabel   = 'Salvage Crashed Drone',
    crashPickupDistance = 2.5,
}

---------------------------------------------
-- Fiveous Drone | LB Integration
---------------------------------------------
-- Enable/disable LB-Phone and LB-Tablet app registration.
-- When disabled, those resources do NOT need to be installed.
-- The standalone controller UI (opened via the controller item) always works.

Config.Apps = {
    enablePhone  = true,    -- Register "Aero" app on lb-phone
    enableTablet = true,    -- Register "Aero" app on lb-tablet
}

---------------------------------------------
-- Fiveous Drone | No-Fly Zones
---------------------------------------------
-- Polygon zones where civilian drones CANNOT take off from or fly into.
-- Police drones (droneType == 'police') are EXEMPT from all no-fly restrictions.
--
-- Each zone is a table with:
--   name   = Display name (shown on the map UI)
--   color  = Hex colour for the map overlay (optional, defaults to red)
--   points = Ordered list of {x, y} vertices forming a closed polygon
--            (the last point auto-connects back to the first)
--
-- Example: a simple rectangular zone around the airport
-- You can use as many points as you like to create irregular shapes.

Config.NoFlyZones = {
    {
        name   = 'Los Santos Intl Airport',
        color  = '#F87171',
        points = {
            { x = -1399.0, y = -1969.0 },
            { x = -2181.0, y = -3164.0 },
            { x = -870.0,  y = -3882.0 },
            { x = -579.0,  y = -3192.0 },
            { x = -729.0,  y = -2876.0 },
            { x = -635.0,  y = -2550.0 },
        },
    },
    {
        name   = 'Fort Zancudo',
        color  = '#F87171',
        points = {
            { x = -2992.0, y = 3274.0 },
            { x = -2827.0, y = 3504.0 },
            { x = -2569.0, y = 3346.0 },
            { x = -2340.0, y = 3462.0 },
            { x = -2208.0, y = 3564.0 },
            { x = -1639.0, y = 3235.0 },
            { x = -1688.0, y = 3188.0 },
            { x = -1602.0, y = 2882.0 },
            { x = -1706.0, y = 2805.0 },
            { x = -1828.0, y = 2742.0 },
            { x = -2094.0, y = 2766.0 },
            { x = -2484.0, y = 2895.0 },
        },
    },
    -- Add more zones as needed:
    -- {
    --     name   = 'My Custom Zone',
    --     color  = '#60A5FA',
    --     points = {
    --         { x = 100.0, y = 200.0 },
    --         { x = 150.0, y = 300.0 },
    --         { x = 200.0, y = 250.0 },
    --     },
    -- },
}

---------------------------------------------
-- Fiveous Drone | Insurance
---------------------------------------------

Config.Insurance = {
    enabled = true,  -- Set to false to completely disable the insurance system
}

---------------------------------------------
-- Fiveous Drone | Police Drone
---------------------------------------------
-- Jobs (and minimum grades) allowed to use the police drone.
-- Each entry: { name = 'jobname', minGrade = 0 }
-- minGrade 0 means all grades can use it.

Config.PoliceJobs = {
    { name = 'police', minGrade = 0 },
    -- { name = 'sheriff', minGrade = 2 },
    -- { name = 'fbi', minGrade = 0 },
}

---------------------------------------------
-- Fiveous Drone | Skins (Civilian Only)
---------------------------------------------
-- Progression-based skin unlocks. Players must activate and complete each
-- challenge in order before moving to the next.  Progress is account-wide
-- (tied to citizenid, not per-drone) and persists across server restarts.
--
-- challenge types: 'distance' (miles), 'landings' (successful lands), 'photos'
-- The first skin (index 1) is always unlocked (the default prop).
-- Set enabled = false to completely disable the skin system.

Config.SkinsEnabled = true
Config.SkinsImageBase = 'nui://fiveous_drones/ui/images/skins/'

-- Inventory item images use the same path
Config.SkinsInventoryImageBase = Config.SkinsImageBase

Config.Skins = {
    { model = 'fiveous_drone',              broken = 'fiveous_drone_broken',              name = 'Standard',      color = '#94A3B8', challenge = nil },
    { model = 'fiveous_drone_red',          broken = 'fiveous_drone_red_broken',          name = 'Red',           color = '#EF4444', challenge = { type = 'distance', target = 10,   label = 'Fly 10 miles' } },
    { model = 'fiveous_drone_yellow',       broken = 'fiveous_drone_yellow_broken',       name = 'Yellow',        color = '#EAB308', challenge = { type = 'landings', target = 10,   label = '10 successful landings' } },
    { model = 'fiveous_drone_orange',       broken = 'fiveous_drone_orange_broken',       name = 'Orange',        color = '#F97316', challenge = { type = 'photos',   target = 10,   label = 'Take 10 photos' } },
    { model = 'fiveous_drone_green',        broken = 'fiveous_drone_green_broken',        name = 'Green',         color = '#22C55E', challenge = { type = 'distance', target = 40,   label = 'Fly 40 miles' } },
    { model = 'fiveous_drone_pink',         broken = 'fiveous_drone_pink_broken',         name = 'Pink',          color = '#EC4899', challenge = { type = 'landings', target = 40,   label = '40 successful landings' } },
    { model = 'fiveous_drone_purple',       broken = 'fiveous_drone_purple_broken',       name = 'Purple',        color = '#A855F7', challenge = { type = 'photos',   target = 25,  label = 'Take 25 photos' } },
    { model = 'fiveous_drone_blue',         broken = 'fiveous_drone_blue_broken',         name = 'Blue',          color = '#3B82F6', challenge = { type = 'distance', target = 75,  label = 'Fly 75 miles' } },
    { model = 'fiveous_drone_green_camo',   broken = 'fiveous_drone_green_camo_broken',   name = 'Green Camo',    color = '#4D7C0F', challenge = { type = 'landings', target = 75,  label = '75 successful landings' } },
    { model = 'fiveous_drone_black_camo',   broken = 'fiveous_drone_black_camo_broken',   name = 'Black Camo',    color = '#57534E', challenge = { type = 'photos',   target = 50,  label = 'Take 50 photos' } },
    { model = 'fiveous_drone_black',        broken = 'fiveous_drone_black_broken',        name = 'Black',         color = '#1E1E1E', challenge = { type = 'distance', target = 100,  label = 'Fly 100 miles' } },
    { model = 'fiveous_drone_gold',         broken = 'fiveous_drone_gold_broken',         name = 'Gold',          color = '#D4A017', challenge = { type = 'distance', target = 250,  label = 'Fly 250 miles' } },
    { model = 'fiveous_drone_diamond',      broken = 'fiveous_drone_diamond_broken',      name = 'Diamond',       color = '#67E8F9', challenge = { type = 'distance', target = 500,  label = 'Fly 500 miles' } },
    { model = 'fiveous_drone_diamond_gold', broken = 'fiveous_drone_diamond_gold_crashed', name = 'Diamond Gold', color = '#FCD34D', challenge = { type = 'distance', target = 1000, label = 'Fly 1,000 miles' } },
}

---------------------------------------------
-- Fiveous Drone | Entity Tracker (Police)
---------------------------------------------

Config.Tracker = {
    -- Mask detection: component index 1 = face masks/coverings
    -- If the player's drawable ID for component 1 is in this list, they are masked
    -- Masked players show limited data (no name/DOB), unmasked show full identity
    maskComponentIndex = 1,

    maskDrawables = {
        male = {
            2,3,4,5,6,7,8,9,10,11,14,15,17,19,20,21,22,30,37,39,40,42,43,44,45,47,48,
            54,55,56,58,59,60,61,69,70,71,72,79,80,81,82,83,84,85,86,87,88,90,91,92,93,
            94,95,96,97,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
            115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
            134,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,
            154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,172,173,
            174,175,177,178,179,180,181,185,186,187,188,189,190,191,192,193,194,195,196,
            197,198,199,200,201,202,203,204,205,206,208,209,210,211,212,213,214,215,216,
            217,218,219,220,221,222,223,224,225,226,227,229,230,231,232,233,234,235,236,
            237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
            256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,
            275,276,277,278,279,280,281,282,285,287,291,292,295,296,297,298,299,300,301,
            305,306,308,309,310,311,313,314,315,316,317,319,320,321,322,323,324,325,326,
            327,328,331,332,333,334,335,336,337,342,346,347,353,355,357,358,359,360,361,
        },
        female = {
            1,2,3,5,6,7,8,9,11,24,34,43,44,45,46,47,49,50,52,53,54,65,137,149,150,151,
            152,153,154,155,156,157,158,159,160,161,163,164,165,166,167,168,169,170,171,
            172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
            191,192,193,194,195,196,197,199,200,201,202,204,205,206,207,208,212,213,214,
            215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
            235,236,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,
            255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,
            274,275,276,277,278,280,281,282,283,284,285,286,287,288,289,290,291,292,293,
            294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,313,315,
            319,320,323,324,325,326,330,332,333,334,335,336,
        },
    },
}

---------------------------------------------
-- Fiveous Drone | Notifications (ox_lib)
---------------------------------------------

Config.Notify = {
    dronePlaced        = { title = 'Drone',  description = 'Drone deployed. Use your controller or walk up to the drone to connect.',  type = 'info',    duration = 5000 },
    pairing            = { title = 'Drone',  description = 'Pairing to drone...',                                         type = 'info',    duration = 2000 },
    flightStarted      = { title = 'Drone',  description = 'Drone active — you are now flying.',                          type = 'success', duration = 4000 },
    noDroneNearby      = { title = 'Drone',  description = 'No deployed drone nearby to pair with.',                      type = 'error',   duration = 3000 },
    alreadyPlaced      = { title = 'Drone',  description = 'You already have a drone deployed.',                          type = 'error',   duration = 3000 },
    alreadyFlying      = { title = 'Drone',  description = 'You are already flying a drone.',                             type = 'error',   duration = 3000 },
    crashed            = { title = 'Drone',  description = 'Your drone crashed!',                                         type = 'error',   duration = 4000 },
    landed             = { title = 'Drone',  description = 'Drone landed safely. Go retrieve it.',                        type = 'success', duration = 5000 },
    pickedUp           = { title = 'Drone',  description = 'Drone retrieved.',                                            type = 'success', duration = 3000 },
    tooFar             = { title = 'Drone',  description = 'You are too far from the drone to pair.',                     type = 'error',   duration = 3000 },
    noController       = { title = 'Drone',  description = 'You need a controller in your inventory to connect.',          type = 'error',   duration = 3000 },
    signalLost         = { title = 'Drone',  description = 'Signal lost — drone returning to home, please wait...',       type = 'warning', duration = 6000 },
    returnComplete     = { title = 'Drone',  description = 'Drone has returned home safely.',                             type = 'success', duration = 4000 },
    batteryLow         = { title = 'Drone',  description = 'Battery low! Land soon.',                                    type = 'warning', duration = 4000 },
    batteryCritical    = { title = 'Drone',  description = 'Battery critical! Landing imminent.',                         type = 'error',   duration = 4000 },
    batteryDead        = { title = 'Drone',  description = 'Battery depleted — drone falling!',                           type = 'error',   duration = 5000 },
    batterySwapped     = { title = 'Drone',  description = 'Battery swapped successfully.',                               type = 'success', duration = 3000 },
    noBattery          = { title = 'Drone',  description = 'You don\'t have a battery to swap in.',                       type = 'error',   duration = 3000 },
    batteryRemoved     = { title = 'Drone',  description = 'Battery removed from drone.',                                  type = 'info',    duration = 3000 },
    noBatteryConnect   = { title = 'Drone',  description = 'This drone has no battery. Insert a battery first.',           type = 'error',   duration = 4000 },
    noBatteryInDrone   = { title = 'Drone',  description = 'Drone has no battery to remove.',                              type = 'error',   duration = 3000 },
    noFlyTakeoff       = { title = 'Drone',  description = 'You cannot launch a drone inside a no-fly zone.',              type = 'error',   duration = 4000 },
    noFlyEntered       = { title = 'Drone',  description = 'Approaching no-fly zone — turn back!',                        type = 'warning', duration = 4000 },
    noFlyBlocked       = { title = 'Drone',  description = 'Cannot enter no-fly zone — controls reversed.',                type = 'error',   duration = 3000 },
}

Last updated