TC ScriptDocumentation

Configuration

Every shared/config.lua option: bridge, police, evidence, casings, fingerprints, sampling, lab, camera, cases.

The file is shared/config.lua (clear text, editable). Field settings (laboratories) are done in game with /forensicgestion.

#Bridge

Lua
Config.Bridge = {
    Framework = 'auto',    -- 'auto' | 'vision' | 'qbox' | 'qbcore' | 'esx' | 'standalone'
    Inventory = 'auto',    -- 'auto' | 'ox_inventory' | 'qs-inventory' | 'qb-inventory' | 'framework' | 'none'
    Target    = 'auto',    -- 'auto' | 'ox_target' | 'qb-target' | 'none'
    Society   = 'auto',    -- not used by this script
    Callbacks = 'auto',    -- 'auto' (ox_lib > framework callbacks > built-in callbacks) | 'native'
    Debug     = false,
    Admins    = {},        -- staff identifiers, e.g. 'license:xxxx', 'discord:xxxx'
    AdminAce  = 'command', -- staff ACE permission
    Standalone = {},       -- standalone hooks
}

#Standalone mode

FunctionReturns
getJob(src){ name, label, grade, gradeName, onDuty }
getCharacter(identifier)character profile
itemCount(src, name)quantity
addItem(src, name, count, metadata)add
removeItem(src, name, count, metadata)remove

#Integrations

Each integration is only used when the resource is started and enabled here.

Lua
Config.Integrations = {
    logs       = true,   -- tc-logs: copy actions to Discord
    screenshot = true,   -- screenshot-basic: required by the camera
    doorlock   = true,   -- ox_doorlock: fingerprints on doors
    emotes     = true,   -- tablet in hands during /enquete (rpemotes or compatible)
}
Config.Logs = { webhook = 'forensic.default' }   -- tc-logs channel key; the webhook itself is set in tc-logs
Config.TabletAnim = { command = 'e tablet2', cancel = { resource = 'rpemotes', export = 'EmoteCancel' } }

#Staff and police jobs

Lua
Config.AdminDiscords = {}                                    -- Discord IDs always staff (never ship real IDs in a distributed config)
Config.StaffPermissions = { 'gestion_features', 'staff_menu' }   -- Vision only

Config.Police = { jobs = { 'police', 'sheriff' } }

On Vision, police jobs come from the core (police type). Elsewhere, they are the ones in Config.Police.jobs. Only these jobs, on duty, can access investigations, the lab and seals.

#Evidence

Lua
Config.Evidence = {
    backend  = 'auto',          -- 'auto' | 'core' (Vision) | 'internal' (tc_forensic_* tables)
    hashSalt = 'change-me',     -- ⚠ change it: salt for DNA / fingerprint codes (internal mode)
    expireHours = { casing = 168, fingerprint = 72, blood = 72, gunpowder = 24, gsr = 6, fragment = 72, bullet_impact = 72 },
    gsrOnShot = true,           -- internal mode: gunshot residue is recorded on every shot
}

expireHours: lifetime of a trace left on the ground, in hours (internal mode). 0 = unlimited.

#Items

Item names in your inventory:

Lua
Config.Items = {
    casing = 'douille', camera = 'camera', photo = 'photo', folder = 'dossier_photo',
    dnaSample = 'prelevement_adn', printCard = 'fiche_empreintes', gsrTest = 'test_gsr',
    kit = 'forensic_kit', gloves = 'gloves', bag = 'evidence_bag',
    uvLamp = 'lampe_uv', casingBag = 'sachet_douilles',
}

Config.NewItems (Vision only) lists items created automatically at start-up if missing. Elsewhere, see Items.

#Casings

OptionDefaultRole
modelsw_pi_flaregun_shell, w_am_caseFirst model present in the game
viewDistance35.0Prop spawn distance
pickupRange1.6Pick-up distance
needFlashlighttrueLight on required to see the prompt
civilianFlashlightfalsetrue: the regular flashlight also works for civilians
pickupTime1800Pick-up duration (ms)
everyBullettrueOne casing per bullet, whoever fires
npcShots / npcRangetrue / 150.0Armed peds also leave casings
maxPerSecond40Per-player anti-abuse cap
maxProps200Props displayed at once (the closest ones)
disableStateBags{ 'inPaintball' }Player state bags that disable casings (e.g. a paintball mini-game)
Vision

