bridge/target.lua

-- ==========================================
-- TARGET BRIDGE  (client-side only)
-- ==========================================
-- Wraps targeting system calls so the main script works with
-- either qb-target or ox_target based on Config.Setup.target.
--
-- Global table:  Target
--
-- All functions accept qb-target-style option tables:
--   {
--       options  = { { type, event, icon, label, canInteract, ... }, ... },
--       distance = 2.5,
--   }
-- The bridge converts these to the correct format for each backend.
-- ==========================================

Target = {}

local targetType = Config.Setup and Config.Setup.target or 'qb-target'

-- ==========================================
-- QB-TARGET
-- ==========================================
if targetType == 'qb-target' then

    function Target.AddEntity(entity, opts)
        pcall(function()
            exports['qb-target']:AddTargetEntity(entity, opts)
        end)
    end

    function Target.RemoveEntity(entity)
        pcall(function()
            exports['qb-target']:RemoveTargetEntity(entity)
        end)
    end

    function Target.AddModel(model, opts)
        pcall(function()
            exports['qb-target']:AddTargetModel(model, opts)
        end)
    end

    function Target.RemoveModel(model)
        pcall(function()
            exports['qb-target']:RemoveTargetModel(model)
        end)
    end

-- ==========================================
-- OX_TARGET
-- ==========================================
elseif targetType == 'ox_target' then

    --- Convert qb-target option format → ox_target option format
    --- qb: { options = { { type, event, icon, label, canInteract, ... } }, distance = N }
    --- ox: { { name, event/onSelect, icon, label, canInteract, distance, ... } }
    local function convertOpts(qbOpts)
        local oxOptions = {}
        local dist = qbOpts.distance or 2.5

        for _, opt in ipairs(qbOpts.options or {}) do
            local eventName = opt.event

            -- Collect any extra data fields (e.g. crashNetId) that qb-target passes
            -- to the event handler via the data table
            local extraData = {}
            local reserved = {
                type = true, event = true, icon = true, label = true,
                canInteract = true, action = true, job = true,
            }
            for k, v in pairs(opt) do
                if not reserved[k] then
                    extraData[k] = v
                end
            end
            local hasExtra = next(extraData) ~= nil

            local oxOpt = {
                name     = eventName,
                icon     = opt.icon,
                label    = opt.label,
                distance = dist,
            }

            if opt.canInteract then
                -- ox_target passes (entity, distance, coords, name, bone)
                -- qb-target passes (entity, ...) — same first arg
                oxOpt.canInteract = opt.canInteract
            end

            if hasExtra then
                -- qb-target injects extra fields + entity into the data table
                -- passed to the event.  We replicate that with onSelect.
                oxOpt.onSelect = function(data)
                    local payload = {}
                    for k, v in pairs(extraData) do payload[k] = v end
                    payload.entity = data.entity
                    TriggerEvent(eventName, payload)
                end
            else
                -- Simple event trigger — ox passes (data) with .entity
                -- We wrap to match qb-target format: event receives (data) with .entity
                oxOpt.onSelect = function(data)
                    TriggerEvent(eventName, { entity = data.entity })
                end
            end

            oxOptions[#oxOptions + 1] = oxOpt
        end

        return oxOptions
    end

    function Target.AddEntity(entity, opts)
        pcall(function()
            local oxOpts = convertOpts(opts)
            exports.ox_target:addLocalEntity(entity, oxOpts)
        end)
    end

    function Target.RemoveEntity(entity)
        pcall(function()
            exports.ox_target:removeLocalEntity(entity)
        end)
    end

    function Target.AddModel(model, opts)
        pcall(function()
            local oxOpts = convertOpts(opts)
            exports.ox_target:addModel(model, oxOpts)
        end)
    end

    function Target.RemoveModel(model)
        pcall(function()
            exports.ox_target:removeModel(model)
        end)
    end

else
    -- Unknown target — warn and provide no-ops
    print('[fiveous_drones] WARNING: Unknown target system "' .. tostring(targetType) .. '". Target interactions disabled.')
    function Target.AddEntity() end
    function Target.RemoveEntity() end
    function Target.AddModel() end
    function Target.RemoveModel() end
end

-- ==========================================
-- BATTERY OPTION FILTER
-- ==========================================
-- When battery system is completely disabled, strip all swap/insert
-- battery options from every target so they never appear.

if Config.Battery and Config.Battery.enabled == false then
    local _addEntity = Target.AddEntity
    local _addModel  = Target.AddModel

    local function stripBatteryOpts(opts)
        if not opts or not opts.options then return opts end
        local filtered = {}
        for _, o in ipairs(opts.options) do
            if o.event ~= 'fiveous_drones:swapBattery' then
                filtered[#filtered + 1] = o
            end
        end
        opts.options = filtered
        return opts
    end

    function Target.AddEntity(entity, opts)
        _addEntity(entity, stripBatteryOpts(opts))
    end

    function Target.AddModel(model, opts)
        _addModel(model, stripBatteryOpts(opts))
    end
end

Last updated