OrigenNetwork
Docs

Custom Locations · origen_ilegalv2

Config.Locations.Types defines every location type that a gang leader can place on the map through the management panel (stashes, garages, clothing rooms, bank deposit points, management desks…). You can add your own location types by extending this table — no core edits required.

Each type controls:

  • Its blip and 3D marker appearance.
  • The permission a member needs to interact with it.
  • Whether it's a default type (seeded automatically for new gangs).

Where to add custom types

Add new entries inside Config.Locations.Types in config/locations.lua:

luaconfig/locations.lua
Config.Locations = {
    DrawDistance       = 50.0,
    InteractDistance   = 1.5,
    MarkerDrawDistance = 15.0,
 
    Types = {
        stash = { --[[ ... ]] },
        garage = { --[[ ... ]] },
 
        -- your custom type
        armory = {
            label              = 'Open gang armory',
            default            = false,
            requiredPermission = 'access_armory',
 
            blip = {
                enabled = false,
                sprite  = 110,
                color   = 1,
                scale   = 0.7,
            },
 
            marker = {
                type          = 22,
                offset        = { x = 0.0, y = 0.0, z = 1.0 },
                scale         = { x = 0.25, y = 0.25, z = 0.25 },
                color         = { r = 255, g = 0, b = 0, a = 255 },
                bobUpAndDown  = true,
                faceCamera    = true,
                rotationOrder = 2,
                rotate        = false,
            },
 
            onInteract = function(gangData, locationId, locationData)
                -- client-side logic here
                TriggerServerEvent('my_resource:openArmory', gangData.id)
            end,
        },
    },
}

The key (armory in the example) is the locationType used internally. It is the value stored in the DB for each placed point.


Type fields

FieldTypeRequiredDescription
labelstringyesText shown in the interaction prompt. Can be a plain string or a locale key (e.g. locations.types.armory.label).
defaultbooleanyesIf true, the type is handled by the core (stash, garage, clothing, bank, management). Set false for custom types that define their own onInteract.
requiredPermissionstring | nilyesRank permission required to interact with a placed point. Use nil to allow any member.
bliptableyesMinimap blip config (see below).
markertableyes3D world marker config (see below).
onInteractfunctionnoRequired for custom types (default = false). Called client-side when a member interacts with the point. Receives (gangData, locationId, locationData).
placement_previewtablenoOnly used by special types that need a world preview while placing (e.g. garage shows a vehicle to pick heading).

blip

FieldTypeDescription
enabledbooleanShow the blip on the minimap.
spritenumberGTA blip sprite id.
colornumberGTA blip color id.
scalenumberBlip size.

marker

FieldTypeDescription
typenumberMarker type id — see FiveM marker reference.
offset{ x, y, z }Offset from the base coordinate. Legacy alias offsetZ (float) is still accepted.
scale{ x, y, z }Marker size per axis.
color{ r, g, b, a }RGBA 0–255.
bobUpAndDownbooleanBob animation.
faceCamerabooleanAlways face the camera.
rotationOrdernumberAxis order for rotation (default 2).
rotatebooleanSpin on axis.

How custom type interaction works

When default = false, the core calls the onInteract function defined directly in the type config. This function runs client-side and receives three arguments:

ArgumentTypeDescription
gangDatatableThe player's gang data (id, name, members, ranks, etc.).
locationIdstringThe unique ID of the placed point (e.g. gang_ballas_armory_1).
locationDatatableRaw location data including coords (x, y, z, h) and type.

Permission validation (requiredPermission) is handled by the core before onInteract is called. If the member does not have the required permission, the interaction is blocked silently and onInteract never runs.

onInteract runs on the client. To run server-side logic (open an inventory, give items, etc.), trigger a server event from inside the function.

luaconfig/locations.lua — onInteract example
onInteract = function(gangData, locationId, locationData)
    -- trigger your own server event from here
    TriggerServerEvent('my_resource:openArmory', gangData.id)
end,
luacustom/server/my_armory.lua — server handler
RegisterNetEvent('my_resource:openArmory', function(gangId)
    local src = source
    -- your server-side logic here
    exports.ox_inventory:openInventory(src, {
        type = 'shop',
        id   = 'gang_armory_' .. gangId,
    })
end)

Place custom server handlers inside custom/server/ so that core updates do not overwrite your logic.


Permission system

requiredPermission maps directly to the rank permission flags defined in Config.Gang.DefaultRanks (config/gangs.lua). When a member tries to interact with a placed point, the core checks:

lua
gang:hasPermission(identifier, location.requiredPermission)

If it returns false, the interaction is silently blocked.

Adding your own permission flag

  1. Define the flag in each default rank that should receive it:

    luaconfig/gangs.lua
    DefaultRanks = {
        {
            id   = 1,
            name = "Leader",
            permissions = {
                -- ... existing flags ...
                access_armory = true,
            },
        },
        {
            id   = 3,
            name = "Member",
            permissions = {
                access_armory = false,
            },
        },
    },
  2. Reference it from your location type:

    lua
    armory = {
        requiredPermission = 'access_armory',
        -- ...
    },
  3. Placement gate (optional) — to restrict who can place the point (not just interact), the management panel reuses the standard manage_locations permission for all types. No extra config needed.

Every rank that should be able to see or use the new permission must have the flag explicitly defined. Missing flags default to false.

Members can also edit rank permissions at runtime through the gang panel (if they have manage_ranks). Any permission key declared in Config.Gang.DefaultRanks is automatically listed there.


Complete example — armory type

luaconfig/locations.lua
armory = {
    label              = 'locations.types.armory.label',
    default            = false,
    requiredPermission = 'access_armory',
 
    blip = {
        enabled = true,
        sprite  = 110,
        color   = 1,
        scale   = 0.7,
    },
 
    marker = {
        type          = 22,
        offset        = { x = 0.0, y = 0.0, z = 1.0 },
        scale         = { x = 0.3, y = 0.3, z = 0.3 },
        color         = { r = 255, g = 50, b = 50, a = 200 },
        bobUpAndDown  = true,
        faceCamera    = true,
        rotationOrder = 2,
        rotate        = false,
    },
 
    onInteract = function(gangData, locationId, locationData)
        TriggerServerEvent('my_resource:openArmory', gangData.id)
    end,
},
luaconfig/gangs.lua — DefaultRanks
-- Leader + Co-Leader:
access_armory = true,
-- Member + Recruit:
access_armory = false,
luacustom/server/my_armory.lua
RegisterNetEvent('my_resource:openArmory', function(gangId)
    local src = source
    exports.ox_inventory:openInventory(src, {
        type = 'shop',
        id   = 'gang_armory_' .. gangId,
    })
end)

Restart the resource. The new Armory type appears in the location placement picker for any rank with manage_locations, and only members with access_armory can interact with the placed points.