Configuration
Overview
shared/config.lua: Global settings, vehicle defaults, commandsserver/config_questions.lua: Server-only quiz questions and profiles (clients never receive them)server/config_sv.lua: Discord webhooks and log togglesshared/data/terminals/*.lua: Individual terminal definitions (one file per terminal)
General
1Config.Debug = false
2Config.Locale = 'en'
3Config.Interaction = 'target'Debug: Console output. Keep off in production.Locale: Language code. See thelocales/folder.Interaction:'target'for auto-detected target system,'textui'to force 3D Text UI
Vehicle Defaults
1Config.Vehicles = {
2 garage = '',
3 plateFormat = 'LLNNNN',
4 defaults = {
5 fuel = 50, engine = 1000, body = 1000, tank = 1000,
6 },
7}Used when a quiz profile awards a vehicle as a reward.
Commands
1Config.Commands = {
2 theme = 'mltheme',
3 setup = 'mlterminalsetup',
4 props = 'mltoggleprops',
5}Discord Webhooks
1Config.DiscordWebhook = {
2 Default = 'YOUR_WEBHOOK',
3 Test = 'YOUR_WEBHOOK',
4 Minigame = 'YOUR_WEBHOOK',
5 Actions = 'YOUR_WEBHOOK',
6 Doors = 'YOUR_WEBHOOK',
7}Set any webhook to false to disable that log channel entirely.
1Config.DiscordWebhook = {
2 Default = 'YOUR_WEBHOOK',
3 Test = false, -- Disables all quiz-related logs
4 Minigame = false, -- Disables all minigame logs
5 Actions = 'YOUR_WEBHOOK',
6 Doors = 'YOUR_WEBHOOK',
7}Log Toggles
Each log event can be individually routed to a channel or disabled:
1Config.Log = {
2 TestResult = Config.DiscordWebhook.Test,
3 TestConfirmedFailure = Config.DiscordWebhook.Test,
4 ForceConfirm = Config.DiscordWebhook.Test,
5 ExecuteAction = Config.DiscordWebhook.Actions,
6 MinigameSuccess = Config.DiscordWebhook.Minigame,
7 PasswordFailed = Config.DiscordWebhook.Minigame,
8 DoorToggle = Config.DiscordWebhook.Doors,
9}Set any individual log to nil to disable it while keeping its channel active for other logs.
Log Batching
1Config.LogSettings = {
2 Color = 3066993,
3 Interval = 60000, -- Sends logs every 60 seconds
4}Do not set Interval below 60000 ms. Discord will rate-limit your webhook and logs will be dropped.
Terminal Configuration
Each terminal is defined as a separate Lua file in shared/data/terminals/. Copy a bundled example such as example_full.lua and configure only the sections you need.
Section 1: Base (Required)
1Config.Terminals['my_terminal'] = {
2 label = 'Use Terminal',
3 model = 'ba_prop_battle_club_computer_01',
4 coords = vector4(100.0, 200.0, 30.0, 180.0),
5 theme = 'theme-default',
6}label: Text shown on the target/textui interactionmodel: GTA prop model hashcoords: Position and heading asvector4theme: UI theme (see below)
Multi-Location: Replace coords with locations to spawn the same terminal at multiple positions:
1locations = {
2 vector4(100.0, 200.0, 30.0, 180.0),
3 vector4(110.0, 200.0, 30.0, 90.0),
4},Available Themes
theme-default: Industrial Orangetheme-wasteland: Rust / Post-Apocalyptictheme-cyberpunk: Neon Magentatheme-noir: Blood Redtheme-fantasy: Goldtheme-fruit: Fresh Greentheme-vintage-yellow: Retro Yellowtheme-vintage-blue: Retro Bluetheme-facade98-teal: Windows 98 Teal
Section 2: Spawn
1spawn = {
2 distance = 15.0,
3 texture = 'prop_computer_screen',
4}distance: Prop create/destroy streaming distancetexture: DUI replacement texture name (depends on the prop model)
Section 3: Camera
1camera = {
2 enabled = true,
3 distance = 0.5,
4 height = 0.35,
5 offset = 0.3,
6 fov = { start = 70, final = 50 },
7 transition = 1500,
8}enabled: Toggle cinematic camera when using the terminaldistance: How close the camera sits to the prop faceheight: Camera height offset relative to the prop centeroffset: Z offset for screen centerfov: Field of view transition (start → final)transition: Camera movement duration in ms
Section 4: Access Control
1access = {
2 exclusive = true,
3 showClose = true,
4 job = 'police',
5 item = 'keycard',
6}exclusive: Only one player at a timeshowClose: Show X button in UIjob: Restrict to a specific job. Setnilfor no restrictionitem: Require an item in inventory. Setnilfor no restriction
Section 5: UI Customization
1ui = {
2 header = 'SYSTEM v2.0',
3 bootLines = {
4 '> Initializing system...',
5 '> Loading modules...',
6 '> System ready.',
7 },
8 logo = {
9 text = 'MICIO OS',
10 duration = 3000,
11 },
12}header: Text shown in the terminal header barbootLines: Array of strings displayed with typewriter effect during bootlogo.text: Text-based logo during boot (or uselogo.imagefor an image file)logo.duration: How long the logo screen is shown (ms)
App Types
Apps are the interactive modules on the terminal desktop. Each app has a type that determines its behavior.
quiz
Psychometric test with randomized questions, skill-based scoring, profile assignment, and rewards.
1{
2 name = 'Psychometric Test',
3 icon = 'fa-solid fa-brain',
4 type = 'quiz',
5}Requires a quiz section in the terminal config (see below).
folder
File browser with text-based files.
1{
2 name = 'Documents',
3 icon = 'fa-solid fa-folder-open',
4 type = 'folder',
5 files = {
6 { name = 'readme.txt', content = 'File content here.' },
7 { name = 'log.dat', content = 'Entry 01: all clear.' },
8 },
9}doors
Door control panel. Requires a doors section.
1{
2 name = 'Door Control',
3 icon = 'fa-solid fa-door-open',
4 type = 'doors',
5}actions
Action panel with cooldown-based buttons that trigger events. Requires an actions section.
1{
2 name = 'Operations',
3 icon = 'fa-solid fa-bolt',
4 type = 'actions',
5}minigame
Standalone minigame from the desktop.
1{
2 name = 'Decrypt',
3 icon = 'fa-solid fa-lock',
4 type = 'minigame',
5 minigame = 'password',
6 difficulty = 5,
7}locked_folder
Folder locked behind a minigame. Can also be gated behind a quiz result.
1{
2 name = 'Classified Files',
3 icon = 'fa-solid fa-file-shield',
4 type = 'locked_folder',
5 unlock = 'password',
6 unlockDifficulty = 5,
7 files = {
8 { name = 'secret.dat', content = 'CLASSIFIED CONTENT' },
9 },
10 requireQuiz = true,
11 requiredProfile = 'tactician',
12}Doors Section
1doors = {
2 title = 'DOOR PANEL',
3 list = {
4 { id = 1, label = 'Main Entrance' },
5 { id = 2, label = 'Server Room' },
6 },
7}id: Must match the door ID in your door lock systemlabel: Display name in the UI
Actions Section
1actions = {
2 title = 'OPERATIONS PANEL',
3 list = {
4 {
5 id = 'alarm',
6 label = 'Activate Alarm',
7 icon = 'fa-solid fa-bell',
8 desc = 'Activate the alarm system.',
9 cooldown = 30,
10 trigger = {
11 type = 'client',
12 event = 'myScript:triggerAlarm',
13 args = { zone = 'main' },
14 },
15 },
16 },
17}id: Unique action identifiercooldown: Seconds before the player can re-usetrigger.type:'client'or'server'trigger.event: Event name to firetrigger.args: Arguments passed to the event handler
Minigames Section
1-- These two live at the terminal root, NOT inside minigames:
2passwordLockoutDuration = 30, -- Lockout seconds after a failed attempt
3lockoutType = 'personal', -- 'global' locks everyone, 'personal' only the player
4
5minigames = {
6 onBoot = 'password', -- 'password' | 'memory' | 'pipePuzzle' | 'simonSays' | nil
7
8 password = {
9 difficulty = 5, -- Word length (3-10)
10 attempts = 4,
11 brackets = true,
12 bonusClicks = 2,
13 words = { 'NEXUS', 'VIPER', 'GHOST', 'RAVEN' },
14 },
15
16 memory = {
17 difficulty = 2, -- 1=easy, 2=medium, 3=hard
18 gridSize = 4, -- 4=4x4, 6=6x6
19 timeLimit = 60,
20 },
21
22 pipePuzzle = {
23 difficulty = '4x4', -- '3x3' easy, '4x4' medium, '5x5' hard
24 timeLimit = 60,
25 },
26
27 simonSays = {
28 sequenceLength = 6, -- 4=easy, 6=medium, 8=hard
29 timeLimit = 30,
30 },
31}onBoot: Require a minigame before reaching the desktop. The four minigames are password, memory, pipePuzzle, simonSays. Setnilfor no boot minigame.passwordLockoutDuration: Seconds before the player can retry after a failure (set at the terminal root, not insideminigames)lockoutType:'global'locks all players,'personal'locks only the failing player.
Quiz Section
1-- Terminal root, client-safe quiz controls:
2showRewards = true,
3reopenifcompleted = false,
4allowRetakeOnSuccess = false,
5allowRetakeOnFailure = true,
6
7quiz = {
8 title = 'PSYCHOMETRIC ANALYSIS',
9 startButton = 'Start Analysis',
10 questionCount = 3, -- Random questions pulled from the server pool
11 fingerprint = true, -- Require a fingerprint scan before starting
12}questionCount: Number of random questions picked from the server poolshowRewards/reopenifcompleted: terminal-root flags: show the reward summary; allow reopening after completionfingerprint: Require a fingerprint scan before startingallowRetakeOnSuccess: terminal-root flag: allow retake after receiving a profileallowRetakeOnFailure: terminal-root flag: allow retake after failing to meet any threshold- Questions and profiles are defined server-side (anti-cheat). Profile rewards can include
money,items,vehicleandjob({ name, grade })
Questions & Profiles (Server-Only)
Questions and profiles never reach the client. Define them in server/config_questions.lua under TerminalQuestions['terminal_id'], using the SAME terminal ID:
1TerminalQuestions['my_terminal'] = {
2 questions = {
3 {
4 question_key = 'How do you handle pressure?',
5 answers = {
6 { text_key = 'I analyze and plan', value = { skill = 'tactical', points = 15 } },
7 { text_key = 'I act on instinct', value = { skill = 'combat', points = 15 } },
8 },
9 },
10 },
11 profiles = {
12 {
13 id = 'tactician',
14 name = 'PROFILE: TACTICIAN',
15 description = 'Strategic mind, born leader.',
16 points_required = { skill = 'tactical', amount = 11 },
17 rewards = {
18 money = 5000,
19 items = { { name = 'radio', amount = 1 } },
20 job = { name = 'police', grade = 0 },
21 vehicle = { name = 'police' },
22 },
23 },
24 {
25 id = 'recruit',
26 name = 'PROFILE: RECRUIT',
27 description = 'Fallback, always matchable (no points_required).',
28 rewards = { money = 0 },
29 },
30 },
31}question_key/text_key: question and answer text shown in the UIvalue: score for an answer:{ skill, points }points_required: profile threshold:{ skill, amount }. First matching profile wins (order = priority); a profile with nopoints_requiredis the fallback.rewards:money,items({ name, amount }),job({ name, grade }),vehicle({ name = "model" })
Kiosk Mode
Transforms the terminal into a single-app experience with no desktop.
1kiosk = {
2 mode = 'simple',
3 app = 'doors',
4}mode = 'simple': Opens the app directly, no boot or minigamemode = 'locked': Requires a minigame to unlock, access expires afterunlockDurationseconds
1kiosk = {
2 mode = 'locked',
3 app = 'doors',
4 unlockGame = 'password',
5 unlockDuration = 300,
6}