RE:CORD
REC_HeistPrep

Stracture

Installation, configuration, and usage for REC_HeistPrep.
Added
Updated

The following configuration files and manifest are taken from the current source.

config/sh_config.lua

---@type REC_Library.Shared.API
local shApi = require "@REC_Library.shared.sh_api"
local apiShCfg = shApi.Config

---@type REC_HeistPrep.Locales
local locales = require ("@REC_HeistPrep.locales.".. apiShCfg.language)

---@class REC_HeistPrep.Shared.Config
local config = {}

---[[
---    Debug mode
---]]
---@type boolean
config.debugMode = true

config.job = {}

---[[
---     Whether to play music to build tension
---]]
---@type boolean
config.job.triggerMusicEvent = false

---[[
---     Players with the jobs listed here are not attacked by the guards
---]]
---@type table<string, true>
config.job.whitelistJobs = {
    ["police"] = true,
    -- ["sheriff"] = true,
    -- ["ambulance"] = true,
}

---[[
---     Key used to deliver
---     https://docs.fivem.net/docs/game-references/controls/
---]]
---@type integer
config.job.deliverControl = 38 -- INPUT_PICKUP (E)

---[[
---     Radius around the prep vehicle where the guards turn hostile
---]]
---@type number
config.job.guardZoneRadius = 100.0

---[[
---     time allowed on the vehicle selection UI
---]]
---@type integer
config.job.selectTimeout = 60 * 1000

---[[
---     time allowed on the delivery naming modal
---     Running out is the same as skipping it: the vehicle is still delivered, it just
---     keeps the model label. Nobody loses a job to a modal.
---]]
---@type integer
config.job.labelTimeout = 30 * 1000

---[[
---     Longest delivery label a player may set
---     The column is varchar(32), so anything above that is cut server side anyway.
---]]
---@type integer
config.job.labelMaxLength = 32

---[[
---     Marker at the garage storage spot
---]]
config.job.marker = {

    ---@type integer
    type = 1,

    ---@type REC_Library.Shared.RGBA
    rgba = { r = 60, g = 255, b = 126, a = 120 },

    ---[[
    ---     The marker is drawn once the player is within this distance
    ---]]
    ---@type number
    drawDistance = 80.0,
}

---[[
---     Blip settings
---]]
---@type table<"vehicle" | "garage" | "garageForSale", REC_HeistPrep.Shared.Config.Job.Blip>
config.job.blips = {
    vehicle = {
        label = locales.blip.vehicle,
        sprite = 225,
        scale = 0.8,
        color = 1,
    },
    garage = {
        label = locales.blip.garage,
        sprite = 357,
        scale = 0.8,
        color = 2,
    },

    ---[[
    ---     A garage nobody owns yet, so a player without one can find the kiosk
    ---]]
    garageForSale = {
        label = locales.blip.garage_for_sale,
        sprite = 357,
        scale = 0.7,
        color = 0,
    },
}

---[[
---     Marker at a garage entrance (owner only) and at the interior exit
---]]
---@type table<"entrance" | "exit", REC_HeistPrep.Shared.Config.Job.ZoneMarker>
config.job.zoneMarkers = {
    entrance = {
        type = 1,
        rgba = { r = 60, g = 255, b = 126, a = 90 },
        drawDistance = 60.0,
    },
    exit = {
        type = 1,
        rgba = { r = 255, g = 120, b = 60, a = 110 },
        drawDistance = 60.0,
    },
}

---[[
---     Remaining time shown next to the order text once the job has this much left (ms)
---     0 shows it for the whole job
---]]
---@type integer
config.job.showRemainingBelow = 0

---[[
---     One warning notification when the job has this much time left (ms)
---]]
---@type integer
config.job.warnRemainingAt = 2 * 60 * 1000

---[[
---     Screen fade in/out duration for the garage teleport (ms)
---]]
---@type integer
config.job.garageFadeDuration = 700

---[[
---     Delay between the vehicle touching the ground and the fade in (ms)
---]]
---@type integer
config.job.garageLandDelay = 1000

