Documentation

Exports & Events

Exports, local events, and Discord logs for laptop integrations.

General Information

A laptop that is out has a laptop id: the holder's server id while it is in their hands, and a negative id of its own while it is put down. A desktop computer has a negative id like a placed laptop. Laptop ids are handed out again on every start, so keep a laptop's serial and look the laptop up again on the server zyke_laptop:Ready event.

A laptop's serial belongs to the chassis and stays with it when parts are swapped. Its drive serial is the serial of the SSD inside, which keeps the OS, accounts, files, and system log, and goes wherever the SSD goes. A laptop's factory SSD shares the laptop's serial until it is swapped.

Exports marked Yields wait on the database or another resource. Call them from a thread, an event handler, or a callback.

Apps, sites, device types, Shroud contacts and rooms, Natter businesses, and monitored sites belong to the resource that registers them and are removed when it stops.

Values the client reports, such as IsConnected on the server, are fine for flavour but not for anything that pays out.

Types / Classes

All types / classes can be found in types/*.lua inside zyke_laptop, such as types/laptop.lua, types/hardware.lua, and types/devices.lua.

#Complete Export Index

ContextExports
ClientOpenScreen, CloseScreen, IsScreenOpen, IsConnected, GetActivity, TakeOut, PutAway, GetLaptopDevices, GetLaptopPorts, OpenPorts, ClosePorts, IsServicing, OpenApp, OpenUrl, Notify, AddBookmark, OpenMessenger, RegisterApp, UnregisterApp, RegisterSite, UnregisterSite, SendAppMessage, SendSiteMessage
Server: LaptopsIsConnected, GetLaptop, IsLaptopOwner, SetLaptopFinish, SetLaptopSkin, IsAtLaptop, GetLaptopSerial, GetLaptopDriveSerial, GetLaptopOs, RemoveLaptop
Server: Ports & DevicesGetLaptopDevices, GetSessionDevices, PlugDevice, UnplugDevice, GetLaptopPorts, RegisterDeviceType
Server: HardwareGetLaptopHardware, CreateLaptopMetadata, CreatePartMetadata, GetPartInfo, SetLaptopHardwareSlot, RepairLaptop, GetLaptopSpecs, WearLaptop
Server: StatusGetLaptopStatus, GetLaptopStatuses, GetPlacedLaptops
Server: OwnershipGetLaptopOwner, SetLaptopOwner, ReleaseLaptopOwner, GetCharacterLaptops, IsLaptopReportedStolen
Server: Drives & RecoveryGetLaptopLogs, IsLaptopDriveUnlocked, GetLaptopRecoveryReport
Server: Network & BrowsingGetLaptopNetwork, GetBrowsingTier, GetSiteVisitTraces, SetSiteMonitored
Server: ShroudGetChatHandle, GetChatTraces, RegisterChatRoom, RemoveChatRoom, RegisterChatContact, RemoveChatContact, SetChatListings, SendChatMessage, UpdateChatMessage, OpenChat
Server: NatterGetMessengerNumber, HasMessengerAccount, RegisterMessengerBusiness, SendMessengerMessage, GetMessengerMetadata
Server: CasinoIsCasinoEnabled, GetCasinoBalance, AdjustCasinoCredits

#Client Sided Exports

#Open Screen

Opens the OS for a resource with its own computer in the world, such as a police MDT. The player takes out a stand-in laptop that goes away with the screen, and the camera zooms onto it. The OS runs on a drive the server keeps for the character, not on a laptop item.

Returns false while the player already uses a laptop or has the screen open, and when CanUseLaptop("screen") or IsPlayerIncapacitated refuses. The player is notified then.

Example:

lua
---@return boolean opened
local opened = exports["zyke_laptop"]:OpenScreen()

#Close Screen

Closes the OS screen, whichever way it was opened. Does nothing while it is closed.

Example:

lua
exports["zyke_laptop"]:CloseScreen()

#Is Screen Open

Returns whether the OS is on the player's screen.

Example:

lua
---@return boolean open
local open = exports["zyke_laptop"]:IsScreenOpen()

#Is Connected

Returns whether the player's OS is connected to the Onion network.

Example:

lua
---@return boolean connected
local connected = exports["zyke_laptop"]:IsConnected()

#Get Activity

Returns what the player is doing with a laptop, or nil. holding is a laptop in the hands, using a placed laptop, screen a screen opened with OpenScreen, ports the port view, servicing the service view, and placing picking a spot to put one down.

Example:

lua
---@return "holding" | "using" | "screen" | "ports" | "servicing" | "placing" | nil activity
local activity = exports["zyke_laptop"]:GetActivity()

#Take Out

Takes the laptop out as if the player used the item. Does nothing while the player is busy with a laptop. CanUseLaptop("takeOut") is asked first.

Example:

lua
exports["zyke_laptop"]:TakeOut()

#Put Away

Puts a held laptop away, closing its screen. Does nothing unless the player holds a laptop.

Example:

lua
exports["zyke_laptop"]:PutAway()

#Get Laptop Devices

Returns what this client sees in the ports of a laptop, by port id, or nil for a laptop it does not see. Only the device type and item name are synced to clients; use the server export for metadata.

Example:

lua
---@param ownerId integer @ Laptop id
---@return table<string, {type: string, item: string}>? devices
local devices = exports["zyke_laptop"]:GetLaptopDevices(ownerId)

#Get Laptop Ports

Returns every port a laptop has, in the port view's order. A desktop computer only has hdmi, usba, and audio, all on its rear side.

Example:

lua
---@return LaptopPort[] ports @ {id, kind, side}
local ports = exports["zyke_laptop"]:GetLaptopPorts()

The ports of a laptop:

PortKindSide
usbc1, usbc2usbcleft
hdmihdmileft
usbausbaright
audioaudioright

#Open Ports

Opens the port view of a placed laptop within reach. The player steps round to its front first. Does nothing while the player is busy with a laptop. CanUseLaptop("ports") is asked first.

Example:

lua
---@param ownerId integer @ The placed laptop's id
exports["zyke_laptop"]:OpenPorts(ownerId)

#Close Ports

Closes the port view.

Example:

lua
exports["zyke_laptop"]:ClosePorts()

#Is Servicing

Returns whether the player has the service view open. See Hardware & Servicing.

Example:

lua
---@return boolean servicing
local servicing = exports["zyke_laptop"]:IsServicing()

#Open App

Opens an app, passing params to its window. An app that does not run on the player's OS is not opened.

The OS runs while a laptop is at hand and for a few minutes after. Like a real laptop that is off, an OS that is not running misses the call: it returns false and nothing is kept for the next boot.

Example:

lua
---@param appId string
---@param params? table
---@return boolean delivered
local delivered = exports["zyke_laptop"]:OpenApp("my_app", {tab = "orders"})

#Open Url

Opens an address in the OS's own browser. Returns false while no OS runs.

Example:

lua
---@param url string
---@return boolean delivered
local delivered = exports["zyke_laptop"]:OpenUrl("lscustoms.com")

#Notify

Shows a desktop notification. Clicking it opens url in the OS's browser, or else the app appId with params passed to its window. Returns false without a title, and while no OS runs; the notification is not kept.

Example:

lua
---@param notification LaptopNotification
---@return boolean delivered
local delivered = exports["zyke_laptop"]:Notify({
    title = "Order ready", -- Required
    text = "Your parts are at the counter.", -- Optional
    icon = "package", -- Optional, a Lucide icon name or an image URL
    appId = "my_app", -- Optional, opened on click
    url = "lscustoms.com", -- Optional, opened on click before appId
    params = {tab = "orders"}, -- Optional, passed to appId's window
    duration = 6000, -- Optional
})

#Add Bookmark

Adds a bookmark to the bookmarks every OS's browser shares, once per id, for example when a contact in the world hands the player an address. While no OS runs it waits on the client, through relogs, until a browser saves it. force adds it again after the player deleted it.

Returns whether the bookmark was handed over or kept, not whether the player lacked it. Returns false without an id and url.

Example:

lua
---@param bookmark LaptopBookmark
---@return boolean kept
exports["zyke_laptop"]:AddBookmark({
    id = "market", -- Unique within your resource
    url = "market5xq.onion",
    title = "The Market", -- Optional
    force = false, -- Optional
})

#Open Messenger

Opens Natter, on a chat when chatId is given. Returns false while no OS runs. See Messaging.

Example:

lua
---@param chatId? string
---@return boolean delivered
local delivered = exports["zyke_laptop"]:OpenMessenger()

#Register App

Adds an app to the OS for the calling resource. Registering an id again replaces the app. Returns false without an id, label, and ui, for the id of a built-in app, and for an os list with no known OS. See Apps & Sites for every field.

Example:

lua
---@param app LaptopAppRegistration
---@return boolean registered
local registered = exports["zyke_laptop"]:RegisterApp({
    id = "my_app",
    label = "Dispatch",
    ui = "web/app.html", -- A path inside your resource, or a full URL
})

#Unregister App

Removes an app.

Example:

lua
---@param appId string
exports["zyke_laptop"]:UnregisterApp("my_app")

#Register Site

Adds a site to the browser for the calling resource. Returns false without an id, url, title, and ui, and for an address another site already has. See Apps & Sites for every field.

Example:

lua
---@param site LaptopSiteRegistration
---@return boolean registered
local registered = exports["zyke_laptop"]:RegisterSite({
    id = "my_site",
    url = "market5xq.onion",
    title = "The Market",
    ui = "web/site.html",
})

#Unregister Site

Removes a site.

Example:

lua
---@param siteId string
exports["zyke_laptop"]:UnregisterSite("my_site")

#Send App Message

Sends data to the app's open page as a message event. Returns false while no OS runs.

Example:

lua
---@param appId string
---@param data any
---@return boolean delivered
local delivered = exports["zyke_laptop"]:SendAppMessage("my_app", {orders = 3})

#Send Site Message

Sends data to the site's open page as a message event. Returns false while no OS runs.

Example:

lua
---@param siteId string
---@param data any
---@return boolean delivered
local delivered = exports["zyke_laptop"]:SendSiteMessage("my_site", {stock = 12})

#Server Sided Exports

Server exports are grouped below by area. Shroud's exports are only registered while chat.enabled is on, and Natter's while messenger.enabled is on. The casino exports are always registered and answer as disabled while the casino is off.

Exports such as SetLaptopOwner, PlugDevice, SetLaptopHardwareSlot, RepairLaptop, WearLaptop, and AdjustCasinoCredits are trusted server operations. Do not expose them directly through an unrestricted network event.

#Laptops

#Is Connected

Returns whether the player's OS reports a connection to the Onion network. It comes from the client, so use it for flavour only.

Example:

lua
---@param plyId integer
---@return boolean connected
local connected = exports["zyke_laptop"]:IsConnected(plyId)

#Get Laptop

Returns a laptop that is out by its laptop id, or nil. Treat it as read-only.

skin is the backplate id from Config.Settings.skins, nil for the stock lid. finish is the id from Config.Settings.finishes, nil for the stock graphite. usb is the boot stick a session runs from while the player carries it. ports holds the plugged devices. dead is true while the laptop can't power on. kind is computer for a desktop computer.

Example:

lua
---@param ownerId integer @ Laptop id
---@return LaptopState? laptop @ {mode, kind?, lidOpen, coords?, bucket, skin?, finish?, usb?, ports?, service?, dead?}
local laptop = exports["zyke_laptop"]:GetLaptop(ownerId)

#Is Laptop Owner

Returns whether the player's character put that placed laptop down, or holds that laptop. This is who put it there, not the registered owner; use GetLaptopOwner for that.

Example:

lua
---@param plyId integer
---@param ownerId integer @ Laptop id
---@return boolean isOwner
local isOwner = exports["zyke_laptop"]:IsLaptopOwner(plyId, ownerId)

#Set Laptop Finish

Sets the finish of the laptop item in the player's inventory slot, nil for the stock graphite. When that laptop is out, everyone who sees it gets the new colour at once.

Example:

lua
---@param plyId integer
---@param slot integer @ Inventory slot of the laptop item
---@param finishId? string @ Id from Config.Settings.finishes
---@return boolean changed
---@return string? err @ "invalidFinish", "noLaptopItem" or "notSaved"
local changed, err = exports["zyke_laptop"]:SetLaptopFinish(plyId, slot, "midnight")

#Set Laptop Skin

Puts a backplate skin on the laptop item in the player's inventory slot, nil for the stock lid. The skin it had is replaced. When that laptop is out, everyone who sees it gets the new backplate at once.

Example:

lua
---@param plyId integer
---@param slot integer @ Inventory slot of the laptop item
---@param skinId? string @ Id listed under Config.Settings.skins
---@return boolean changed
---@return string? err @ "invalidSkin", "noLaptopItem" or "notSaved"
local changed, err = exports["zyke_laptop"]:SetLaptopSkin(plyId, slot, "carbon")

#Is At Laptop

Returns whether the player holds a laptop or stands at one put down, theirs or anyone's. Returns false while the player is dead, downed, or cuffed. Use it to gate server callbacks behind a laptop page.

Example:

lua
---@param plyId integer
---@return boolean atLaptop
local atLaptop = exports["zyke_laptop"]:IsAtLaptop(plyId)

#Get Laptop Serial

Returns the serial of the laptop the player's OS runs on right now, their own or one another player put down, or nil while their OS is off. Use it to key data to the laptop itself.

Example:

lua
---@param plyId integer
---@return string? serial
local serial = exports["zyke_laptop"]:GetLaptopSerial(plyId)

#Get Laptop Drive Serial

Returns the serial of the SSD in the laptop the player's OS runs on right now, or nil while their OS is off or the laptop has no SSD. Use it to key data that should travel with the drive.

Example:

lua
---@param plyId integer
---@return string? drive
local drive = exports["zyke_laptop"]:GetLaptopDriveSerial(plyId)

#Get Laptop OS

Returns the OS the player runs right now, or nil while it is off. veil boots from a USB stick and keeps nothing on the drive.

Example:

lua
---@param plyId integer
---@return "facade" | "lumen" | "solace" | "veil" | nil osId
local osId = exports["zyke_laptop"]:GetLaptopOs(plyId)

#Remove Laptop

Takes the laptop out of the player's hands and closes their screen. A laptop they put down stays where it is.

Example:

lua
---@param plyId integer
exports["zyke_laptop"]:RemoveLaptop(plyId)

#Ports & Devices

#Get Laptop Devices

Returns what is in the ports of a laptop that is out, by port id, or nil when it is not out. plugId changes every time a device is plugged in. type is nil for an item no registered device type has any more.

The built-in device types are boot_stick, data_stick, power_bank, and hdmi_cable.

Example:

lua
---@param ownerId integer @ Laptop id
---@return table<string, LaptopDeviceInfo>? devices @ {port, kind, side, type?, item, metadata, plugId}
local devices = exports["zyke_laptop"]:GetLaptopDevices(ownerId)

#Get Session Devices

Returns the same for the laptop the player's OS runs on right now, their own or another player's. nil while their OS is off or runs on a screen opened without a laptop prop. Use it to let a hacking app work only with an antenna plugged in, for example.

Example:

lua
---@param plyId integer
---@return table<string, LaptopDeviceInfo>? devices
local devices = exports["zyke_laptop"]:GetSessionDevices(plyId)

#Plug Device

Plugs the item in the player's inventory slot into a port, with the port view's reach checks and the CanPlugLaptopDevice hook. The exact item, with its metadata, moves into the laptop. Yields for a data stick, or another storage device, plugged in for the first time.

Example:

lua
---@param plyId integer
---@param ownerId integer @ Laptop id
---@param port string @ Such as "usba"
---@param slot integer @ Inventory slot of the device item
---@return boolean plugged
---@return string? reason @ Locale key, such as "ports:doesNotFit" or "laptopTooFar"
local plugged, reason = exports["zyke_laptop"]:PlugDevice(plyId, ownerId, "usba", slot)

#Unplug Device

Pulls the device out of a port into the player's inventory, with its metadata, after the reach checks and the CanUnplugLaptopDevice hook.

Example:

lua
---@param plyId integer
---@param ownerId integer @ Laptop id
---@param port string
---@return boolean unplugged
---@return string? reason @ Locale key, such as "ports:portEmpty" or "ports:noRoom"
local unplugged, reason = exports["zyke_laptop"]:UnplugDevice(plyId, ownerId, "usba")

#Get Laptop Ports

Same as the client export. Returns every port, {id, kind, side}, in the port view's order.

Example:

lua
---@return LaptopPort[] ports
local ports = exports["zyke_laptop"]:GetLaptopPorts()

#Register Device Type

Adds a kind of device that goes into the laptop's ports, such as an antenna. Registering an id again replaces it. An item can be only one device type, so an item another type already has is refused.

The type belongs to the calling resource and is removed when it stops. Devices already in a port stay there and can still be pulled out. Register it again when the laptop starts, since the laptop forgets other resources' device types when it restarts.

attach sets where the prop sits in each port kind, in the port's own frame: X points out of the side wall and Z up, in metres and degrees. Ports on the left side turn the prop half a turn and a computer's rear ports a quarter turn, so one offset fits every port. storage makes the device a drive the OS mounts, like the data stick, with its files kept on the server by the stick's serial.

Example:

lua
---@param def LaptopDeviceRegistration
---@return boolean registered
---@return string? err @ Why it was refused, in English
local function registerDevices()
    local registered, err = exports["zyke_laptop"]:RegisterDeviceType({
        id = "wifi_antenna",
        items = {"big_usb_antenna", "small_usb_antenna"},
        ports = {"usba", "usbc"}, -- Port kinds it fits: "usba", "usbc", "hdmi" or "audio"
        model = "my_usb_antenna", -- One prop for every item, or models = {big_usb_antenna = "...", small_usb_antenna = "..."}
        attach = {
            usba = {offset = vec3(0.0006, 0.0, 0.0)},
            usbc = {offset = vec3(0.0005, 0.0, 0.0), rotation = vec3(0.0, 0.0, 0.0)},
        },
        -- Optional: a drive the OS mounts. maxBytes is what its files may take, capacity the size players see
        -- storage = {maxBytes = 131072, capacity = 34359738368},
    })

    if (not registered) then print(("The antenna was not registered: %s"):format(err)) end
end

AddEventHandler("onResourceStart", function(resource)
    if (resource == "zyke_laptop" or resource == GetCurrentResourceName()) then registerDevices() end
end)

---@param device LaptopDeviceInfo
AddEventHandler("zyke_laptop:DevicePlugged", function(device)
    if (device.type ~= "wifi_antenna") then return end

    print(("%s plugged %s into port %s of laptop %s"):format(device.plyId, device.item, device.port, device.serial))
end)

#Hardware

#Get Laptop Hardware

Returns a copy of a laptop's hardware, or nil. target is a player with a laptop out, {plyId, slot} for a laptop item in an inventory slot, or {serial} for a laptop that is out, or any laptop while Config.Settings.item is false. A laptop item that was not taken out since hardware was added to it returns nil until its next take-out.

Example:

lua
---@param target integer | LaptopHardwareTarget
---@return LaptopHardware? hardware @ Slots board, ram0, ram1, ssd, wifi, battery, each {name, metadata}
local hardware = exports["zyke_laptop"]:GetLaptopHardware({plyId = plyId, slot = 4})

#Create Laptop Metadata

Returns metadata for a new laptop item, built as a prebuilt from shared/unlocked/hardware.lua, hardware.default when left out, with every serial new. The second argument adds metadata such as a finish or a skin. An owner in it, a character identifier, becomes the laptop's registered owner instead of staying on the item. Yields.

Example:

lua
---@param prebuiltId? string
---@param metadata? table
---@return table | false metadata
---@return string? err @ "unknownPrebuilt"
local metadata = exports["zyke_laptop"]:CreateLaptopMetadata("performance", {finish = "midnight"})

exports["ox_inventory"]:AddItem(plyId, "laptop", 1, metadata)

#Create Part Metadata

Returns metadata for a new part item, with the label and description ox_inventory shows in place of the item's own, such as "Nordwell NV4 1 TB SSD". used = true gives the part a random condition and makes some memory sticks faulty, and condition sets it from 0 to 1. Yields for an SSD.

Example:

lua
---@param itemName string
---@param model string @ Model id from the catalogue
---@param opts? {used?: boolean, condition?: number}
---@return table | false metadata
---@return string? err @ "unknownItem" or "unknownModel"
local ssd = exports["zyke_laptop"]:CreatePartMetadata("laptop_ssd", "nv4_1tb")
local stick = exports["zyke_laptop"]:CreatePartMetadata("laptop_ram", "d5_16", {used = true})
local battery = exports["zyke_laptop"]:CreatePartMetadata("laptop_battery", "zb61", {condition = 0.8})

#Get Part Info

Returns what a part item is and what shape it is in, for a shop listing or a tooltip of your own, or nil for an item that is not a part. fits lists the board generations the part fits. A memory fault only shows once the stick was tested.

Example:

lua
---@param itemName string
---@param metadata table
---@return LaptopPartInfo? info @ {kind, model, label, spec, condition?, faulty, fits, description}
local info = exports["zyke_laptop"]:GetPartInfo(item.name, item.metadata)

#Set Laptop Hardware Slot

Fits a part into a slot of the laptop item in the player's inventory slot, or takes the part out when part is nil, with the service view's checks and the CanInstallPart and CanRemovePart hooks. The installed part is not taken from any inventory, and a removed part is returned to your script without being given to anyone. A laptop that is out is refused while someone services it or an OS runs on it.

The slots are board, cooler, ram0, ram1, ssd, wifi, and battery.

Example:

lua
---@param plyId integer
---@param laptopSlot integer @ Inventory slot of the laptop item
---@param slotId string
---@param part? {name: string, metadata: table}
---@return boolean done
---@return LaptopStoredPart | string | nil result @ The removed part, or the locale key of the reason
local done, err = exports["zyke_laptop"]:SetLaptopHardwareSlot(plyId, laptopSlot, "ssd", {name = "laptop_ssd", metadata = ssd})
local taken, removed = exports["zyke_laptop"]:SetLaptopHardwareSlot(plyId, laptopSlot, "ram1")

#Repair Laptop

A repair shop's shortcut for the laptop item in the player's inventory slot, without the service view or its supplies. clean blows the fan clean, repaste puts fresh paste on, and battery brings the battery back to full health with no cycles.

Example:

lua
---@param plyId integer
---@param laptopSlot integer @ Inventory slot of the laptop item
---@param kinds ("clean" | "repaste" | "battery")[]
---@return boolean repaired
---@return string? err @ Locale key, such as "hardware:service:slotEmpty"
local repaired, err = exports["zyke_laptop"]:RepairLaptop(plyId, laptopSlot, {"clean", "repaste"})

#Get Laptop Specs

Returns what a laptop's parts are and how they run, worked out the way the OS gets them: the processor, its built-in graphics, the working memory, the heat from dust and dried paste, and the speed factor it all comes to. Use it for scripts that build on a laptop's parts, such as a mining script that works out what each laptop makes.

target is the serial of a laptop that is out, {plyId, slot} for a laptop item, or {metadata} or {hardware} for a laptop item kept anywhere else, such as a stash. Absent parts are nil.

Example:

lua
---@param target string | LaptopItemTarget
---@return LaptopSpecs | false specs @ {board?, cooler?, memory, ssd?, wifi?, battery?, heat, speed, canBoot}
---@return string? err @ "invalid", "notOut", "noLaptopItem" or "noHardware"
local specs, err = exports["zyke_laptop"]:GetLaptopSpecs(serial)

if (specs and specs.canBoot) then
    print(specs.board.cpu, specs.memory.gb, specs.speed) -- speed is 0.70 to 1.80, lower is faster
end

#Wear Laptop

Wears a laptop on top of the wear it gathers on its own, for a load such as mining. Every amount is optional and 0 or more. hours wears the laptop as if it ran that long. dust, ssd, paste, and battery change those values directly; paste and battery health stop at their floors in the config.

A laptop that is out is written at once and every OS on it gets its parts as they are now. A laptop item in a slot is written in that slot. A {metadata} or {hardware} target is never written back; the worn copy is returned for your script to keep. A laptop that is open for service is refused.

Example:

lua
---@param target string | LaptopItemTarget
---@param wear LaptopWear @ {hours?, dust?, paste?, ssd?, battery?}
---@return boolean worn
---@return table | string | nil result @ The worn metadata or hardware for a passed copy, otherwise the reason it failed
local worn, err = exports["zyke_laptop"]:WearLaptop(serial, {hours = 1.0})

-- A laptop item in a rack's stash
local ok, metadata = exports["zyke_laptop"]:WearLaptop({metadata = item.metadata}, {hours = 1.0})

#Status

#Get Laptop Status

Returns the status of a laptop that is out, held or put down, by its serial, or nil while it is not out. powered is true while an OS runs on it or it was left on, and players lists the players whose OS runs on it. power holds the battery and whether it runs on mains or a power bank.

Example:

lua
---@param serial string
---@return LaptopStatus? status @ {laptopId, mode, kind, coords?, bucket, owner?, area?, lidOpen, powered, standby, players, dead, service, power}
local status = exports["zyke_laptop"]:GetLaptopStatus(serial)

#Get Laptop Statuses

Returns the status of many laptops in one call, by serial. Laptops that are not out are left out.

Example:

lua
---@param serials string[]
---@return table<string, LaptopStatus> statuses
local statuses = exports["zyke_laptop"]:GetLaptopStatuses({"ZL-7Q2K-9F4M", "ZL-3B8P-1D6X"})

#Get Placed Laptops

Returns the laptops and desktop computers put down right now. Every filter field is optional and matches anything when left out.

Example:

lua
---@param filter? {owner?: string, area?: string, kind?: "laptop" | "computer"}
---@return LaptopPlacedEntry[] laptops @ {serial, laptopId, kind, owner, area?, coords, bucket}
local laptops = exports["zyke_laptop"]:GetPlacedLaptops({area = "mining:serverroom"})

#Ownership

The ownership exports wait while the owners are still loading on start. See Ownership & Recovery.

#Get Laptop Owner

Returns the character identifier of the laptop's registered owner, or nil.

Example:

lua
---@param serial string @ The laptop's serial
---@return string? identifier
local identifier = exports["zyke_laptop"]:GetLaptopOwner(serial)

#Set Laptop Owner

Makes the character the laptop's owner, and clears a stolen report when the owner changes. zyke_laptop:LaptopOwnerChanged names the calling resource as what set it.

Example:

lua
---@param serial string @ The laptop's serial
---@param identifier string @ Character identifier
---@return boolean set
---@return string? err @ "invalid"
local set, err = exports["zyke_laptop"]:SetLaptopOwner(serial, identifier)

#Release Laptop Owner

Leaves the laptop without an owner, so whoever takes it out next claims it. Returns false when it had no owner.

Example:

lua
---@param serial string
---@param origin? string @ Passed on to LaptopOwnerChanged, "release" when left out
---@return boolean released
local released = exports["zyke_laptop"]:ReleaseLaptopOwner(serial)

#Get Character Laptops

Returns the laptops a character owns, newest first. since is when they became the owner, in seconds since the epoch.

Example:

lua
---@param identifier string
---@return {serial: string, stolen: boolean, since: integer}[] laptops
local laptops = exports["zyke_laptop"]:GetCharacterLaptops(identifier)

#Is Laptop Reported Stolen

Returns whether the owner reported the laptop stolen. Nothing in the laptop acts on the flag; it is there for police and pawn shop scripts.

Example:

lua
---@param serial string
---@return boolean stolen
local stolen = exports["zyke_laptop"]:IsLaptopReportedStolen(serial)

#Drives & Recovery

These exports take a drive serial. A laptop's serial reads the SSD in that laptop while it is out, or any time while Config.Settings.item is false.

#Get Laptop Logs

Returns a drive's system log, oldest first, or an empty list. kind is boot, signIn, signInFailed, accountCreated, passwordChanged, passwordReset, install, network, cloudLinked, or cloudSignedOut. Yields.

Example:

lua
---@param serial string
---@return LaptopLogEntry[] logs @ {at, kind, device?, username?, os?, ssid?, reason?}
local logs = exports["zyke_laptop"]:GetLaptopLogs(serial)

#Is Laptop Drive Unlocked

Returns whether Crowbar, the recovery toolkit, got past a drive's password, until an OS is installed on it again. Yields.

Example:

lua
---@param serial string
---@return boolean unlocked
local unlocked = exports["zyke_laptop"]:IsLaptopDriveUnlocked(serial)

#Get Laptop Recovery Report

Returns what Crowbar reads off a drive, or nil when no drive has this serial. files and history are left out while the drive is locked, which a Lumen drive is until Crowbar unlocks it. logs and history are newest first. shroudKey is a Shroud sign-in key found in the visible files. Yields.

Example:

lua
---@param serial string
---@return LaptopRecoveryReport? report @ {serial, os?, hostname?, account?, locked, files?, history?, logs, shroudKey?, progress?, canSetPassword}
local report = exports["zyke_laptop"]:GetLaptopRecoveryReport(serial)

#Network & Browsing

See Wi-Fi & Browsing.

#Get Laptop Network

Returns the network the laptop on the player's screen is online through, or nil when they have no laptop on screen or are offline. kind is phone or hotspot, and id is the hotspot's id or phone. coords is the hotspot's position, or the player's for their phone. The range is checked again on every call.

Example:

lua
---@param plyId integer
---@return {kind: "phone" | "hotspot", id: string, ssid: string, coords: vector3}? network
local network = exports["zyke_laptop"]:GetLaptopNetwork(plyId)

#Get Browsing Tier

Returns how the player's browser reaches sites right now, or nil while their OS is off. Veil is always onion. The Onion connection on other OSes comes from the client and only counts while the laptop is online.

Example:

lua
---@param plyId integer
---@return "direct" | "vpn" | "onion" | nil tier
local tier = exports["zyke_laptop"]:GetBrowsingTier(plyId)

#Get Site Visit Traces

Returns recorded visits to monitored sites, newest first. Every filter field is optional and all of them have to match. url compares only the host. since and before are seconds since the epoch. limit defaults to 100, at most 500. Yields.

Example:

lua
---@param filter? {url?: string, serial?: string, character?: string, tier?: "direct" | "vpn" | "onion", since?: integer, before?: integer, limit?: integer}
---@return BrowsingTraceRecord[] traces @ {host, url, tier?, character?, serial?, network?, coords?, createdAt}
local traces = exports["zyke_laptop"]:GetSiteVisitTraces({url = "market5xq.onion", since = os.time() - 86400})

#Set Site Monitored

Records visits to the site while browsing.record is "monitored", until the calling resource stops. false stops it. Returns false for an address that can't be read.

Example:

lua
---@param url string
---@param monitored? boolean @ true when left out
---@return boolean changed
local changed = exports["zyke_laptop"]:SetSiteMonitored("market5xq.onion")

#Shroud

Shroud is the onion chat app. The contact exports are covered in full in Shroud Contacts.

#Get Chat Handle

Returns the handle the player is signed in to Shroud with, or nil.

Example:

lua
---@param plyId integer
---@return string? handle
local handle = exports["zyke_laptop"]:GetChatHandle(plyId)

#Get Chat Traces

Returns what senders left behind for a handle, oldest first, from since on. Which fields a trace has depends on the OS the sender ran: Facade and Solace record the character, serial, network, and position, Lumen the serial and network, and Veil nothing. Yields.

Example:

lua
---@param handle string
---@param since? integer @ Seconds since the epoch
---@return ChatTraceRecord[] traces @ {kind, handle, tier, conversationId?, messageId?, character?, serial?, network?, coords?, createdAt}
local traces = exports["zyke_laptop"]:GetChatTraces("ghost", os.time() - 86400)

for _, trace in ipairs(traces) do
    if (trace.network) then print(("ghost was online through %s"):format(trace.network.ssid)) end
end

#Register Chat Room

Adds a room, for example for a gang or a job. listed = false keeps it out of the directory, so only players who know its id can join. Returns false without a valid id and name.

Example:

lua
---@param room {id: string, name: string, description?: string, listed?: boolean}
---@return boolean registered
local registered = exports["zyke_laptop"]:RegisterChatRoom({id = "grove", name = "Grove Street", listed = false})

#Remove Chat Room

Removes a room. Conversations in it stay readable, but nobody can write there until it is back.

Example:

lua
---@param roomId string
---@return boolean removed
local removed = exports["zyke_laptop"]:RemoveChatRoom("grove")

#Register Chat Contact

Adds a contact owned by your resource, such as a dealer or a fixer, with handlers for messages, card buttons, and purchases. Its handle is reserved. See Shroud Contacts.

Example:

lua
---@param contact ChatContactRegistration
---@return boolean registered
local registered = exports["zyke_laptop"]:RegisterChatContact({id = "greenthumb", handle = "greenthumb", name = "Greenthumb"})

#Remove Chat Contact

Removes a contact.

Example:

lua
---@param contactId string
---@return boolean removed
local removed = exports["zyke_laptop"]:RemoveChatContact("greenthumb")

#Set Chat Listings

Replaces a contact's listings and updates the listing messages players have open.

Example:

lua
---@param contactId string
---@param listings ChatListing[]
---@return boolean updated
local updated = exports["zyke_laptop"]:SetChatListings("greenthumb", listings)

#Send Chat Message

Sends a message from a contact to a player's server id or a handle, also while they are offline or signed out. Returns the message id, or nil when the contact, target, or message is invalid or the player blocked the contact. Yields.

Example:

lua
---@param contactId string
---@param target integer | string @ Server id or handle
---@param message string | ChatMessageInput
---@return string? messageId
local messageId = exports["zyke_laptop"]:SendChatMessage("greenthumb", plyId, "Got a run for you.")

#Update Chat Message

Changes a message one of the calling resource's contacts sent, for example to disable a card's buttons. text, listings, location, and frame are replaced, card fields are merged into the card, and false removes a field. Yields.

Example:

lua
---@param messageId string
---@param patch table
---@return boolean updated
local updated = exports["zyke_laptop"]:UpdateChatMessage(messageId, {card = {actions = {{id = "accept_job", label = "Accepted", disabled = true}}}})

#Open Chat

Opens the contact's conversation in the player's Shroud if their screen is on, otherwise tells them a message is waiting. Yields.

Example:

lua
---@param plyId integer
---@param contactId string
---@return boolean sent
local sent = exports["zyke_laptop"]:OpenChat(plyId, "greenthumb")

#Natter

Natter is the everyday messaging app, keyed by the character's phone number. See Messaging.

#Get Messenger Number

Returns the key Natter stores the character's number by and the number as their phone shows it. reason is noPhone when a phone resource runs but they carry no phone or SIM. Yields.

Example:

lua
---@param plyId integer
---@return string? number
---@return string? phone
---@return string? reason
local number, phone, reason = exports["zyke_laptop"]:GetMessengerNumber(plyId)

#Has Messenger Account

Returns whether the number has a Natter account. Yields.

Example:

lua
---@param number string
---@return boolean hasAccount
local hasAccount = exports["zyke_laptop"]:HasMessengerAccount(number)

#Register Messenger Business

Adds a business players can message. id is up to 20 letters, digits, _, or -. Returns its sender, biz:<id>, or nil for an invalid id or name. Replies reach onMessage.

Example:

lua
---@param id string
---@param business {name: string, about?: string, photo?: string, verified?: boolean, onMessage?: fun(plyId: integer, number: string, text?: string, chatId: string)}
---@return string? sender
exports["zyke_laptop"]:RegisterMessengerBusiness("lsc", {
    name = "Los Santos Customs",
    about = "Open all day",
    photo = "web/lsc.webp", -- An https URL or a path inside your resource
    verified = true,
    onMessage = function(plyId, number, text, chatId)
        exports["zyke_laptop"]:SendMessengerMessage("lsc", number, "Thanks, a mechanic will text you back shortly.")
    end,
})

#Send Messenger Message

Sends a message from a business id or the built-in system account (Natter itself). message is a string, or a table with text and at most one of image (an https URL), location, or contact. Returns the message id, or nil when the number has no account or blocked the sender. Yields.

Example:

lua
---@param from string @ "system" or a business id
---@param number string
---@param message string | {text?: string, image?: string, location?: vector3 | {x: number, y: number, z?: number, label?: string}, contact?: {number: string, name?: string}}
---@return string? messageId
local messageId = exports["zyke_laptop"]:SendMessengerMessage("lsc", number, {
    text = "Your car is ready.",
    location = {x = -337.4, y = -136.9, z = 39.0, label = "LS Customs Burton"},
})

#Get Messenger Metadata

Returns who messaged whom and when for a number, newest first, never the content. nil when CanReadMessengerMetadata refuses. since and before are milliseconds since the epoch, and limit defaults to 100, at most 1000. drive is the sending laptop's drive serial, nil for Veil and resources. Yields.

Example:

lua
---@param plyId integer @ The player asking, such as an officer
---@param number string
---@param filter? {since?: integer, before?: integer, limit?: integer}
---@return MessengerMetadataRow[]? rows @ {id, chatId, chatKind, from, to?, kind, drive?, sentAt}
local rows = exports["zyke_laptop"]:GetMessengerMetadata(plyId, number, {limit = 50})

#Casino

Amounts are credits in cents. See Casino.

#Is Casino Enabled

Returns whether the casino is on.

Example:

lua
---@return boolean enabled
local enabled = exports["zyke_laptop"]:IsCasinoEnabled()

#Get Casino Balance

Returns the credits in a wallet, by server id or character identifier, or nil without a wallet or while the casino is off. Yields.

Example:

lua
---@param player integer | string @ Server id or character identifier
---@return integer? balance @ Cents
local balance = exports["zyke_laptop"]:GetCasinoBalance(plyId)

#Adjust Casino Credits

Gives credits (positive) or takes them (negative) outside the games, for example as a reward from another resource. The change is written to the ledger with the reason, the calling resource's name when left out. Yields.

Example:

lua
---@param player integer | string @ Server id or character identifier
---@param amount integer @ Cents, negative to take
---@param reason? string
---@return boolean adjusted
---@return integer | string balanceOrError @ The balance after it, or "disabled", "invalid", "noAccount" or "insufficient"
local adjusted, result = exports["zyke_laptop"]:AdjustCasinoCredits(plyId, 50000, "Event prize")

#Client Local Events

These events are local client notifications. Listen with AddEventHandler on the client.

#Ready

Fires when the laptop starts on the client. Register your apps and sites again on it, as well as when your own resource starts.

Example:

lua
AddEventHandler("zyke_laptop:Ready", function()
    RegisterMyApps()
end)

#Screen Opened

Fires when the OS comes on screen.

Example:

lua
---@param mode "handheld" | "placed" | "screen"
AddEventHandler("zyke_laptop:ScreenOpened", function(mode)
    print(mode)
end)

#Screen Closed

Fires when the OS leaves the screen.

Example:

lua
AddEventHandler("zyke_laptop:ScreenClosed", function()
    print("closed")
end)

#App Opened

Fires when the first window of an app opens.

Example:

lua
---@param appId string
AddEventHandler("zyke_laptop:AppOpened", function(appId)
    print(appId)
end)

#App Closed

Fires when the last window of an app closes.

Example:

lua
---@param appId string
AddEventHandler("zyke_laptop:AppClosed", function(appId)
    print(appId)
end)

#Connection Changed

Fires when the OS connects to or loses the Onion network.

Example:

lua
---@param connected boolean
AddEventHandler("zyke_laptop:ConnectionChanged", function(connected)
    print(connected)
end)

#Power Changed

Fires when the OS boots or powers off. serial is the laptop it ran on.

Example:

lua
---@param on boolean
---@param serial? string
AddEventHandler("zyke_laptop:PowerChanged", function(on, serial)
    print(on, serial)
end)

#Devices Changed

Fires when what is in a laptop's ports changes, as this client sees it. devices is what the client GetLaptopDevices export returns, nil once the client no longer sees that laptop.

Example:

lua
---@param ownerId integer @ Laptop id
---@param devices? table<string, {type: string, item: string}>
AddEventHandler("zyke_laptop:DevicesChanged", function(ownerId, devices)
    print(ownerId, json.encode(devices))
end)

#Service Started

Fires when the player opens the service view of a laptop.

Example:

lua
---@param ownerId integer @ Laptop id
AddEventHandler("zyke_laptop:ServiceStarted", function(ownerId)
    print(ownerId)
end)

#Service Ended

Fires when the service view closes.

Example:

lua
---@param ownerId integer @ Laptop id
AddEventHandler("zyke_laptop:ServiceEnded", function(ownerId)
    print(ownerId)
end)

#Activity Changed

Fires when the player's activity changes, with the value GetActivity returns, nil when they are done with the laptop.

Example:

lua
---@param activity? "holding" | "using" | "screen" | "ports" | "servicing" | "placing"
AddEventHandler("zyke_laptop:ActivityChanged", function(activity)
    print(activity)
end)

#Server Local Events

These events are local server integration notifications. They are not network event entry points and cannot block an action; use the Can-Check Hooks for that. Listen with AddEventHandler on the server.

#Ready

Fires once the placed laptops of the last run are restored on start. Laptop ids are new on every start, so resources that track placed laptops read them again here.

Example:

lua
AddEventHandler("zyke_laptop:Ready", function()
    local laptops = exports["zyke_laptop"]:GetPlacedLaptops()
end)

#Network Changed

Fires when the laptop on the player's screen joins another network, as GetLaptopNetwork returns it, or goes offline or off screen, network nil.

Example:

lua
---@param plyId integer
---@param network? {kind: "phone" | "hotspot", id: string, ssid: string, coords: vector3}
AddEventHandler("zyke_laptop:NetworkChanged", function(plyId, network)
    print(plyId, network and network.ssid)
end)

#Laptop Drive Unlocked

Fires when Crowbar gets past a drive's password. serial is the drive's. plyId is the player whose toolkit worked on it, nil when none did.

Example:

lua
---@param serial string
---@param plyId? integer
AddEventHandler("zyke_laptop:LaptopDriveUnlocked", function(serial, plyId)
    print(serial, plyId)
end)

#Chat Message Sent

Fires when a player sends a message in Shroud. trace holds what the sender's OS records, with tier and only the fields that OS records.

Example:

lua
---@param handle string
---@param conversationId string
---@param kind "direct" | "room"
---@param trace ChatTrace
AddEventHandler("zyke_laptop:ChatMessageSent", function(handle, conversationId, kind, trace)
    print(handle, kind, trace.character)
end)

#Messenger Message Sent

Fires when a message is sent in Natter, with the metadata row GetMessengerMetadata returns, never its content.

Example:

lua
---@param row MessengerMetadataRow @ {id, chatId, chatKind, from, to?, kind, drive?, sentAt}
AddEventHandler("zyke_laptop:MessengerMessageSent", function(row)
    print(row.from, row.to, row.kind)
end)

#Site Visited

Fires when a player opens a monitored site and their tier records something. url is the address without its scheme.

Example:

lua
---@param host string
---@param url string
---@param trace {tier: "direct" | "vpn" | "onion", character?: string, serial?: string, network?: table, coords?: vector3}
AddEventHandler("zyke_laptop:SiteVisited", function(host, url, trace)
    print(host, trace.tier, trace.character)
end)

#Device Plugged

Fires when a device goes into a port, through the port view or PlugDevice. ownerId is the laptop id, serial the laptop's, and plyId the player who plugged it in.

Example:

lua
---@param device LaptopDeviceInfo @ {ownerId, serial, plyId, port, kind, side, type, item, metadata, plugId}
AddEventHandler("zyke_laptop:DevicePlugged", function(device)
    print(device.serial, device.port, device.item)
end)

#Device Unplugged

Fires when a device comes out of a port, with the same fields. plyId is the player who pulled it out.

Example:

lua
---@param device LaptopDeviceInfo
AddEventHandler("zyke_laptop:DeviceUnplugged", function(device)
    print(device.serial, device.port, device.item)
end)

#Laptop Owner Changed

Fires when a laptop gets another owner, identifier nil once released. origin is shop, claim, admin, character, release, or the resource that called the export.

Example:

lua
---@param serial string
---@param identifier? string
---@param origin string
AddEventHandler("zyke_laptop:LaptopOwnerChanged", function(serial, identifier, origin)
    print(serial, identifier, origin)
end)

#Cloud Device Linked

Fires when a drive is linked to a character's Nimbus account.

Example:

lua
---@param identifier string
---@param drive string
AddEventHandler("zyke_laptop:CloudDeviceLinked", function(identifier, drive)
    print(identifier, drive)
end)

#Cloud Device Signed Out

Fires when a drive leaves a Nimbus account.

Example:

lua
---@param identifier string
---@param drive string
---@param reason "removed" | "reinstalled" | "mode" | "repair" | "recovery" | "user"
AddEventHandler("zyke_laptop:CloudDeviceSignedOut", function(identifier, drive, reason)
    print(identifier, drive, reason)
end)

#Part Installed

Fires when a part goes into a laptop, from the service view or SetLaptopHardwareSlot.

Example:

lua
---@param plyId integer
---@param serial string @ The laptop's
---@param slotId string
---@param item {name: string, metadata: table}
AddEventHandler("zyke_laptop:PartInstalled", function(plyId, serial, slotId, item)
    print(serial, slotId, item.name)
end)

#Part Removed

Fires when a part comes out of a laptop, from the service view or SetLaptopHardwareSlot.

Example:

lua
---@param plyId integer
---@param serial string
---@param slotId string
---@param item {name: string, metadata: table}
AddEventHandler("zyke_laptop:PartRemoved", function(plyId, serial, slotId, item)
    print(serial, slotId, item.name)
end)

#Laptop Serviced

Fires when a laptop's fan is cleaned (clean), its processor re-pasted (repaste), or its battery restored (battery, from RepairLaptop only).

Example:

lua
---@param plyId integer
---@param serial string
---@param kind "clean" | "repaste" | "battery"
AddEventHandler("zyke_laptop:LaptopServiced", function(plyId, serial, kind)
    print(serial, kind)
end)

#Part Worn Out

Fires when wear turns an SSD read-only (ssd) or a memory stick faulty (ram0, ram1), from normal use or WearLaptop. A copy passed to WearLaptop as {metadata} or {hardware} does not fire it.

Example:

lua
---@param serial string
---@param slotId "ssd" | "ram0" | "ram1"
AddEventHandler("zyke_laptop:PartWornOut", function(serial, slotId)
    print(serial, slotId)
end)

#Laptop Power Changed

Fires when a laptop powers on or off: an OS started or stopped on it, or it was left on or went off. A laptop put away counts as off. Changes are noticed within about 10 seconds.

Example:

lua
---@param serial string
---@param on boolean
AddEventHandler("zyke_laptop:LaptopPowerChanged", function(serial, on)
    print(serial, on)
end)

#Laptop Dead Changed

Fires when a laptop that is out can no longer power on, or can again. A dead laptop has no board, no working memory, or a flat battery off mains, and its screen stays black.

Example:

lua
---@param serial string
---@param dead boolean
AddEventHandler("zyke_laptop:LaptopDeadChanged", function(serial, dead)
    print(serial, dead)
end)

#Laptop Placed

Fires when a player puts a laptop down. area is the placement area it went into, nil outside every area.

Example:

lua
---@param plyId integer
---@param serial string
---@param coords vector4 @ w is the heading
---@param bucket integer
---@param area? string
AddEventHandler("zyke_laptop:LaptopPlaced", function(plyId, serial, coords, bucket, area)
    print(serial, coords, bucket, area)
end)

#Laptop Picked Up

Fires when a player picks up a placed laptop. placedBy is the character who put it down.

Example:

lua
---@param plyId integer
---@param serial string
---@param coords vector4
---@param bucket integer
---@param placedBy string
---@param area? string
AddEventHandler("zyke_laptop:LaptopPickedUp", function(plyId, serial, coords, bucket, placedBy, area)
    print(serial, placedBy, area)
end)

#Computer Placed

Fires when a desktop computer is set up. owner is the character it was set up for.

Example:

lua
---@param plyId integer
---@param serial string
---@param coords vector4
---@param bucket integer
---@param owner string
AddEventHandler("zyke_laptop:ComputerPlaced", function(plyId, serial, coords, bucket, owner)
    print(serial, owner)
end)

#Computer Removed

Fires when a desktop computer is taken away.

Example:

lua
---@param plyId integer
---@param serial string
---@param coords vector4
---@param bucket integer
---@param owner string
AddEventHandler("zyke_laptop:ComputerRemoved", function(plyId, serial, coords, bucket, owner)
    print(serial, owner)
end)

#Placed Laptop Expired

Fires when placement.removeAfterDays removes a placed laptop nobody used. Its item's metadata is printed to the server console.

Example:

lua
---@param serial string
---@param placedBy string
---@param coords vector4
---@param bucket integer
---@param days number
---@param area? string
AddEventHandler("zyke_laptop:PlacedLaptopExpired", function(serial, placedBy, coords, bucket, days, area)
    print(serial, placedBy, days)
end)

#Laptop Shop Bought

Fires after a purchase at the shop. offerId is such as laptop:performance:midnight and total is the money paid. A new laptop bought with a backplate fires once for the laptop and once for the skin:<id> offer, each with its own price.

Example:

lua
---@param plyId integer
---@param offerId string
---@param total integer
AddEventHandler("zyke_laptop:LaptopShopBought", function(plyId, offerId, total)
    print(plyId, offerId, total)
end)

#Casino Deposited

Fires when dollars go from the bank into a casino wallet. balance is the wallet's credits after it, in cents.

Example:

lua
---@param plyId integer
---@param identifier string
---@param dollars integer
---@param balance integer
AddEventHandler("zyke_laptop:CasinoDeposited", function(plyId, identifier, dollars, balance)
    print(identifier, dollars, balance)
end)

#Casino Withdrawn

Fires when credits are paid out to the bank.

Example:

lua
---@param plyId integer
---@param identifier string
---@param dollars integer
---@param balance integer
AddEventHandler("zyke_laptop:CasinoWithdrawn", function(plyId, identifier, dollars, balance)
    print(identifier, dollars, balance)
end)

#Casino Credits Adjusted

Fires when another resource changes a wallet with AdjustCasinoCredits.

Example:

lua
---@param identifier string
---@param cents integer @ Negative when taken
---@param reason string
---@param resource? string @ The resource that called the export
---@param balance integer
AddEventHandler("zyke_laptop:CasinoCreditsAdjusted", function(identifier, cents, reason, resource, balance)
    print(identifier, cents, reason, resource, balance)
end)

#Laptop Reported Stolen

Fires when the owner reports a laptop stolen or withdraws the report.

Example:

lua
---@param plyId integer
---@param serial string
---@param stolen boolean
AddEventHandler("zyke_laptop:LaptopReportedStolen", function(plyId, serial, stolen)
    print(serial, stolen)
end)

#Laptop Password Reset

Fires when the installer stick of a drive's own OS sets a new password on its account.

Example:

lua
---@param plyId integer
---@param serial string @ The laptop's
---@param drive string
AddEventHandler("zyke_laptop:LaptopPasswordReset", function(plyId, serial, drive)
    print(serial, drive)
end)

#Laptop OS Installed

Fires when an installer stick erases a drive and installs its OS.

Example:

lua
---@param plyId integer
---@param serial string
---@param drive string
---@param osId "facade" | "lumen" | "solace"
AddEventHandler("zyke_laptop:LaptopOsInstalled", function(plyId, serial, drive, osId)
    print(serial, drive, osId)
end)

#Laptop Admin Command

Fires when laptop_owner, laptop_charge, or laptop_computer is used. plyId is 0 from the server console, and result is the locale key the command answered with.

Example:

lua
---@param plyId integer
---@param command string
---@param args string[]
---@param result string
AddEventHandler("zyke_laptop:LaptopAdminCommand", function(plyId, command, args, result)
    print(plyId, command, result)
end)

#Cast Screen Saved

Fires when the screen creator places a screen or changes one.

Example:

lua
---@param plyId integer
---@param screenId string
---@param label string
---@param bucket integer
---@param isNew boolean
AddEventHandler("zyke_laptop:CastScreenSaved", function(plyId, screenId, label, bucket, isNew)
    print(screenId, label, isNew)
end)

#Cast Screen Deleted

Fires when the screen creator deletes a screen.

Example:

lua
---@param plyId integer
---@param screenId string
AddEventHandler("zyke_laptop:CastScreenDeleted", function(plyId, screenId)
    print(screenId)
end)

#Applicant Hired

Fires when an employer hires an applicant on the Hireline job board. Hiring does not change the player's job; set it from here. See Job Board.

Example:

lua
---@param application {id: integer, listingId: integer, listingTitle: string, job: string, identifier: string, applicantName: string, hiredBy: string, hiredAt: integer}
AddEventHandler("zyke_laptop:jobs:ApplicantHired", function(application)
    print(application.identifier, application.job, application.hiredBy)
end)

#Police Application Reviewed

Fires when a reviewer accepts or declines an application in the example LSPD Recruitment app, with the application and the applicant's identifier. Use it to hire accepted applicants. See Example Sites.

Example:

lua
---@param application {id: integer, name: string, status: "accepted" | "declined", identifier: string, note?: string, reviewerName?: string, reviewedAt?: integer}
AddEventHandler("zyke_laptop:examples:police:ApplicationReviewed", function(application)
    if (application.status ~= "accepted") then return end

    print(("Hire %s"):format(application.identifier))
end)

#Discord Logs

The laptop sends Discord logs through zyke_lib. Set a webhook URL per action in zyke_lib/webhooks/laptop.lua; an action left empty sends nothing. Each log names who did it, or the server, and carries its raw data. The texts are the logs: keys in the locale files. See Discord Webhooks / Logs.

server/unlocked/webhooks.lua sends them. It only listens to the server events above, so change a log there freely, or listen to the same events from your own resource.

ActionEventLogged when
LaptopPlacedLaptopPlaced, ComputerPlacedA player puts a laptop down or sets a desktop computer up.
LaptopPickedUpLaptopPickedUp, ComputerRemovedA player picks up a placed laptop or takes a desktop computer away.
LaptopExpiredPlacedLaptopExpiredplacement.removeAfterDays removes an unused placed laptop.
ShopPurchaseLaptopShopBoughtSomething is bought at the shop, with the offer and what was paid.
CasinoDepositCasinoDepositedDollars go from the bank into a casino wallet.
CasinoWithdrawCasinoWithdrawnCredits are paid out to the bank.
CasinoAdjustedCasinoCreditsAdjustedAnother resource changes a wallet with AdjustCasinoCredits.
OwnerChangedLaptopOwnerChangedA laptop gets an owner or loses one.
ReportedStolenLaptopReportedStolenThe owner reports a laptop stolen or withdraws the report.
DriveUnlockedLaptopDriveUnlockedCrowbar gets past a drive's password.
PasswordResetLaptopPasswordResetAn installer stick resets a drive's password.
OsInstalledLaptopOsInstalledAn installer stick erases a drive and installs its OS.
PartInstalledPartInstalledA part goes into a laptop.
PartRemovedPartRemovedA part comes out of a laptop.
AdminActionLaptopAdminCommand, CastScreenSaved, CastScreenDeletedAn admin command is used, or the screen creator places, changes, or deletes a screen.

For custom permission rules within the laptop itself, use Can-Check Hooks.