Whats up mates,

Over the previous two months I’ve been utilizing bt-target as my main interplay methodology for a server I’ve been constructing and I’ve made many adjustments to bt-target that I really feel enhance upon the unique performance of it.

For these of you who haven’t checked out bt-target, I extremely advocate doing so. It was made by BrentN5 over at GitHub – brentN5/bt-target and many individuals use it to at the present time. It lets you maintain a button to disclose interactions round you.

It obtained to some extent the place I made a decision I ought to on the very least launch my fork publicly as you can also use these extra advantages and options of bt-target. It’s been optimised barely and the way in which it really works has been modified fairly considerably, nevertheless there must be no “breaking” adjustments to this.

I wish to preface this launch by stating that there are two necessary pre-requisites for this fork of bt-target:

Github:

Abstract of my adjustments/additions:

  • All knowledge from the unique choice is handed by means of to the occasion as a knowledge desk (see examples)
  • Automobile bone assist – I initially merged in a model from one other pull request however didn’t like the way it labored, so I rewrote most of it. It’s not excellent but it surely kind of works.
  • In-built disabling of the flexibility to assault/fight mode whereas holding the work together key.
  • Job checks have been made a per-option verify, with inbuilt grade checking (see examples)
  • Added assist for networked Entity bt-targets. This principally lets you connect a bt-target choice to a spawned entity (corresponding to a job automobile) and it’ll stay till the entity is despawned.
  • Added assist for EntityZones – they work just like EntityTarget however with a zone across the object. Helpful for difficult fashions or issues that don’t transfer.
  • Go any knowledge by means of an choice to the goal occasion, together with the entity you interacted with by default.
  • Added a required_item verify that hooks into linden_inventory and checks when you’ve got the merchandise in your stock earlier than displaying the choice.
  • The piece de la resistance – added a canInteract() perform so that you can do any code verify you need on the time of interplay.

Installation instructions

Installation is very straightforward but as we use a few custom imports for performance you’ll want to include them yourself:

In es_extendedimports.lua Add the following to the bottom of the file (if it does not already exist):


------------------------------------------------------------------------

-- SHARED

------------------------------------------------------------------------

local Intervals = {}

local CreateInterval = function(name, interval, action, clear)

    local self = {interval = interval}

    CreateThread(function()

        local name, action, clear = name, action, clear

        repeat

            action()

            Citizen.Wait(self.interval)

        until self.interval == -1

        if clear then clear() end

        Intervals[name] = nil

    end)

    return self

end

SetInterval = function(name, interval, action, clear)

    if Intervals[name] and interval then Intervals[name].interval = interval

    else

        Intervals[name] = CreateInterval(name, interval, action, clear)

    end

end

ClearInterval = function(name)

    Intervals[name].interval = -1

end

Examples

Passing Item Data / AddTargetModel


local coffee = {

    690372739,

}

exports['bt-target']:AddTargetModel(coffee, {

    options = {

        {

            event = "coffee:buy",

            icon = "fas fa-coffee",

            label = "Coffee",

            item = "coffee",

            price = 5,

        },

    },

    distance = 2.5

})

RegisterNetEvent('coffee:buy')

AddEventHandler('coffee:buy',function(data)

    ESX.ShowNotification("You purchased a " .. data.item .. " for $" .. data.price .. ". Enjoy!")

    -- server event to buy the item here

end)

AddTargetModel requires a table of model hashes to function correctly. You can use the direct hash number: 690372739 or direct object name with backticks: prop_vend_coffe_01.

Define a table like:


local coffee = {

    `prop_vend_coffe_01`,

    `p_ld_coffee_vend_01`

}

Checking job / BoxZone


exports['bt-target']:AddBoxZone("MissionRowDutyClipboard", vector3(441.7989, -982.0529, 30.67834), 0.45, 0.35, {

    name="MissionRowDutyClipboard",

    heading=11.0,

    debugPoly=false,

    minZ=30.77834,

    maxZ=30.87834,

    }, {

        options = {

            {

                event = "qrp_duty:goOnDuty",

                icon = "fas fa-sign-in-alt",

                label = "Sign In",

                job = "police",

            },

            {

                event = "qrp_duty:goOffDuty",

                icon = "fas fa-sign-out-alt",

                label = "Sign Out",

                job = "police",

            },

        },

        distance = 3.5

})

In this example I’m defining police as a straight string to check if the player interacting has that job before showing the option. You can also define it as [key] = value pairs for grade, for example:


job = {

    ["police"] = 5, -- minimum grade required to see this option

    ["ambulance"] = 0,

}

Removing Zones

You can and SHOULD remove zones in various situations, as a rule I tend to remove a zone with the same name before creating one to prevent clutter, and it helps if you’re using debugPoly.


exports['bt-target']:RemoveZone("MissionRowDutyClipboard")

Just make sure you’re using the exact name of the zone you defined.

CanInteract / EntityZone

In this example we’re making a specifc zone around an entity that was created. This can help if you can’t interact with a particular entity, but also don’t have a static location to define.

The EntityZone is typically removed with the entity.

The canInteract() function defined here allows you to do any particular checks you want to be executed at the time of interaction, in this instance, it checks if the plant has a statebag defined for growth that is higher than or equal to 100.

You can do any check you want as long as you return true or false.


local playerPed = PlayerPedId()

local coords = GetEntityCoords(playerPed)

model = `prop_plant_fern_02a`

RequestModel(model)

while not HasModelLoaded(model) do

    Citizen.Wait(50)

end

local plant = CreateObject(model, coords.x, coords.y, coords.z, true, true)

Citizen.Wait(50)

PlaceObjectOnGroundProperly(plant)

SetEntityInvincible(plant, true)

exports['bt-target']:AddEntityZone("potato-growing-"..plant, plant, {

    name = "potato-growing-"..plant,

    heading=GetEntityHeading(plant),

    debugPoly=false,

}, {

    options = {

    {

        event = "farming:harvestPlant",

        icon = "fa-solid fa-scythe",

        label = "Harvest potato",

        plant = plant,

        job = "farmer",

        canInteract = function()

            if Entity(plant).state.growth >= 100 then 

                return true

            else 

                return false

            end 

        end,

    },

},

    distance = 3.5

})

AddTargetEntity

You can also define an entity target that only that entity will have the interaction. This is very simular to EntityZone except attached to the network entity instead of a static zone.


exports['bt-target']:AddTargetEntity(NetworkGetNetworkIdFromEntity(vehicle), {

    options = {

        {

            event = "postop:getPackage",

            icon = "fa-solid fa-box-circle-check",

            label = "Get Package",

            owner = NetworkGetNetworkIdFromEntity(PlayerPedId()),

            job = "postop",

        },

    },

    distance = 3.0

})

AddTargetBone

Use this in conjunction with the bone index in the config.lua file to define bones you would like to interact with on a vehicle.


    exports['bt-target']:AddTargetBone({"boot"}, {

    options = {

        {

            event = "qrp_vehicle:toggleVehicleDoor",

            icon = "fas fa-door-open",

            label = "Toggle Boot",

            door = 5,

        },

    },

    distance = 1.5

    })



Looking for paid scripts? Click here