---[[
---     Driving into the entrance faster than this is refused (km/h)
---     0 disables the check
---]]
---@type number
config.job.garageEnterMaxSpeed = 15.0

---[[
---     Frontend sound played when the player enters the garage (PlaySoundFrontend)
---     The screen stays black until it has finished, maxWait (ms) caps that
---     name "" disables it
---]]
---@type { name: string, set: string, maxWait: integer, }
config.job.garageEnterSound = {
    name = "Garage_Door_Open",
    set = "GTAO_Script_Doors_Faded_Screen_Sounds",
    maxWait = 10000,
}

---[[
---     In-game placement tool used by the admin panel (Garages page)
---     The panel hides, the admin aims at the spot, a translucent preview follows
---     the crosshair and the confirm key sends the coordinates back to the form.
---]]
---@type REC_HeistPrep.Shared.Config.Job.Placer
config.job.placer = {

    ---[[
    ---     Vehicle drawn as the preview for entrance / interior / exit / store points
    ---]]
    previewVehicle = "baller",

    ---[[
    ---     Ped drawn as the preview for the on-foot points
    ---]]
    previewPed = "a_m_m_business_01",

    ---[[
    ---     0-255, how visible the preview entity is
    ---]]
    previewAlpha = 160,

    ---[[
    ---     https://docs.fivem.net/docs/game-references/controls/
    ---]]
    confirmControl = 38,     -- INPUT_PICKUP (E)
    cancelControl = 177,     -- INPUT_CELLPHONE_CANCEL (Backspace / Esc)
    rotateLeftControl = 174, -- INPUT_CELLPHONE_LEFT (Arrow left)
    rotateRightControl = 175,-- INPUT_CELLPHONE_RIGHT (Arrow right)

    ---[[
    ---     degrees per frame while an arrow key is held, and per scroll notch
    ---]]
    rotateStep = 1.5,
    scrollStep = 15.0,

    ---[[
    ---     how far ahead of the camera a spot can be picked
    ---]]
    maxDistance = 60.0,

    ---[[
    ---     an interior point skips the teleport when the admin is already this close to it
    ---]]
    teleportSkipDistance = 30.0,

    ---[[
    ---     the tool gives up and returns to the panel after this (ms)
    ---]]
    timeout = 120 * 1000,

    ---@type REC_Library.Shared.RGBA
    markerRgba = { r = 60, g = 255, b = 126, a = 110 },
}

---[[
---     Guidance per phase
---     [1] secure the vehicle  [2] deliver
---]]
---@type table<integer, REC_HeistPrep.Shared.Config.Job.Phase>
config.job.phases = {
    [1] = {
        helpText = locales.phase.helpText_1,
        orderText = locales.phase.orderText_1,
        sound = "",
    },
    [2] = {
        helpText = locales.phase.helpText_2,
        orderText = locales.phase.orderText_2,
        sound = "",
    },
}

---[[
---     Do not touch.
---]]
config.job.relationshipGroups = {
    whitelistPlayer = "REC_HeistPrep_PLAYER_WHITELIST",
    memberPlayer = "REC_HeistPrep_PLAYER_MEMBER",
    enemyNpc = "REC_HeistPrep_NPC_ENEMY",
}

return config

---@class REC_HeistPrep.Shared.Config.Job.Blip
---@field label string
---@field sprite integer
---@field scale number
---@field color integer

---@class REC_HeistPrep.Shared.Config.Job.ZoneMarker
---@field type integer
---@field rgba REC_Library.Shared.RGBA
---@field drawDistance number

---@class REC_HeistPrep.Shared.Config.Job.Phase
---@field helpText string[]|false
---@field orderText string|false
---@field sound? string

---@class REC_HeistPrep.Shared.Config.Job.Placer
---@field previewVehicle string
---@field previewAlpha integer
---@field confirmControl integer
---@field cancelControl integer
---@field rotateLeftControl integer
---@field previewPed string
---@field rotateRightControl integer
---@field rotateStep number
---@field scrollStep number
---@field maxDistance number
---@field teleportSkipDistance number
---@field timeout integer
---@field markerRgba REC_Library.Shared.RGBA
©2026 RE:CORD Development Group. All rights reserved.