TC ScriptDocumentation

Configuration

Every config.lua option: access, lobby, difficulties, arenas, voice, keys, gestures.

#Bridge

Lua
Config.Bridge = {
    Framework = 'auto',     -- 'auto' | 'vision' | 'qbox' | 'qbcore' | 'esx' | 'standalone'
    Inventory = 'auto',     -- not used by this script (present for the shared bridge)
    Target    = 'auto',
    Society   = 'auto',
    Callbacks = 'auto',
    Debug     = false,      -- detection logs in the server console
    Admins    = {},         -- staff identifiers outside Vision, e.g. { 'license:xxxxxxxx', 'discord:123456' }
    AdminAce  = 'command',  -- ACE granting access to staff commands outside Vision
    Standalone = {},
}

#Optional integrations

None is mandatory: if the resource is not started, it is ignored.

Lua
Config.Integrations = {
    logs     = true,   -- tc-logs: Discord log (game start / end, stop by staff)
    lbphone  = true,   -- lb-phone: phone disabled during the game (if Config.BlockComms)
    pmavoice = true,   -- pma-voice: radio / calls cut during the game (if Config.BlockComms)
}

#Access (ped)

Lua
Config.InteractId = 'auto:banana_defuse'   -- Vision: point identifier (“auto:” prefix required); ignored elsewhere
Config.Npc = {
    model  = 'a_m_y_hipster_01',
    coords = vector4(209.0, -925.5, 30.69, 160.0),   -- chest height (the ped is placed 0.98 lower)
}
Config.Blip = { sprite = 486, color = 5, scale = 0.7, label = 'Banana Bomb' }   -- sprite = nil: no blip
Config.InteractIcon       = 'Jobcenter'
Config.NpcDistance        = 2.0      -- distance to talk to the ped
Config.LobbyLeaveDistance = 60.0     -- beyond this from the ped, a lobby player is removed

#Staff

Lua
Config.Permissions = { 'staff_menu', 'gestion', 'dev' }   -- Vision only: having ONE is enough

Grants /banana stop, /banana arene and starting even when not lobby leader. On ESX / QBCore / Qbox / standalone, staff is the bridge's admin (ACE Config.Bridge.AdminAce, admin group, Config.Bridge.Admins).

#Lobby

OptionDefaultRole
Config.Command'banana'Command: /banana quitter | statut | stop | arene
Config.AdminOnlyStartfalsetrue: only staff can start from the menu
Config.AutoStarttrueStarts automatically at 3 players
Config.AutoStartDelay15Seconds before automatic start
Config.DefaultDifficulty'normal'Default difficulty; the lobby leader can change it

#Difficulties

Lua
Config.Difficulties = {
    facile    = { label = 'Easy',   modules = 3, time = 360, strikes = 3 },
    normal    = { label = 'Normal', modules = 4, time = 360, strikes = 3 },
    difficile = { label = 'Hard',   modules = 5, time = 300, strikes = 2 },
    expert    = { label = 'Expert', modules = 7, time = 420, strikes = 2 },
}

modules: number of modules · time: duration in seconds · strikes: tolerated mistakes. The keys (facile, normal…) are identifiers; only label is displayed.

#Game

OptionDefaultRole
Config.BlockCommstrueCuts phone, radio and calls during the game
Config.EndDelay8Seconds of end screen before players return
Config.BucketBase7300Routing bucket = BucketBase + arena index
Config.InteractDistance2.0Distance to interact with the bomb (client)
Config.MaxActionDistance4.0Server check (OneSync)
Config.ServerDistanceChecktrueEnables the server-side distance check
Config.LeashDistance25.0A player who strays further is put back
Config.BoomScreenEffect'ExplosionJosh3'Detonation screen effect

#Arenas

Lua
Config.Arenas = {
    { label = 'Legion Square', bomb = vector3(195.0, -933.0, 30.7), heading = 0.0 },
}
Sample coordinates

The coordinates provided (Legion Square) are an example: check them on your map. Z is snapped to the ground client-side. One arena = one possible simultaneous game.

Config.BombModels (prop_ld_bomb, prop_ld_suitcase_01): bomb model, the first existing one is used. Config.Table: tables, chairs, radius, seat height, chairHeadingOffset (set to 0.0 or 180.0 if the chairs face away from the table).

#Voice

Lua
Config.Voice = { enabled = true }

Uses MumbleSetVolumeOverrideByServerId: the deaf player sets the other two's volume to 0, everyone sets the mute player's to 0. Re-applied every 500 ms, restored to normal at the end of the game. pma-voice only rewrites these values for radio and calls, which are blocked during the game.