Switch off “Spawn casing on shot” in the core's evidence config menu, otherwise it adds its own duplicate casing.

#Fingerprints

Lua
Config.Prints = { vehicles = true, doors = true, cooldown = 300, vehicleScanRange = 3.0 }

cooldown: seconds between two prints of the same player at the same place.

#Sampling

Lua
Config.Sampling = {
    range = 2.5, duration = 6000,   -- range (m) and duration (ms)
    consentTimeout = 20,            -- seconds to accept
    forceIfRestrained = true,       -- no consent needed if the target is cuffed, down or dead
    gsrWindow = 45,                 -- minutes: a shot within this delay makes the test positive
}

#Laboratory

Lua
Config.Lab = {
    pointRange = 6.0,
    atLab = { ballistics = true, dna = false, prints = false, paint = false, gsr = false },   -- analyses that can only start at a lab point
    durations = { dna = 240, prints = 180, ballistics = 180, paint = 120, gsr = 90 },         -- seconds
}

“Laboratory” points are placed in game (/forensicgestion). An analysed DNA / fingerprint trace always gives the identity, with no prior sampling of the person.

#Camera, cases, UV lamp, bag

Lua
Config.Camera   = { traceRange = 120.0, quality = 0.72, width = 1280, maxPhotosPerFolder = 40 }
Config.Cases    = { manageGrade = 3, categories = { 'Homicide', 'Vol', 'Autre' --[[ … ]] }, roles = { 'Suspect', 'Témoin' --[[ … ]] } }
Config.UvLamp   = { prop = 'prop_cs_police_torch_02', color = { 140, 40, 255 }, range = 18.0 }
Config.CasingBag = { slots = 30, maxWeight = 3.0 }
  • Config.Cases.manageGrade: minimum grade to delete a case that is not your own; categories and roles are the lists offered in the interface.
  • Config.CasingBag: each bag has its own chest (30 slots, 3 kg).

#Full file

Show config.lua (243 lines)
shared/config.luaDownload
Config = {}

