Configuration
Every option in STG MDT shared/config.lua, from jobs, opening and the CAD to dispatch, permissions, evidence, forensics, ALPR, CCTV, billing and the EMS terminal.
All settings live in stg-mdt/shared/config.lua. The file stays editable in the escrow version, together with locales/ and integrations/. Restart the resource after a change.
Language
Config.Language = 'en'Available: en, de, fr, es, pt, it, nl, pl, sv, no, fi, cs, ar, he, jp, ko, zh. Messages live in stg-mdt/locales/<language>.lua and the tablet interface in stg-mdt/locales/ui/<language>.lua. In the interface files the key is the English text and the value is what the tablet shows, so you can also change the English wording in locales/ui/en.lua.
Jobs
Config.Jobs = {
police = { App = 'police', Label = 'Mission Row PD', CallsignPrefix = '1-A-' },
bcso = { App = 'police', Label = 'Blaine County SO', CallsignPrefix = '2-S-' },
sasp = { App = 'police', Label = 'San Andreas SP', CallsignPrefix = '3-H-' },
ambulance = { App = 'ems', Label = 'Pillbox Medical', CallsignPrefix = 'MED-' },
}
Config.RequireOnDuty = true
Config.RosterCheckInterval = 60Prop
Type
Opening the MDT
Config.Open = {
Command = { Enabled = true, Name = 'mdt' },
Keybind = { Enabled = true, Key = 'F6' },
Item = { Enabled = true, Name = 'stg_mdt_tablet', Required = false },
StationOnly = false,
Stations = {
{ App = 'police', Label = 'Mission Row PD', Coords = vec3(441.0, -982.0, 30.7), Radius = 60.0 },
{ App = 'ems', Label = 'Pillbox Medical', Coords = vec3(307.0, -595.0, 43.3), Radius = 60.0 },
-- more stations in the file
},
}Prop
Type
In-vehicle CAD
Config.Cad = {
Enabled = true,
Command = 'cad',
Keybind = '',
VehicleClasses = { 18 },
Models = {},
RefreshInterval = 500,
Laptop = {
Enabled = true,
Offset = vec3(0.12, 0.35, 0.3),
Turn = 30.0,
},
}Prop
Type
Tablet
Config.Tablet = {
Enabled = true,
Prop = 'stg_mdt_tablet',
Bone = 28422,
Offset = vec3(-0.05, 0.0, 0.0),
Rotation = vec3(0.0, 0.0, 0.0),
Dict = 'amb@code_human_in_bus_passenger_idles@female@tablet@idle_a',
Anim = 'idle_b',
Phase = 0.0,
Zoom = true,
}The tablet prop and animation used on foot. With Zoom = true the camera moves in and the MDT is drawn on the tablet's screen. Zoom only works with the included stg_mdt_tablet prop.
Callsigns and photos
Config.Callsign = { MaxLength = 10 }
Config.Mugshot = {
Enabled = true,
StartDelay = 20,
RefreshMinutes = 30,
MaxBytes = 80000,
Debug = false,
}Players change their own callsign by clicking the unit chip. Every player's game takes a headshot of their own character for citizen, warrant and patient profiles. Turn on Debug if photos do not show up, it prints each step in the F8 console.
Booking photos
Config.Booking = {
Enabled = true,
MaxDistance = 6.0,
CameraDistance = 1.0,
Fov = 32.0,
Width = 300,
Height = 375,
Quality = 0.8,
MaxBytes = 120000,
}Right, front and left photos of the suspect, taken from the arrest report. Needs screencapture or screenshot-basic. MaxDistance is how close the officer has to stand.
Phone trace
Config.PhoneTrace = {
Enabled = true,
Phone = 'auto',
Minutes = 30,
SelfApprove = true,
ViewAll = false,
HistoryHours = 48,
Accuracy = 60.0,
RefreshSeconds = 20,
PhoneItems = { 'phone', 'black_phone', 'blue_phone' },
}Prop
Type
The supported phones and their database queries are in integrations/phones.lua. See Integrations.
Permissions
Config.Permissions = {
AssignUnits = 0,
ApproveReports = 2,
SignWarrants = 2,
CancelWarrants = 3,
DeleteEvidence = 3,
Impound = 0,
ManageLicenses = 1,
DeleteRecords = 2,
DeleteReports = 3,
RequestPhoneTrace = 0,
ApprovePhoneTrace = 3,
Broadcast = 1,
}The minimum job grade for each action, using your framework's job grades. Officers can always delete their own report drafts.
Units
Config.Units = {
LocationInterval = 5000,
PushInterval = 5000,
Statuses = {
['10-8'] = { Label = 'Available', Tone = 'brand' },
['10-76'] = { Label = 'En route', Tone = 'hot' },
-- more statuses in the file
},
}Statuses are the unit status codes, Tone colors them (brand, hot or empty).
Dispatch
Config.Dispatch = {
ClosedRetention = 60,
MaxCalls = 60,
SelfDispatch = {
{ Code = '10-11', Title = 'Traffic stop' },
{ Code = '10-80', Title = 'Pursuit', Priority = true },
},
Backup = { Code = '10-78', Title = 'Officer needs backup' },
Panic = { Code = '10-99', Title = 'Officer down' },
Pursuit = { Code = '10-80', Title = 'Pursuit in progress' },
Blips = { Enabled = true, Sprite = 161, Scale = 1.0, Color = 1, PriorityColor = 49, Duration = 300 },
Sounds = true,
CitizenCalls = {
Enabled = true,
Police = { Command = '911', Code = '911', Title = 'Citizen call' },
Ems = { Command = '912', Code = 'MED-01', Title = 'Medical call' },
Cooldown = 60,
Zone = { Enabled = true, Radius = 120.0, Duration = 120, BlipColor = 1, BlipAlpha = 110 },
},
}Prop
Type
Other scripts can create calls too, see Integrations.
Penal code and citations
Config.PenalCode = {
{ Id = 't1', Title = 'Driving without a license', Description = 'Operating a vehicle without a valid license.', Fine = 500, Extra = '', Level = 2, Category = 'traffic' },
-- more charges in the file
}
Config.Citations = {
MaxCustomFine = 50000,
MaxTotal = 100000,
}Category is traffic or order, Level is 1 to 3. Extra is a short note shown on the charge. Officers can also write custom charges up to MaxCustomFine.
Billing
Config.Billing = {
ConsentSeconds = 30,
Mode = 'consent',
}| Mode | What bills and citations do |
|---|---|
consent | The citizen gets a pay or decline prompt, the money comes out of their bank |
log | Only written on the MDT record, no money is taken |
esx_billing | Added to the ESX billing table |
custom | Handed to your billing script in integrations/billing.lua |
Health plans always ask the citizen first. You can add any billing script as a new mode, see Integrations.
Config.Pdf = {
Enabled = true,
BaseUrl = '',
LinkMinutes = 10,
Header = 'San Andreas Public Records',
}Reports download as PDF from the FXServer HTTP port. Leave BaseUrl empty to use the address players connected with. Set it when the server is behind a proxy, for example https://play.myserver.com.
Licenses and reports
Config.Licenses = { 'driver', 'weapon', 'pilot', 'hunting', 'business' }
Config.Reports = {
Types = {
{ Name = 'Traffic stop', Fields = { 'Vehicle', 'Plate', 'Violation', 'Outcome' } },
{ Name = 'Arrest', Fields = { 'Charges', 'Rights read', 'Transported to', 'Booking number' } },
{ Name = 'Custom', Fields = {} },
},
MaxFields = 12,
Roles = { 'Suspect', 'Victim', 'Witness' },
Templates = {
{ Title = 'Arrest', Text = 'Subject [name] was arrested at [location] for [charges]...' },
},
}
Config.Warrants = { ExpireDays = 14, DefaultBail = 25000 }Licenses are read from metadata.licences on QBCore and QBOX, and from the user_licenses table on ESX. Report types start with their own detail fields, templates fill the narrative. Warrants written below the SignWarrants grade wait for a supervisor.
Evidence
Config.Evidence = {
LabMinutes = 30,
DefaultLocation = 'Intake shelf',
ItemImages = 'nui://ox_inventory/web/images/%s.png',
Locker = {
Enabled = true,
Slots = 30,
Weight = 100000,
},
}Every report gets its own evidence locker, opened from the report. With ox_inventory items put in are logged on the report and tagged with their evidence number. ItemImages is where item images are loaded from, for qb-inventory use nui://qb-inventory/html/images/%s.png. LabMinutes is how long a lab request on an evidence item takes.
Forensics
Config.Forensics = {
Enabled = true,
Item = 'stg_blood_sample',
DropMinutes = 30,
LabMinutes = 60,
Lab = {
Label = 'Crime lab',
Model = 's_m_m_scientist_01',
Coords = vec4(441.0534, -995.2778, 30.6896, 44.2730),
},
}Players hit by a gun or a blade leave blood. Police collect it as a sealed sample item and hand it to the lab technician at Lab.Coords. After LabMinutes the evidence in the MDT shows whose blood it is. Blood dries up after DropMinutes.
Vehicles
Config.Vehicles = {
ImpoundPrice = 500,
Images = { gauntlet4 = 'gauntlet4', sultan = 'sultan' },
ClassImages = { [0] = 'blista', [18] = 'ambulance' },
DefaultImage = 'buffalo2',
}ImpoundPrice is the cost to release an impounded vehicle. The images pick the vehicle picture from web/assets/img, by model first, then by class. How impounding is saved is set in integrations/garage.lua.
ALPR
Config.Alpr = {
Enabled = true,
Command = 'alpr',
SettingsCommand = 'alprsettings',
Keys = { Toggle = 'F11', Lock = 'F9', Reset = 'F10', Lane = 'NUMPAD5' },
Radar = {
Unit = 'kmh',
DefaultLimit = 60,
Limits = { ['Los Santos Freeway'] = 120 },
},
AlertSeconds = 12,
CallCode = 'ALPR',
LaneWidth = 4.0,
ScanByDefault = true,
Hud = { Position = 'bottom-right' },
ShareHits = true,
ShareCooldown = 120,
ShareBlipSeconds = 90,
Range = 30.0,
Interval = 250,
Cooldown = 30,
MaxReads = 30,
}Prop
Type
CCTV
Config.Cctv = {
Cameras = {
{ Id = 'CAM-0418', Name = 'Legion Square', Coords = vec3(195.7, -933.6, 36.0), Rotation = vec3(-20.0, 0.0, 140.0), Facing = 'West', Online = true },
-- more cameras in the file
},
MinFov = 20.0,
MaxFov = 70.0,
Timecycle = 'CAMERA_secuirity',
TimecycleStrength = 1.0,
ExtraTimecycle = 'scanline_cam_cheap',
HideRadar = true,
SnapshotToEvidence = true,
Discord = {
Webhook = '',
Quality = 0.85,
},
}Add a camera with its position and starting rotation. Snapshots are logged as evidence. With a Discord Webhook, the photo is posted there and officers can open it from the evidence log. Set a Timecycle to '' to turn that screen effect off.
EMS
Config.Ems = {
Hospital = 'Pillbox Medical',
HospitalCoords = vec3(311.0, -590.0, 43.3),
HospitalRadius = 80.0,
Beds = { 'Trauma 1', 'Trauma 2', 'Bed 3', 'Bed 4' },
Reception = {
Enabled = true,
Command = 'checkin',
Coords = vec3(308.0, -595.0, 43.3),
Radius = 6.0,
Ped = {
Model = 's_f_y_scrubs_01',
Coords = vec4(305.3798, -597.4440, 43.2918, 20.4048),
},
Reasons = { 'Injury', 'Feeling sick', 'Check-up', 'Prescription refill', 'Visiting a patient' },
},
Plans = {
{ Name = 'BASIC', Price = 50, Ems = 50, Pharmacy = 15, Ambulance = 50, Surgery = 0 },
{ Name = 'PREMIUM', Price = 150, Ems = 100, Pharmacy = 50, Ambulance = 100, Surgery = 75, BestValue = true },
},
PlanDays = 7,
MaxBill = 100000,
Medications = { 'Morphine 10 mg', 'Saline 500 ml', 'Bandage kit' },
SupplyUse = 10,
InjuryTypes = { 'Gunshot wound', 'Stab wound', 'Fracture', 'Burn' },
InjurySeverity = { 'Minor', 'Moderate', 'Serious', 'Critical' },
MaxInjuries = 20,
}Prop
Type
BodyMap and WoundLevels at the end of the block set up the injury body map, leave them as they are unless you change the image.
Next steps
Integrations
Connect your own phone, inventory, billing or garage script
Dependencies
What needs to start before the MDT
Still having trouble?
Open a ticket on our Discord. Our team answers around 15 hours a day.