MDT & Businesses
Post dispatch calls, bulletins and tow requests to the MDT, read its records, and take over business orders from another resource.
The MDT is the records app for the police, EMS and mechanic departments, and the till for player-run businesses. Other resources post calls on its dispatch board, post bulletins and calendar events, set unit statuses, register weapon sales, read medical records, death and roadworthiness certificates, dispense prescriptions at a pharmacy, and make a business's orders, such as a cooking script for a restaurant.
Departments are set in shared/unlocked/mdt.lua: the defaults are lspd (police), sams (EMS), autorepair (mechanic) and digitalden (Digital Den). Businesses are the blocks under Config.Businesses in shared/unlocked/business.lua, and each makes a department of its own with the block's key as its id, such as burgershot. A departmentId on this page is one of those ids. See the Config.
These exports only exist while Config.Mdt.enabled is true. SendMdtAlert and CreateMdtCall also need Config.Mdt.dispatch.enabled. The business exports need Config.Business.enabled and a business that is enabled, or they return false. A resource that works without the MDT wraps its calls in pcall.
General Information
SendMdtAlertis a client export. Every other export on this page is a server export.A character is named by its framework identifier, the same one the MDT's person records use. Plates are read in upper case with single spaces, as the plate reads on the car.
Exports marked Yields wait on the database. Call them from a thread, an event handler or a command, not while your script loads. Until the MDT's tables are ready on start they return
nil,falseor an empty list.Who may use the app is checked with the
CanUseMdtandCanUseMdtPermissionhooks inserver/unlocked/hooks.lua, andCanSellBusinessItemcan refuse a business line. See Can-Check Hooks.
Types / Classes
MdtPatient,MdtDeathCertificate,MdtRoadworthinessandMdtHistoryEntryare intypes/mdt.lua, andBusinessOrderandBusinessOrderLineintypes/business.lua, insidezyke_laptop.
#Client Sided Exports
#Send Mdt Alert
Posts a call on the dispatch board from the player's client, for a robbery, an alarm or a shooting script that runs on the client. The server places the call where it sees the player.
coordsis used only when it is within 150 m of the player, and the call is placed at the player otherwise. Withoutlocation, the street the call is on is used. The call's source is the resource that called the export.It takes the same fields as Create Mdt Call, with
coordsoptional. Nothing is returned. The server drops the alert without a word when the data isn't valid, no department matches, or the player sent more thanrateLimits.alertalerts (6 in 60 seconds by default). The same alert again within two minutes and 30 m adds a note to the open call instead of posting another. A new call fireszyke_laptop:mdt:CallCreatedwith the player's server id.Example:
lua---@param data {title: string, description?: string, code?: string, priority?: integer, coords?: vector3, location?: string, departments?: string | string[], jobs?: string | string[], types?: string | string[], caller?: string, details?: table} exports["zyke_laptop"]:SendMdtAlert({ title = "Store robbery", code = "10-90", priority = 1, description = "Silent alarm at the register.", jobs = "leo", details = {sex = "m", weapon = "Pistol", camera = "12"}, })
#Dispatch
Calls go to the departments in departments, else to those of the framework jobs in jobs, else to every department of the types in types, else to every police department. jobs also takes job types: leo, police and sheriff reach the police departments, ems, ambulance, medic, doctor and fire the EMS ones, and mechanic and tow the mechanic ones. Each list is a string or up to 8 strings. Business departments take no calls.
Scripts written for ps-dispatch, cd_dispatch, qs-dispatch or rcore_dispatch keep working while that resource isn't started: the MDT answers their exports and events and posts the calls here. The named alerts they send are listed in shared/unlocked/mdt_shims.lua, and Config.Mdt.dispatch.shims turns each shim off.
#Create Mdt Call
Posts a call on the dispatch board and notifies the on-duty members of new priority 1 and 2 calls. Returns the call id, or
nilwhen the data isn't valid or no department matches. The sametitlefrom the samesourcewithin two minutes and 30 m of an open call adds a note to that call and returns its id. A new call fireszyke_laptop:mdt:CallCreatedwithplyId0. Yields.Example:
lua---@param data {title: string, coords: vector3 | {x: number, y: number, z?: number}, description?: string, code?: string, priority?: integer, location?: string, departments?: string | string[], jobs?: string | string[], types?: string | string[], caller?: string, source?: string, details?: table} ---@return integer? callId local callId = exports["zyke_laptop"]:CreateMdtCall({ title = "Bank alarm", code = "10-90", priority = 1, coords = vector3(150.2, -1040.1, 29.4), location = "Fleeca Bank, Legion Square", description = "Vault door forced.", types = {"police"}, caller = "Fleeca Security", })
| Field | Default | Description |
|---|---|---|
title | Required | Up to 120 characters. |
coords | Required | Where the call is. A vector3 or {x, y, z?}. |
description | None | Up to 1000 characters, line breaks kept. |
code | None | Up to 16 characters, such as "10-90". The codes members pick from are in dispatch.codes. |
priority | 2 | 1 urgent, 2 normal or 3 low. Any other value makes the call invalid. |
location | None | The place, up to 80 characters. |
departments | None | Department ids. |
jobs | None | Framework job names or job types. |
types | "police" | Department types: "police", "ems" or "mechanic". |
caller | None | Who called it in, up to 64 characters. |
source | The calling resource | Shown on the note of a repeated call, and part of what makes two calls the same. |
details | None | {vehicle?, plate?, sex?, weapon?, camera?}. The server adds a line for each to the description, in the server's language. sex is "m" or "f". |
#Set Mdt Unit Status
Sets a player's unit status in their department, such as
"enroute"when a dispatch resource assigns them to a call.statusis a status id of the department'sstatuses. Returnsfalsewhen the player's job belongs to no department or the department has no such status. Setting the status they already have returnstrueand changes nothing. Fireszyke_laptop:mdt:StatusChanged.Example:
lua---@param plyId integer ---@param status string ---@return boolean set exports["zyke_laptop"]:SetMdtUnitStatus(plyId, "enroute")
#Department
#Get Mdt Department
Returns the id of the department whose MDT the player may use right now, or
nil. A player whose department hasrequireDutymust be on duty, andCanUseMdtmust allow them.Example:
lua---@param plyId integer ---@return string? departmentId local departmentId = exports["zyke_laptop"]:GetMdtDepartment(plyId)
#Create Mdt Bulletin
Posts a bulletin as the department itself, with the department's short name as the author. The department's online members are notified. Returns the bulletin id, or
nilfor an unknown department or invalid data. Fireszyke_laptop:mdt:BulletinPostedwithplyId0. Yields.Example:
lua---@param departmentId string ---@param data {title: string, body: string, priority?: "info" | "important", mustAck?: boolean, expiresAt?: integer} ---@return integer? bulletinId local bulletinId = exports["zyke_laptop"]:CreateMdtBulletin("lspd", { title = "Court closed Friday", body = "All hearings move to Monday. Check the calendar for the new times.", priority = "important", mustAck = true, expiresAt = os.time() + 3 * 86400, })
| Field | Default | Description |
|---|---|---|
title | Required | Up to 120 characters. |
body | Required | Up to 4000 characters, line breaks kept. |
priority | "info" | "info" or "important". |
mustAck | false | true asks every member to mark it read. |
expiresAt | None | Unix seconds, in the future. |
#Create Mdt Event
Adds a calendar event as the department itself. Attendees are notified when they are online. Returns the event id, or
nilfor an unknown department or invalid data. Yields.Example:
lua---@param departmentId string ---@param data {kind: string, title: string, start: integer, end: integer, location?: string, coords?: {x: number, y: number, z?: number}, notes?: string, attendees?: string[]} ---@return integer? eventId local eventId = exports["zyke_laptop"]:CreateMdtEvent("lspd", { kind = "court", title = "Hearing: Smith", start = os.time() + 3600, ["end"] = os.time() + 7200, location = "Courthouse, Room 2", attendees = {officerIdentifier}, })
| Field | Default | Description |
|---|---|---|
kind | Required | A kind of the department's calendarKinds, such as "court". |
title | Required | Up to 80 characters. |
start, end | Required | Unix seconds. end is after start, at most limits.eventDays (14) days later. end is a Lua keyword, so write it as ["end"]. |
location | None | Up to 80 characters. |
coords | None | {x, y, z?}. |
notes | None | Up to 1000 characters. |
attendees | None | Up to 30 character identifiers. They must be members of the department, unless the kind has external = true, such as "appointment". One that isn't makes the event invalid. |
#Get Mdt Person Flags
Returns the flag ids the department set on the character's record, such as
"armed". Flags no longer in the department's config are left out. Returns an empty list for an unknown department or a character without flags. Yields.Example:
lua---@param departmentId string ---@param identifier string ---@return string[] flags local flags = exports["zyke_laptop"]:GetMdtPersonFlags("lspd", identifier)
#Police
#Register Mdt Weapon
Registers a weapon to a character in the police weapons registry, which every police department shares, such as when a gun shop sells one. A serial already in the registry moves to the new owner and is set back to registered. The serial is 3 to 32 letters, digits and
-, read in upper case.modelLabelis up to 64 characters. Returnsfalsefor an invalid serial, identifier or label. Yields.Example:
lua---@param identifier string ---@param serial string ---@param modelLabel string ---@return boolean registered exports["zyke_laptop"]:RegisterMdtWeapon(identifier, "AMM-48213", "Pistol .50")
#Medical
#Get Mdt Patient
Returns the character's medical record, shared by every EMS department, or
nilwhen EMS never wrote one.bloodTypeis"unknown"when it isn't set, andinsuranceis the first EMS department's default tier when the record has none. Yields.Example:
lua---@param identifier string ---@return MdtPatient? patient @ {bloodType, allergies, conditions, medications, dnr, organDonor, emergencyContact, insurance, notes} local patient = exports["zyke_laptop"]:GetMdtPatient(identifier) if (patient and patient.dnr) then -- Do not resuscitate end
#Get Mdt Death Certificate
Returns the character's death certificate, or
nilwithout one. A character has one at most: issuing it again replaces it.manneris"natural","accident","homicide","suicide","undetermined"or"pending". Yields.Example:
lua---@param identifier string ---@return MdtDeathCertificate? certificate @ {id, identifier, name, at, location, cause, manner, reportId?, certifiedBy, certifiedByName, certifiedAt} local certificate = exports["zyke_laptop"]:GetMdtDeathCertificate(identifier)
#Dispense Mdt Prescription
Dispenses an active prescription once, for a pharmacy resource. A prescription with refills left stays active with one refill fewer, and one without refills becomes dispensed, so a prescription with 2 refills is dispensed 3 times. Returns what to hand over, or
nilwhen the prescription doesn't exist or isn't active. Yields.The prescription id is on the printed prescription: with
printPrescriptions = trueon the department, the paper document's item metadata has it asprescription, next tomedication,doseandquantity.Example:
lua---@param prescriptionId integer ---@return {identifier: string, medication: string, label: string, dose: string, quantity: integer, refillsLeft: integer}? dispensed local dispensed = exports["zyke_laptop"]:DispenseMdtPrescription(item.metadata.prescription) if (dispensed) then -- dispensed.medication is the catalogue id in shared/unlocked/mdt_medical.lua exports.ox_inventory:AddItem(plyId, dispensed.medication, dispensed.quantity) end
#Mechanic
#Create Mdt Tow Request
Posts a tow request to a mechanic department's tow queue in the department's own name, such as from a dispatch or after a crash. The department's on-duty members are notified. Returns the request id, or
nilwhen the department isn't a mechanic one or the data isn't valid. Fireszyke_laptop:mdt:TowRequestedwithplyId0. Yields.Example:
lua---@param departmentId string ---@param data {plate?: string, coords?: vector3 | {x: number, y: number, z?: number}, location?: string, reason?: string, source?: "export" | "police"} ---@return integer? towId local towId = exports["zyke_laptop"]:CreateMdtTowRequest("autorepair", { plate = "46EEK572", coords = vector3(-212.4, -1325.8, 30.9), location = "Strawberry Ave", reason = "Collision, front wheel off", })
| Field | Default | Description |
|---|---|---|
plate | None | The vehicle's plate. |
coords | None | Where the vehicle is. Either coords or location is needed. |
location | None | The place, up to 80 characters. |
reason | None | Up to 200 characters. |
source | "export" | "police" shows it as a police request. |
#Get Mdt Certificate
Returns the plate's newest roadworthiness certificate from any shop, passed or failed, or
nilwithout one. A failed one expires the moment it is issued, so check bothpassedandexpiresAt. Yields.Example:
lua---@param plate string ---@return MdtRoadworthiness? certificate @ {id, plate, passed, at, expiresAt, by, byName, orderId?} local certificate = exports["zyke_laptop"]:GetMdtCertificate(plate) local roadworthy = certificate ~= nil and certificate.passed and certificate.expiresAt > os.time()
#Get Mdt Service History
Returns everything the shops know of the plate, newest first, up to 50 entries: repair orders, inspections, odometer readings, roadworthiness certificates, finished tows and zyke_towing rope tows, the impound it is in through zyke_garages, and its current mileage through zyke_lib. Returns an empty list for an invalid plate. Yields.
kindis"order","inspection","certificate","tow","impound"or"mileage".detailis the order's status, an inspection's green/yellow/red counts such as"12/3/0","passed"or"failed", a tow's reason or"rope", the impound fee, or the miles.Example:
lua---@param plate string ---@return MdtHistoryEntry[] entries @ {at, kind, label, refId?, detail?, stars?} local entries = exports["zyke_laptop"]:GetMdtServiceHistory(plate)
#Businesses
Lines with prepare = true in a business's catalogue are made to order: with orders.enabled on the business they open an order on its Orders tab and order screens, from the counter or from the website. Staff tick the lines off, mark the order ready and hand it over at the counter. These exports let another resource make the lines instead, such as a cooking script.
#Set Business Line Handler
Sets the function called for every line of each new order of the business.
orderis the order without the customer's identifier,indexthe line's place inorder.linesfrom 1, andlinethe line. An error in the handler is printed in the server console. A business has one handler: setting it again replaces it,nilremoves it, and it is removed when its resource stops. Returnsfalsefor a department that isn't a business.Staff can still tick the lines off themselves, and the order only becomes ready when staff mark it ready.
Example:
lua---@param departmentId string ---@param handler? fun(order: BusinessOrder, index: integer, line: BusinessOrderLine) ---@return boolean set exports["zyke_laptop"]:SetBusinessLineHandler("burgershot", function(order, index, line) -- line: {entryId, label, qty, item?, amount, done} QueueCooking(order.id, index, line.entryId, line.qty) end)
#Set Business Order Line Done
Ticks a line of an order off, or back on with
done = false. The Orders tab and the order screens show it at once. Returnsfalsewhen the order doesn't exist, is no longer open, or has no such line. Yields.Example:
lua---@param orderId integer ---@param index integer @ The line, from 1 ---@param done? boolean @ true when left out ---@return boolean set exports["zyke_laptop"]:SetBusinessOrderLineDone(orderId, index)
#Events
Local server events, listened to with AddEventHandler. They can't block an action. plyId is 0 when an export did it. server/unlocked/webhooks.lua sends most of them to Discord.
| Event | Arguments |
|---|---|
zyke_laptop:mdt:CallCreated | plyId, departments, call |
zyke_laptop:mdt:CallClosed | plyId, departments, call |
zyke_laptop:mdt:StatusChanged | plyId, department, status, previous |
zyke_laptop:mdt:BulletinPosted | plyId, department, bulletin |
zyke_laptop:mdt:ReportSubmitted | plyId, department, report |
zyke_laptop:mdt:ReportReviewed | plyId, department, report, decision, note |
zyke_laptop:mdt:WarrantRequested, WarrantServed | plyId, department, warrant |
zyke_laptop:mdt:WarrantDecided | plyId, department, warrant, approved, note |
zyke_laptop:mdt:BoloPosted | plyId, department, bolo |
zyke_laptop:mdt:ChargesProcessed | plyId, department, sentence |
zyke_laptop:mdt:VehicleImpounded | plyId, department, vehicle |
zyke_laptop:mdt:LicenseRevoked | plyId, department, license |
zyke_laptop:mdt:CaseOpened, CaseClosed | plyId, department, case |
zyke_laptop:mdt:DeviceSeized, DeviceReleased | plyId, department, device |
zyke_laptop:mdt:DriveImaged, ImageUnlocked | plyId, department, image |
zyke_laptop:mdt:CareBilled | plyId, department, bill |
zyke_laptop:mdt:PreAlertSent | plyId, department, alert |
zyke_laptop:mdt:PatientAdmitted, PatientDischarged | plyId, department, admission |
zyke_laptop:mdt:PrescriptionWritten | plyId, department, prescription |
zyke_laptop:mdt:CertificateIssued | plyId, department, certificate |
zyke_laptop:mdt:OrderStatusChanged, OrderBilled, OrderPaid | plyId, department, order |
zyke_laptop:mdt:OrderApprovalAnswered | plyId, department, answer, plyId being the customer |
zyke_laptop:mdt:TowRequested, TowFinished | plyId, department, tow |
zyke_laptop:mdt:RoadworthinessIssued | plyId, department, certificate |
zyke_laptop:mdt:CatalogueChanged | plyId, department, change |
zyke_laptop:business:OrderPlaced, OrderReady, OrderCancelled | department, order |
zyke_laptop:business:OrderCollected | department, order, customerPlyId |
zyke_laptop:business:ReceiptIssued | staffPlyId, department, receipt |
zyke_laptop:business:StaffChanged | department, onDutyCount |
zyke_laptop:den:TicketCreated, TicketReturned | plyId, department, ticket |