return {
    Enabled = true, -- false = no masts; drops can then only be forced via /deaddrop_start

    -- Network intrusion (terminal `breach` command): crack a relay's defence minigames and clear
    -- `Required` relays before the grid-wide purge to call a drop. The flush + the Required->drop
    -- trigger are wired server-side.
    Intrusion = {
        Flush = 300, -- seconds from the first intrusion before the network flushes everyone out
        Required = 2, -- relays to fully breach within that window to call a drop
        Defenses = 2, -- defence layers to crack per relay (successful daemon runs needed)
        Cooldown = 30, -- seconds a daemon is benched after a failed run before the same player can retry it
        CoopBreach = false, -- true = several players can pool progress on the SAME relay; false = one intruder per relay

        -- Post-breach: once the relays fall, the whole crew runs `calldrop` within
        -- TriangulateWindow seconds of each other, starting a shared Triangulate-second bar
        -- (closing the terminal aborts it) which calls the drop on completion.
        TriangulateWindow = 15, -- seconds for the whole crew to run `calldrop` together
        Triangulate = 8, -- shared triangulating progress-bar duration (seconds)

        -- Proof-of-play floors: the minimum seconds a daemon must run before the server accepts it,
        -- tuned to the fastest a human could PHYSICALLY finish - so a devtools/executor skip saves
        -- no time and a skilled player is never rejected. Formulas: server/deaddrop/proof.lua.
        Proof = {
            MinFloor = 3.0, -- global floor-of-the-floor: no daemon is ever accepted faster than this
            Grace = 2.0, -- survival games (cipher, evasion): floor = timeLimit - Grace
            Safety = 0.85, -- throughput floors * this, so lag/variance never rejects a genuinely fast run

            -- Per-game tuning (omit a game to use proof.lua's defaults).
            Capture = { perUnit = 0.20 }, -- units = capturesRequired
            Snake = { perUnit = 0.10 }, -- units = nodesRequired
            Typing = { maxCps = 20.0 }, -- floor = stringsRequired*stringLength / maxCps (~240 WPM ceiling)
            -- Maze ships its fragment cells to the client to render, so time is its only real
            -- bound - its floor is tuned UP toward a realistic fog-of-war solve.
            Maze = { perNode = 1.5, perCell = 0.20 }, -- units = dataNodes*perNode + (width+height)*perCell
            Pipe = { base = 3.0, perBoard = 4.0 }, -- units = rounds
            Breakout = { perBrick = 0.18 }, -- units = rows*cols, divided by ballSpeed
            Signal = { flashOnMs = 450, flashOffMs = 200, startDelayMs = 600, showPauseMs = 500 }, -- mirrors SignalGame.tsx
            -- firewall derives from shootCooldown; cipher/evasion are survival (timeLimit - Grace).
        },
    },

    Prop = 'prop_radiomast02', -- the radio-mast prop spawned at each tower

    SpawnDistance = 500.0, -- metres at which a tower's mast spawns via lib.points (and despawns), so the set never loads at once

    -- Optional map blip per tower. Sprite/colour ids: docs.fivem.net/docs/game-references/blips
    Blip = {
        enabled = true, -- master switch: no blips at all while false
        sprite = 866, -- icon id
        color = 1, -- colour id
        scale = 0.8, -- icon size
        shortRange = true, -- false = visible across the whole map (find the towers)
        display = 4, -- 2 = minimap only, 4 = map + minimap, 8 = map only
        alpha = 255, -- 0-255 opacity
    },

    -- Daemons outside an intrusion ("practice runs"): true (default) = allowed, with a warning
    -- that it progresses nothing (don't-ask-again option). false = refused outright.
    PracticeRuns = true,

    -- The hacking tablet's USB storage (right-click the merryweather_tablet item): a per-tablet
    -- stash - its id is minted into the item's metadata on first open. Inserted USBs are what the
    -- terminal reads its available daemons from.
    Tablet = {
        StashSlots = 8, -- stash size (slots)
        StashWeight = 4000, -- stash capacity (grams)

        -- Daemons each USB item provides while it sits in the tablet's storage. Keys are
        -- ox_inventory item names; values are terminal module keys (configs/client/minigame.lua).
        -- Keep each USB's item label/description (ox_inventory/data/items.lua) in sync.
        USBHacks = {
            deaddrop_usb_1 = { 'maze', 'cipher' }, -- Runner Kit (ungated)
            deaddrop_usb_2 = { 'capture', 'typing' }, -- Breaker Kit (ungated)
            deaddrop_usb_3 = { 'evasion', 'signal', 'pipe' }, -- Decrypt Suite (Acquaintance)
            deaddrop_usb_4 = { 'snake', 'firewall', 'breakout' }, -- Black ICE Suite (Trusted)
        },

        -- USB durability: each run wears the providing stick (metadata.durability; 100 = fresh,
        -- shown as the icon's wear bar). A stick at 0 is FRIED: it stays in the stash but its
        -- daemons unload until replaced. When several inserted sticks provide the same daemon the
        -- most-worn one takes the hit first, so sticks fry one at a time.
        Durability = {
            Hack = { Enabled = true, Cost = 10 }, -- daemon runs against a relay defence
            Practice = { Enabled = true, Cost = 5 }, -- practice runs (outside an intrusion)
            -- true = a stick worn to 0 is removed from the stash entirely (with a "burned out"
            -- notification) instead of staying fried at 0%.
            RemoveAtZero = false,
        },

        -- Held-prop animation while the terminal is open (flag 49 upper-body, so the player can
        -- still move/turn). Anim = false skips the prop + animation (the terminal still opens).
        -- bone 28422 = right hand; offset/rot are tuned for this dict + prop - re-tune if you swap either.
        Anim = {
            dict = 'amb@world_human_seat_wall_tablet@female@base',
            clip = 'base',
            prop = 'prop_cs_tablet',
            bone = 28422,
            offset = vec3(0.0, -0.00, 0.0),
            rot = vec3(0.0, 0.0, 0.0),
        },
    },

    -- Terminal scans: `longrangescan` (from high ground, reads the distance to every active
    -- tower) and `scan` (sniffs nearby Wi-Fi; a tower's network appears within NetworkRange).
    Scan = {
        MinElevation = 150.0, -- longrangescan: minimum world Z (height) to get a signal
        ScanMs = 3000, -- progress-bar duration for either scan (milliseconds)
        Units = 'imperial', -- longrangescan: 'imperial' (mi/ft, default) or 'metric' (km/m)
        ShowDirection = false, -- longrangescan: also show a compass bearing (N, NE, SW, ...)
        NetworkRange = 150.0, -- scan: metres within an active tower to reveal its network
    },

    -- Towers spawned each restart, picked at random from the server-only pool - so the active set
    -- rotates and the scan hunt stays fresh. false/0/>= pool size = spawn EVERY listed tower.
    SpawnCount = 4,

    -- Minimum metres between any two ACTIVE towers. If the pool can't supply enough spaced-out
    -- spots the remainder fill closer (with a server-console warning). 0/false = no spacing check.
    MinDistance = 900.0,

    -- The radio-mast tower POOL is server-only (configs/server/trigger.lua): the server picks the
    -- active subset each restart and publishes those coords via GlobalState, so clients never see
    -- the full candidate list.
}