#Keys

Each player can change them in Settings → Key Bindings → FiveM.

Lua
Config.Keys = {
    interact = 'E',   -- blind: handle · deaf: look · mute: open the manual
    gesture  = 'G',   -- gesture menu
    slap     = 'H',   -- slap the nearest teammate
}

#Gestures

Config.Gestures lists the mute player's 24 gestures (numbers, actions, answers, colours). Each gesture: id, cat (section), text (bubble) or color + name, and anim (upper-body animation played while seated, from rpemotes' verified list). Config.GestureDuration (4000 ms) sets the bubble duration and Config.SlapAnim the slap animation.

The list is deliberately short to keep the game hard: no alphabet or questions.

#Full file

Show config.lua (184 lines)
config.luaDownload
Config = {}

-- ================================================================ Bridge / Compatibilité
-- Couche de compatibilité framework (bridge/*.lua). 'auto' détecte tout seul.
-- Compatibility layer. 'auto' detects everything by itself.
--   Framework : 'auto' | 'vision' | 'qbox' | 'qbcore' | 'esx' | 'standalone'  (auto : vision > qbox > qbcore > esx > standalone)
--   Inventory / Target / Society / Callbacks : 'auto' (non utilisés par ce script, présents pour le bridge commun)
--   Debug     : true = logs de détection dans la console serveur
--   Admins    : identifiants autorisés comme staff hors Vision, ex. { 'license:xxxxxxxx', 'discord:123456' }
--   AdminAce  : permission ACE donnant accès aux commandes staff hors Vision (add_ace group.admin command allow)
--   Standalone: réservé (surcharges éventuelles en mode standalone)
Config.Bridge = {
    Framework = 'auto',
    Inventory = 'auto',
    Target    = 'auto',
    Society   = 'auto',
    Callbacks = 'auto',
    Debug     = false,
    Admins    = {},
    AdminAce  = 'command',
    Standalone = {},
}

-- ================================================================ Intégrations optionnelles / Optional integrations
-- Aucune n'est obligatoire : si la ressource n'est pas démarrée, elle est simplement ignorée.
Config.Integrations = {
    logs     = true,   -- tc-logs : journal Discord (début / fin de partie, arrêt par un staff)
    lbphone  = true,   -- lb-phone : téléphone coupé pendant la partie (si Config.BlockComms)
    pmavoice = true,   -- pma-voice : radio / appels coupés pendant la partie (si Config.BlockComms)
}

-- ---------------------------------------------------------------- Accès (PNJ)
-- Le lobby s'ouvre en parlant au PNJ (touche E).
-- Sur Vision, le PNJ est géré par la gestion staff du serveur (menu gestion > interactions
-- « Bombe Banana ») : déplacement, modèle du ped, suppression. Les coords ci-dessous ne servent
-- alors qu'au premier démarrage. Sur les autres frameworks, le PNJ est créé directement
-- à ces coordonnées (ped local, blip, touche E).
-- Config.InteractId : identifiant du point côté Vision (préfixe « auto: » obligatoire) ; ignoré ailleurs.
Config.InteractId = 'auto:banana_defuse'
Config.Npc = {
    model  = 'a_m_y_hipster_01',
    coords = vector4(209.0, -925.5, 30.69, 160.0), -- hauteur de torse (le ped est posé 0.98 plus bas)
}
Config.Blip = { sprite = 486, color = 5, scale = 0.7, label = 'Bombe Banana' } -- sprite = nil : pas de blip
Config.InteractIcon     = 'Jobcenter'
Config.NpcDistance      = 2.0    -- distance pour parler au PNJ
Config.LobbyLeaveDistance = 60.0 -- au-delà du PNJ, un joueur du lobby (partie pas lancée) en est retiré

-- ---------------------------------------------------------------- Staff
-- Permissions staff VISION uniquement (PlayerGlobal.permissions) : il suffit d'en avoir UNE.
-- Sur ESX / QBCore / Qbox / standalone, le staff = admin du bridge (ACE Config.Bridge.AdminAce, groupe admin, Config.Bridge.Admins).
-- Donne /banana stop | arene et le lancement même si on n'est pas chef du lobby.
Config.Permissions = { 'staff_menu', 'gestion', 'dev' }

-- ---------------------------------------------------------------- Lobby
Config.Command          = 'banana'           -- /banana quitter | statut | stop | pnj | arene
Config.AdminOnlyStart   = false              -- true = seul le staff peut lancer depuis le menu
Config.AutoStart        = true               -- lance automatiquement quand 3 joueurs sont dans le lobby
Config.AutoStartDelay   = 15                 -- secondes avant le lancement auto
Config.DefaultDifficulty = 'normal'          -- le chef du lobby (1er inscrit) peut la changer dans le menu

Config.Difficulties = {
    facile    = { label = 'Facile',    modules = 3, time = 360, strikes = 3 },
    normal    = { label = 'Normal',    modules = 4, time = 360, strikes = 3 },
    difficile = { label = 'Difficile', modules = 5, time = 300, strikes = 2 },
    expert    = { label = 'Expert',    modules = 7, time = 420, strikes = 2 },
}

-- ---------------------------------------------------------------- Radio / téléphone
-- Pendant une partie : téléphone (lb-phone) désactivé, radio pma-voice coupée,
-- appels raccrochés (chaque intégration est optionnelle, voir Config.Integrations).
-- Tout est rétabli à la fin (la radio est à rallumer).
Config.BlockComms = true

-- ---------------------------------------------------------------- Partie
-- Le briefing de chaque rôle reste affiché jusqu'à ce que les 3 joueurs aient cliqué « Compris » :
-- la bombe ne s'arme qu'à ce moment-là (sinon /banana quitter).
Config.EndDelay         = 8      -- secondes d'écran de fin avant le retour des joueurs
Config.BucketBase       = 7300   -- routing bucket = BucketBase + index de l'arène (une partie isolée par arène)

-- Une arène = une partie simultanée possible. Les joueurs sont placés
-- automatiquement autour de la bombe. Le Z est recalé au sol côté client.
-- ⚠ Coordonnées d'exemple (Legion Square) : vérifiez-les sur votre map.
Config.Arenas = {
    { label = 'Legion Square', bomb = vector3(195.0, -933.0, 30.7), heading = 0.0 },
    -- { label = 'Arène 2', bomb = vector3(x, y, z), heading = 0.0 },
}

-- Modèle de la bombe (prop local). Vérifié au chargement avec IsModelInCdimage :
-- si le premier n'existe pas, le suivant est essayé, sinon seul le marqueur est affiché.
Config.BombModels = { 'prop_ld_bomb', 'prop_ld_suitcase_01' }

-- Table et chaises (props locaux, posés à l'identique chez les 3 joueurs).
-- La bombe est posée au centre de la table, les joueurs sont assis autour et se font face.
-- Premier modèle existant utilisé. chairHeadingOffset : à ajuster si les chaises
-- tournent le dos à la table (0.0 ou 180.0 selon le modèle).
Config.Table = {
    models  = { 'prop_table_04', 'prop_table_01', 'prop_table_02' },
    chairs  = { 'prop_table_04_chr', 'prop_table_02_chr', 'prop_chair_01a' },
    radius  = 0.95,               -- distance centre de la table → siège
    seatHeight = 0.5,             -- hauteur d'assise au-dessus du sol
    chairHeadingOffset = 180.0,
    scenario = 'PROP_HUMAN_SEAT_CHAIR_MP_PLAYER',
}

Config.InteractDistance  = 2.0   -- distance pour interagir avec la bombe (client)
Config.MaxActionDistance = 4.0   -- vérification serveur (nécessite OneSync, ignorée sinon)
Config.ServerDistanceCheck = true
Config.LeashDistance     = 25.0  -- un joueur qui s'éloigne plus que ça est replacé

-- Pas de vraie explosion : beaucoup d'anticheats bloquent les explosions créées par un client.
-- La « détonation » est un effet d'écran local + secousse + son.
Config.BoomScreenEffect  = 'ExplosionJosh3'

-- ---------------------------------------------------------------- Vocal
-- Utilise MumbleSetVolumeOverrideByServerId (native client FiveM) :
--  · le sourd met à 0 le volume des deux autres joueurs
--  · tous les joueurs de la partie mettent à 0 le volume du muet
-- Réappliqué toutes les 500 ms, remis à -1.0 (normal) en fin de partie.
-- pma-voice ne réécrit ces valeurs que pour la radio et les appels, bloqués pendant la partie.
Config.Voice = { enabled = true }

-- ---------------------------------------------------------------- Touches (modifiables par chaque joueur dans Paramètres > Raccourcis > FiveM)
Config.Keys = {
    interact = 'E',   -- aveugle : manipuler la bombe · sourd : regarder la bombe · muet : ouvrir le manuel
    gesture  = 'G',   -- menu des gestes
    slap     = 'H',   -- gifler le coéquipier le plus proche
}

-- ---------------------------------------------------------------- Gestes (émotes du muet)
-- Affichés au-dessus de la tête et dans le HUD (visibles par le sourd et le muet, pas par l'aveugle).
-- cat = rubrique du menu ; text = texte de la bulle ; color = carré de couleur.
-- anim = animation haut du corps jouée assis. Toutes viennent de la liste vérifiée de rpemotes.
local G  = 'gestures@m@standing@casual'
local GF = 'gestures@f@standing@casual'
local POINT   = { GF, 'gesture_point' }
local THUMBS  = { 'anim@mp_player_intupperthumbs_up', 'idle_a' }
local NO      = { 'mp_player_int_upper_nod', 'mp_player_int_nod_no' }
local SHRUG   = { GF, 'gesture_shrug_hard' }
local HAND    = { GF, 'gesture_hand_down' }
local PEACE   = { 'mp_player_int_upperpeace_sign', 'mp_player_int_peace_sign' }
local ME      = { G, 'gesture_me_hard' }
local HELLO   = { G, 'gesture_hello' }
local DAMN    = { G, 'gesture_damn' }
local NOWAY   = { G, 'gesture_no_way' }
local HURRY   = { 'misscommon@response', 'bring_it_on' }
local THINK   = { 'misscarsteal4@aliens', 'rehearsal_base_idle_director' }

-- Version courte (24 gestes) : volontairement limitée pour garder le jeu difficile.
-- Pas d'alphabet ni de questions : le muet doit se débrouiller avec OUI / NON / STOP
-- pendant que le sourd lit à voix haute (il l'entend).
Config.Gestures = {
    { id = 'n1', cat = 'Chiffres', text = '1', anim = POINT },
    { id = 'n2', cat = 'Chiffres', text = '2', anim = PEACE },
    { id = 'n3', cat = 'Chiffres', text = '3', anim = POINT },
    { id = 'n4', cat = 'Chiffres', text = '4', anim = POINT },
    { id = 'n5', cat = 'Chiffres', text = '5', anim = POINT },
    { id = 'n6', cat = 'Chiffres', text = '6', anim = POINT },

    { id = 'cut',     cat = 'Actions', text = 'COUPE',     anim = POINT },
    { id = 'press',   cat = 'Actions', text = 'APPUIE',    anim = POINT },
    { id = 'hold',    cat = 'Actions', text = 'MAINTIENS', anim = HAND },
    { id = 'release', cat = 'Actions', text = 'LÂCHE',     anim = HELLO },
    { id = 'up',      cat = 'Actions', text = 'HAUT',      anim = POINT },
    { id = 'down',    cat = 'Actions', text = 'BAS',       anim = HAND },
    { id = 'submit',  cat = 'Actions', text = 'VALIDE',    anim = THUMBS },

    { id = 'ok',   cat = 'Réponses', text = 'OUI',     anim = THUMBS },
    { id = 'no',   cat = 'Réponses', text = 'NON',     anim = NO },
    { id = 'what', cat = 'Réponses', text = '?',       anim = SHRUG },
    { id = 'stop', cat = 'Réponses', text = 'STOP',    anim = NOWAY },
    { id = 'wait', cat = 'Réponses', text = 'ATTENDS', anim = THINK },

    { id = 'c_rouge', cat = 'Couleurs', color = { 217, 59, 59 },   name = 'Rouge', anim = POINT },
    { id = 'c_bleu',  cat = 'Couleurs', color = { 47, 111, 224 },  name = 'Bleu',  anim = POINT },
    { id = 'c_jaune', cat = 'Couleurs', color = { 242, 194, 48 },  name = 'Jaune', anim = POINT },
    { id = 'c_vert',  cat = 'Couleurs', color = { 47, 179, 90 },   name = 'Vert',  anim = POINT },
    { id = 'c_blanc', cat = 'Couleurs', color = { 242, 242, 242 }, name = 'Blanc', anim = POINT },
    { id = 'c_noir',  cat = 'Couleurs', color = { 20, 20, 20 },    name = 'Noir',  anim = POINT },
}
Config.GestureDuration = 4000   -- ms d'affichage de la bulle

Config.SlapAnim = { 'melee@unarmed@streamed_variations', 'plyr_takedown_front_slap' }
Last updated : 7 November 2026© 2026 TC Script