---------------------------------------------------------------------------
-- Compatibilité / Compatibility  (voir bridge/*.lua)
-- FR : tc-forensic fonctionne avec Vision (core), ESX, QBCore, Qbox ou en standalone.
--      Tout est détecté automatiquement ('auto'). Ne force une valeur que si la détection se trompe.
-- EN : tc-forensic runs on Vision (core), ESX, QBCore, Qbox or standalone.
--      Everything is auto-detected ('auto'). Only force a value if detection is wrong.
---------------------------------------------------------------------------
Config.Bridge = {
    Framework = 'auto',    -- 'auto' | 'vision' | 'qbox' | 'qbcore' | 'esx' | 'standalone'
    Inventory = 'auto',    -- 'auto' | 'ox_inventory' | 'qs-inventory' | 'qb-inventory' | 'framework' | 'none'
    Target    = 'auto',    -- 'auto' | 'ox_target' | 'qb-target' | 'none'
    Society   = 'auto',    -- non utilisé par ce script / not used by this script
    Callbacks = 'auto',    -- 'auto' (ox_lib > callbacks du framework > callbacks internes) | 'native'
    Debug     = false,     -- logs de diagnostic / diagnostic logs
    -- FR : identifiants (ex. 'license:xxxx', 'discord:xxxx') considérés comme staff / admin du script.
    -- EN : identifiers (e.g. 'license:xxxx') treated as script staff / admins.
    Admins    = {},
    AdminAce  = 'command', -- permission ACE pour le staff (add_ace group.admin command allow)
    -- FR : crochets pour le mode standalone (sans framework), à remplir si besoin :
    --      getJob(src) -> { name, label, grade, gradeName, onDuty }, getCharacter(identifier), itemCount(src, name),
    --      addItem(src, name, count, metadata), removeItem(src, name, count, metadata)
    -- EN : hooks for standalone mode (no framework), fill in if needed.
    Standalone = {},
}

---------------------------------------------------------------------------
-- Intégrations optionnelles / Optional integrations
-- FR : chaque intégration n'est utilisée que si la ressource est démarrée ET si elle est activée ici.
-- EN : each integration is only used when the resource is started AND enabled here.
---------------------------------------------------------------------------
Config.Integrations = {
    logs       = true,   -- tc-logs : copie des actions sur Discord / copies actions to Discord
    screenshot = true,   -- screenshot-basic : requis pour l'appareil photo / required by the camera
    doorlock   = true,   -- ox_doorlock : empreintes sur les portes / fingerprints on doors
    emotes     = true,   -- tablette en main pendant /enquete (rpemotes ou compatible)
}

-- tc-logs : clé du salon (webhook) utilisée pour les logs. Le webhook Discord lui-même se règle dans tc-logs.
-- tc-logs: channel key used for logs. The Discord webhook itself is configured in tc-logs.
Config.Logs = {
    webhook = 'forensic.default',
}

-- Emote jouée avec /enquete (tablette en main) et export pour l'annuler.
-- Emote played with /enquete (tablet in hands) and the export to cancel it.
Config.TabletAnim = {
    command = 'e tablet2',
    cancel  = { resource = 'rpemotes', export = 'EmoteCancel' },
}

-- FR : staff (accès /forensicgestion). Identifiants Discord toujours considérés staff, et permissions
--      globales du core Vision. Sur ESX / QBCore / Qbox : ACE joaat('command'), groupes admin ou Config.Bridge.Admins.
-- EN : staff (access to /forensicgestion). Discord IDs always treated as staff, and Vision core global
--      permissions. On ESX / QBCore / Qbox: ACE joaat('command'), admin groups or Config.Bridge.Admins.
-- ⚠ Ne mets aucun identifiant réel dans une config distribuée / never ship real IDs.
Config.AdminDiscords = {}
Config.StaffPermissions = { 'gestion_features', 'staff_menu' }   -- Vision uniquement / Vision only

---------------------------------------------------------------------------
-- Police / Police jobs
-- FR : sur Vision, les jobs police viennent du core (type police). Ailleurs (ESX, QBCore, Qbox, standalone)
--      ce sont les jobs listés ici. Seuls ces jobs, EN SERVICE, accèdent aux enquêtes, au labo et aux scellés.
-- EN : on Vision, police jobs come from the core. Elsewhere they are the jobs listed here.
---------------------------------------------------------------------------
Config.Police = {
    jobs = { 'police', 'sheriff' },
}

---------------------------------------------------------------------------
-- Preuves / Evidence
-- FR : sur Vision, les preuves (douilles, empreintes, sang…) sont gérées par le core.
--      Sans ce système, tc-forensic utilise ses propres tables (tc_forensic_evidence, tc_forensic_custody).
-- EN : on Vision, evidence is handled by the core. Without it, tc-forensic uses its own SQL tables.
---------------------------------------------------------------------------
Config.Evidence = {
    backend  = 'auto',                -- 'auto' | 'core' (Vision) | 'internal' (tables tc_forensic_*)
    hashSalt = 'change-me',           -- ⚠ change cette valeur : sel des codes ADN / empreintes (mode internal)
    -- Durée de vie d'une trace restée au sol, en heures (mode internal). 0 = illimité.
    expireHours = { casing = 168, fingerprint = 72, blood = 72, gunpowder = 24, gsr = 6, fragment = 72, bullet_impact = 72 },
    -- Mode internal : un résidu de tir (gsr) est enregistré à chaque tir d'un joueur (test GSR).
    gsrOnShot = true,
}

-- Coffres des preuves (mode internal uniquement : sur Vision ils se placent dans /gestion du core).
-- Chaque entrée : { job = 'police', label = 'Coffre des preuves', coords = vec3(x, y, z), slots = 100, weight = 500 (kg) }
-- Internal mode only (on Vision they are placed in the core's /gestion).
Config.EvidenceLockers = {}

---------------------------------------------------------------------------
-- Objets / Items (noms des items dans ton inventaire). Voir install/ pour les créer.
-- FR : joaat('camera'), joaat('forensic_kit'), joaat('gloves'), joaat('evidence_bag') sont des items « externes » à créer aussi (install/).
-- EN : see install/ to create them (ox_inventory, QBCore, ESX).
---------------------------------------------------------------------------
Config.Items = {
    casing     = 'douille',          -- douille ramassée au sol
    camera     = 'camera',           -- appareil photo
    photo      = 'photo',            -- photo développée
    folder     = 'dossier_photo',    -- dossier qui contient des photos
    dnaSample  = 'prelevement_adn',  -- prélèvement ADN scellé (sur personne)
    printCard  = 'fiche_empreintes', -- fiche d'empreintes (sur personne)
    gsrTest    = 'test_gsr',         -- test de résidus de tir (consommé)
    kit        = 'forensic_kit',     -- kit de prélèvement (requis pour ADN / empreintes)
    gloves     = 'gloves',           -- gants : pas d'empreintes
    bag        = 'evidence_bag',     -- sachet de preuve scellé (lu par le labo)
    uvLamp     = 'lampe_uv',         -- lampe UV (illégal) : fait ressortir les douilles
    casingBag  = 'sachet_douilles',  -- sachet de douilles : mini-inventaire de 30 places
}

-- Items créés au démarrage s'ils n'existent pas (poids en kg) : Vision uniquement (table joaat('items') du core).
-- Ailleurs, ajoute-les avec les fichiers de install/. / Auto-created on Vision only; elsewhere use install/.
Config.NewItems = {
    { name = 'photo',            label = 'Photo',                     weight = 0.01, type = 'objects' },
    { name = 'dossier_photo',    label = 'Dossier photos',            weight = 0.2,  type = 'objects' },
    { name = 'prelevement_adn',  label = 'Prélèvement ADN',           weight = 0.05, type = 'objects' },
    { name = 'fiche_empreintes', label = "Fiche d'empreintes",        weight = 0.05, type = 'objects' },
    { name = 'test_gsr',         label = 'Test de résidus de tir',    weight = 0.1,  type = 'consumable' },
    { name = 'lampe_uv',         label = 'Lampe UV',                  weight = 0.3,  type = 'objects' },
    { name = 'sachet_douilles',  label = 'Sachet de douilles',        weight = 0.05, type = 'objects' },
}

-- Vision uniquement : corrige la description (fausse) du kit de nettoyage du core.
Config.FixCleaningKitDescription = true

---------------------------------------------------------------------------
-- Douilles physiques au sol (visibles par tout le monde)
---------------------------------------------------------------------------
Config.Casings = {
    -- Premier modèle présent dans le jeu (petite douille de laiton).
    models        = { 'w_pi_flaregun_shell', 'w_am_case' },
    viewDistance  = 35.0,   -- distance d'apparition du prop
    pickupRange   = 1.6,    -- distance pour ramasser
    needFlashlight = true,  -- lampe allumée obligatoire pour voir le prompt
    -- Police en service : sa lampe torche. Les autres : la lampe UV (item).
    -- true = la lampe torche classique marche aussi pour les civils.
    civilianFlashlight = false,
    pickupTime    = 1800,   -- ms
    -- Une douille par balle tirée, quel que soit le tireur (joueur, police en
    -- service, PNJ) et l'endroit. Vision : couper « Spawn douille au tir » dans le menu
    -- config preuves du core, sinon il ajoute sa propre douille en double.
    everyBullet   = true,
    npcShots      = true,   -- les PNJ armés laissent aussi leurs douilles
    npcRange      = 150.0,  -- m autour du joueur pour suivre les PNJ qu'il contrôle
    maxPerSecond  = 40,     -- plafond anti-abus par joueur (au-delà : balles ignorées)
    maxProps      = 200,    -- props affichés en même temps (les plus proches)
    -- State bags du joueur local qui coupent les douilles (ex. mini-jeu de paintball : tc-paintball).
    -- Player state bags that disable casings (e.g. a paintball mini-game).
    disableStateBags = { 'inPaintball' },
}

---------------------------------------------------------------------------
-- Empreintes digitales
---------------------------------------------------------------------------
Config.Prints = {
    vehicles   = true,   -- monter dans un véhicule laisse une empreinte (portière)
    doors      = true,   -- ouvrir/fermer une porte ox_doorlock
    cooldown   = 300,    -- s entre deux empreintes du même joueur au même endroit
    vehicleScanRange = 3.0, -- relevé des empreintes d'un véhicule (menu Alt)
}

---------------------------------------------------------------------------
-- Prélèvements sur une personne (menu Alt sur un joueur)
---------------------------------------------------------------------------
Config.Sampling = {
    range          = 2.5,
    duration       = 6000,   -- ms
    consentTimeout = 20,     -- s pour accepter
    -- Sans accord si la cible est menottée, à terre ou morte.
    forceIfRestrained = true,
    gsrWindow      = 45,     -- min : un tir dans ce délai rend le test positif
}

---------------------------------------------------------------------------
-- Laboratoire (analyses longues, résultats dans l'interface Enquêtes)
---------------------------------------------------------------------------
Config.Lab = {
    -- Points « Laboratoire » : placés en jeu par le staff avec /forensicgestion
    -- (Vision : aussi /gestion → Police scientifique) → page Laboratoires
    -- (table tc_forensic_settings, clé 'labs').
    pointRange    = 6.0,
    -- Analyses lançables seulement à un point Laboratoire (refusées partout
    -- tant qu'aucun point n'est placé).
    atLab = {
        ballistics = true,  -- douilles, poudre, impacts
        dna        = false,
        prints     = false,
        paint      = false,
        gsr        = false,
    },
    -- Une trace ADN / empreinte analysée donne toujours l'identité (nom, prénom),
    -- sans prélèvement préalable sur la personne.
    durations = {           -- secondes
        dna        = 240,
        prints     = 180,
        ballistics = 180,
        paint      = 120,
        gsr        = 90,
    },
}

---------------------------------------------------------------------------
-- Appareil photo
---------------------------------------------------------------------------
Config.Camera = {
    traceRange   = 120.0,  -- trajectoires visibles (police en service)
    quality      = 0.72,   -- jpg après redimensionnement
    width        = 1280,   -- largeur max de la photo stockée
    maxPhotosPerFolder = 40,
}

---------------------------------------------------------------------------
-- Enquêtes
---------------------------------------------------------------------------
Config.Cases = {
    manageGrade = 3,        -- grade mini pour supprimer une enquête qui n'est pas la sienne
    categories = {
        'Homicide', 'Tentative de meurtre', 'Fusillade', 'Braquage', 'Vol', 'Cambriolage',
        'Trafic de stupéfiants', 'Trafic d’armes', 'Délit de fuite', 'Agression', 'Enlèvement',
        'Disparition', 'Fraude', 'Corruption', 'Autre',
    },
    roles = { 'Suspect', 'Témoin', 'Victime', 'Personne d’intérêt', 'Plaignant', 'Interpellé' },
}

---------------------------------------------------------------------------
-- Lampe UV (item illégal) : utilisée, elle sort une lampe en main qui fait
-- ressortir les douilles au sol. Réutiliser l'item pour la ranger.
---------------------------------------------------------------------------
Config.UvLamp = {
    prop  = 'prop_cs_police_torch_02',
    color = { 140, 40, 255 },  -- violet UV
    range = 18.0,              -- portée du faisceau
}

---------------------------------------------------------------------------
-- Sachet de douilles : chaque sachet a son propre coffre (inventaire du framework),
-- ouvert à côté de l'inventaire quand on utilise l'item.
---------------------------------------------------------------------------
Config.CasingBag = {
    slots     = 30,
    maxWeight = 3.0,   -- kg : 30 douilles (0,1 kg) — les objets lourds n'y rentrent pas
}
Last updated : 7 November 2026© 2026 TC Script