---@meta -- KCD:MP (KCD Multiplayer) - the game mode API (server side), Lua 5.4. -- Definitions for the Lua language server (LuaLS - the VS Code "Lua" extension and its kin): completion, hover -- documentation and diagnostics while writing a script. Generated from the reference - do not edit. -- https://docs.kcd-mp.com -- ======== Server and timers ===================================================== -- The mode's own lifecycle, the server's facts, timers and the log. Everything a mode does happens on the simulation thread, -- one tick at a time, thirty times a second - the callbacks run inside a tick, the timers run in the tick they fall due, and a -- slow callback delays the tick for every player (Getting started). ---**Called by the server** - The script is loaded and the API is ready - the place to create zones, HUD texts, timers and actors. --- ---Called once when the server starts and again after every hot reload. Everything the mode ---creates - zones, HUD texts, props, actors, timers, state - is gone before it runs again, so this is where it is (re)made. ---The players are told to the mode afterwards: `OnPlayerConnect` for everyone on, then `OnPlayerLogin` for the logged-in and ---`OnPlayerSpawn` for those already in the world. function OnGameModeInit() end ---**Called by the server** - The server shuts down or the mode is about to be reloaded. --- ---The last callback of a mode's life. Persist what you need with `SetServerData` or ---`SetSavedData`; the objects the mode made are torn down by the server right after this. function OnGameModeExit() end ---**Called by the server** - Every simulation tick, with the time since the last one. --- ---Thirty times a second (`[rates] tick_hz`), after the tick's network events were applied. Whatever runs here runs for every ---tick of every player's game, so keep it to a few lines; do the heavy things on a timer every ---second instead. The server log reports the slowest tick while the budget is missed. ---@param dt number seconds since the previous tick (`0.033` at 30 Hz) function OnTick(dt) end ---Names the mode in the server log and the server browser. ---@param name string the mode's name, e.g. `"freeroam"` function SetGameModeText(name) end ---The number of the simulation tick being processed. --- ---Counts up from the server's start, one per tick (30 a second). Handy as a cheap clock for "every n ticks" logic; for ---time in milliseconds use `GetServerTime`. ---@return number the tick function GetServerTick() end ---The server's clock in milliseconds. --- ---Milliseconds since the server started - the clock the protocol carries. It wraps after about 49 days; compare differences, ---not absolute values, for anything long-lived. ---@return number milliseconds function GetServerTime() end ---How many players the server holds (`[server] max_players`). --- ---Player ids run from `0` to `GetMaxPlayers() - 1`. ---@return number the slot count function GetMaxPlayers() end ---The name of the level the server runs. --- ---`[server] level` in `server.toml`: `klaster`, `trosecko` or `kutnohorsko` (Levels). ---Every client boots the same level; the launcher asks the server which. ---@return string the level name function GetLevel() end ---The level as a player reads it. --- ---The game's own name of the level `GetLevel` names: `Trosky` for `trosecko`, `Kuttenberg` for `kutnohorsko`, ---`Sedletz Monastery` for `klaster`. For what a player sees - a welcome line, a HUD text; keep `GetLevel` for ---comparisons and file names. ---@return string the name function GetLevelName() end ---Writes a line to the server log, prefixed `[lua]`. --- ---Every argument is converted with `tostring` and joined with spaces, like `print` - and `print` **is** this function in a ---game mode. The line lands in the server's log (the console and the log file), never in a player's chat. ---@param ... any the values to write function Log(...) end ---Calls a function after a delay, once or repeatedly. --- ---The function runs on the simulation thread in the tick the timer falls due - the same place a callback runs, so it may call ---anything a callback may. A repeating timer runs every `ms` milliseconds until `KillTimer`; a one-shot timer ---runs once and is gone. Timers belong to the mode: a reload discards them. The shortest interval is one tick (about 33 ms). ---@param fn function the function to call (no arguments) ---@param ms number the delay, and the interval of a repeating timer, in milliseconds ---@param repeating? boolean `true` repeats every `ms`; `false` or nothing fires once ---@return number the timer's id, for `KillTimer` function SetTimer(fn, ms, repeating) end ---Stops a timer. ---@param id number the id `SetTimer` returned ---@return boolean `true` when there was such a timer function KillTimer(id) end ---Reloads this mode at the end of the tick, without restarting the server. --- ---The running mode is shut down (`OnGameModeExit`), everything it made is torn down - zones, HUD texts, props, actors, state ---bags, nameplates, colours, teams, timers, `SetPlayerData`, the admins it promoted - and the script is read again from disk ---and initialised (`OnGameModeInit`), then told about every player again (`OnPlayerConnect`, `OnPlayerLogin`, ---`OnPlayerSpawn`). The players, their vitals, inventories, buffs, horses, drops, doors and containers stay as they are; ---everyone reads `the game mode was reloaded: `. A script that fails to load leaves the built-in freeroam in charge ---until the next reload; a missing file refuses the reload. `/reload` (admins) and `[gamemode] watch = true` do the same. ---@param reason? string a word for the log (`"the script asked"` without one) function ReloadGameMode(reason) end -- ======== Players =============================================================== -- A player is a `pid` from `0` to `GetMaxPlayers() - 1`, given at the handshake and **reused after a disconnect**: keep the -- pid while a player is on, and check `IsPlayerConnected` before trusting a pid kept across ticks. Readers return `nil` for a -- pid that is not connected; setters return `false`. Positions are metres, yaw is degrees (`0` = facing +Y, counter-clockwise); -- a mounted player's position and velocity are the horse's. ---**Called by the server** - The handshake is done and the client is loading the level. --- ---The player has a name and an address and no position yet; they are not in the world until `OnPlayerSpawn`. A returning ---player's record is already readable (`GetSavedPlayer`). Also called for everyone on the server after a ---reload. ---@param pid number the player function OnPlayerConnect(pid) end ---**Called by the server** - The client's level is ready - decide where the player spawns, or hold them. --- ---Set the spawn point with `SetSpawnInfo` and return `true` (or nothing): the player is spawned there - or at the server's ---default point without one - and `OnPlayerSpawn` follows. Return `false` to **hold** the player: their screen says ---"waiting for the spawn" until the mode calls `SpawnPlayer` - a lobby, a team pick, a class menu. Called once per level ---load, not on respawns. --- ---Return value: `true` or nothing spawns the player now; `false` holds them until `SpawnPlayer` ---@param pid number the player function OnPlayerRequestSpawn(pid) end ---**Called by the server** - The player stands in the world and the others see them. --- ---After the first spawn, every respawn after a death, and every `SpawnPlayer`. Vitals are full, the position is the ---spawn point, `IsPlayerInWorld` is `true`. Show the player their HUD texts here - a late joiner gets nothing shown before. ---@param pid number the player function OnPlayerSpawn(pid) end ---**Called by the server** - The player is gone. --- ---`reason` is `"disconnected"` (they left), `"timed out"` (nothing heard for a while) or `"kicked: "` with the text ---given to `Kick` or `Ban`. Their pid may be given to the next player who joins; their `SetPlayerData` is cleared, their ---saved record has been written. A horse they controlled stays in the world (a nearby player takes it over); their dog leaves ---with them; every fight of theirs ends. ---@param pid number the player ---@param reason string why, as above function OnPlayerDisconnect(pid, reason) end ---Everyone who passed the handshake, in join order. ---@return table a list of pids, `{}` on an empty server function GetPlayers() end ---How many players are connected. ---@return number function GetPlayerCount() end ---The player's name, as they joined. --- ---Names are unique on a server and compared case-insensitively; a registered name (`IsPlayerRegistered`) belongs to whoever ---logs in with its password. `nil` when no player has the pid. ---@param pid number the player ---@return string|nil function GetPlayerName(pid) end ---The player a command names - a pid, a name or a fragment of one - or `nil`. --- ---The reverse of `GetPlayerName`, for commands that take a player: `"2"` or `2` is the pid 2 (returned when that ---player is connected); a name is matched case-insensitively - the exact name wins, else a fragment (`"hen"` for ---Henry) when exactly one connected name contains it. `nil` when nobody matches or two do, so a command can answer ---"no player called ..." and never guess between two. `sscanf`'s `u` letter is this function. ---@param name string|number a pid, a name, or a fragment of a name ---@return number|nil the pid function GetPlayerId(name) end ---Whether a pid belongs to a connected player. --- ---`true` from the handshake to the disconnect - the player may still be loading the level. For "standing in the world" use ---`IsPlayerInWorld`. ---@param pid number the player ---@return boolean function IsPlayerConnected(pid) end ---Whether the player is spawned and replicated. --- ---`false` while the level loads, while a spawn is held, after a despawn. Positions and vitals mean something only while this ---is `true`; a dead player waiting for the respawn is still in the world (`IsPlayerDead`). ---@param pid number the player ---@return boolean function IsPlayerInWorld(pid) end ---The player's round trip to the server in milliseconds. ---@param pid number the player ---@return number milliseconds; `-1` when not connected function GetPlayerPing(pid) end ---The player's address. ---@param pid number the player ---@return string `"a.b.c.d"`; `""` when not connected function GetPlayerIP(pid) end ---The player's position of record. --- ---Metres in the level's world space, from the client's reports (thirty a second); a mounted player's position is the horse's. ---A report that would move a player faster than `[validation] max_speed` allows is refused and the client pulled back, so the ---record is the server's own opinion of where they are. ---@param pid number the player ---@return number x three numbers `x, y, z`; `nil` when not connected ---@return number y ---@return number z function GetPlayerPos(pid) end ---The direction the player faces, in degrees. --- ---The game's convention: `0` faces +Y, `90` faces -X, `180` faces -Y, `270` faces +X - counter-clockwise seen from above. ---@param pid number the player ---@return number degrees `0`..`360`; `0` when not connected function GetPlayerYaw(pid) end ---The player's velocity in metres per second. ---@param pid number the player ---@return number vx three numbers `vx, vy, vz`; `nil` when not connected ---@return number vy ---@return number vz function GetPlayerVelocity(pid) end ---Moves the player's game to a point - a teleport. --- ---The client puts the player there on the next frame and the server's record follows; reports from before the move are ---dropped, so honest clients never trip the speed check. `z` below `0` puts the player on the terrain at `x, y`. A mounted ---player is moved with the horse. Without `yaw` the player keeps their heading. ---@param pid number the player ---@param x number metres ---@param y number metres ---@param z number metres; below `0` = on the terrain ---@param yaw? number degrees to face ---@return boolean `false` when not connected function SetPlayerPos(pid, x, y, z, yaw) end ---Where and as what the player's next spawn happens. --- ---Sets the point and the outfit for the next `SpawnPlayer` or the spawn that follows `OnPlayerRequestSpawn`. The ---presets are GUIDs from the game's tables - clothing presets and ---weapon presets; `""` or `nil` keeps the server's `[spawn]` defaults. `appearance` is the soul ---whose face and body the **other** players see on this player's body - a soul of the `NPC` or `NPC_Female` archetype from ---the souls by name, id or GUID; `""` picks one from the server's `[spawn] appearances` pool by the ---player's name, so a player looks the same every visit. The point is remembered until the next `SetSpawnInfo`; respawns ---after a death use it too. ---@param pid number the player ---@param x number metres ---@param y number metres ---@param z number metres; below `0` = on the terrain ---@param yaw number degrees to face (`0` without) ---@param clothingPreset? string a clothing preset GUID; `""` = the server default ---@param weaponPreset? string a weapon preset GUID; `""` = the server default ---@param appearance? string the soul whose face the others see (name, id or GUID); `""` = the server's pool ---@return boolean `false` when not connected function SetSpawnInfo(pid, x, y, z, yaw, clothingPreset, weaponPreset, appearance) end ---Spawns - or respawns - the player at their SetSpawnInfo point. --- ---Puts a player whose level is loaded into the world at the point `SetSpawnInfo` set (the server's default without one), or ---moves and re-outfits one who already is; `OnPlayerSpawn` follows. The way to release a player held by ---`OnPlayerRequestSpawn` returning `false`, and to respawn the dead when `[combat] respawn_seconds` is `0`. A spawn heals: ---full health and stamina, injuries and the server's buffs gone. ---@param pid number the player ---@return boolean `false` when not connected function SpawnPlayer(pid) end ---The server's spawn point from server.toml. ---@return number x the `[spawn]` section's point as `x, y, z, yaw` ---@return number y ---@return number z ---@return number yaw function GetDefaultSpawn() end ---Remembers a spawn point under a tag. --- ---A plain list the prelude keeps for the mode - nothing on the server side. Points are grouped by `tag` (`""` without one): ---one list per team, per arena, per role. ---@param x number metres ---@param y number metres ---@param z number|nil metres; `nil` = `-1`, on the terrain ---@param yaw number degrees (`0` without) ---@param tag? string the list to add to ---@return number how many points the list holds now function AddSpawnPoint(x, y, z, yaw, tag) end ---The spawn points of a tag. ---@param tag? string the list (`""` without) ---@return table a list of `{x=, y=, z=, yaw=}`; `{}` when empty function GetSpawnPoints(tag) end ---One spawn point of a tag, at random. ---@param tag? string the list (`""` without) ---@return number x a point as `x, y, z, yaw`; `nil` when the list is empty ---@return number y ---@return number z ---@return number yaw function GetRandomSpawnPoint(tag) end ---Forgets the spawn points of a tag. ---@param tag? string the list (`""` without) function ClearSpawnPoints(tag) end ---Holds or releases the player's keyboard. --- ---`false` freezes the player where they stand: the keyboard does nothing on their client, the mouse still looks around, ---**T** and **Enter** still open the chat. `true` gives the keyboard back. The server's own login hold uses the same lever ---for a registered name until its `/login`. ---@param pid number the player ---@param controllable boolean `false` holds, `true` releases ---@return boolean `false` when not connected function TogglePlayerControllable(pid, controllable) end ---Whether the player's keyboard is theirs right now. ---@param pid number the player ---@return boolean `false` while held function IsPlayerControllable(pid) end ---Disconnects the player with a reason. --- ---The player's client shows the reason and leaves; `OnPlayerDisconnect` follows with `"kicked: "`. Nothing keeps ---them from rejoining - for that, `Ban`. ---@param pid number the player ---@param reason? string shown to the player (`"kicked"` without one) ---@return boolean `false` when not connected function Kick(pid, reason) end ---The label over the player's body on every other screen. --- ---By default the label is the player's name; this replaces it - a rank, a team tag, a title. `""` puts the name back. ---At most 48 characters. The label keeps its colour (`SetPlayerColour`) and hides behind walls like the name does. ---@param pid number the player ---@param text string the label; `""` = the name again ---@return boolean `false` when not connected function SetPlayerNameplate(pid, text) end ---The label as the mode set it. ---@param pid number the player ---@return string the text; `""` when it is the name function GetPlayerNameplate(pid) end ---The colour of the player's label and of their name in the Tab roster. --- ---`0xRRGGBBAA`; `0` puts the default back. The alpha byte matters - `0x4080FF00` is invisible. `SetPlayerColor` is the same ---function. ---@param pid number the player ---@param colour number `0xRRGGBBAA`; `0` = the default ---@return boolean `false` when not connected function SetPlayerColour(pid, colour) end ---The same function as `SetPlayerColour`. SetPlayerColor = SetPlayerColour ---The player's colour as set. ---@param pid number the player ---@return number `0xRRGGBBAA`; `0` = the default function GetPlayerColour(pid) end ---The same function as `GetPlayerColour`. GetPlayerColor = GetPlayerColour ---Puts the player in a team - teammates cannot hurt each other. --- ---Any number is a team; `NO_TEAM` (`-1`) is none. **A hit between two players of one team is refused** before ---`OnPlayerDamage` and starts no fight. Nothing else is implied - no colour, no label, no spawn: those are the mode's ---to set alongside. A mode that wants friendly fire back writes its rule in `OnPlayerDamage` and leaves teams unset. ---@param pid number the player ---@param team number the team; `NO_TEAM` (`-1`) = none ---@return boolean `false` when not connected function SetPlayerTeam(pid, team) end ---The player's team. ---@param pid number the player ---@return number the team; `NO_TEAM` (`-1`) when none function GetPlayerTeam(pid) end ---The virtual world the player is in. --- ---Players and entities are replicated to each other **within one world only**; `0` is the shared world. A registered name ---waiting for its `/login` sits in a world of its own. See Getting started and ---`SetPlayerVirtualWorld`. ---@param pid number the player ---@return number the world; `nil` when not connected function GetPlayerVirtualWorld(pid) end ---Moves the player into another virtual world. --- ---From the next snapshot on the player sees, and is seen by, the players and entities of `world` only; the others part with ---them as if they had left and meet them again when they come back. Their mount comes along; a loose horse they controlled ---stays behind for whoever is nearest. Chat, the roster, the scoreboard, doors and containers stay global. Fights and hits ---stay inside a world. The client never learns its world - nothing changes on the player's screen but who is around. ---Instanced duels, private lobbies, a hidden staging area for the next round. ---@param pid number the player ---@param world number the world; `0` = the shared one ---@return boolean `false` when not connected function SetPlayerVirtualWorld(pid, world) end -- ======== Chat and commands ===================================================== -- Every chat line a player types passes through the mode before anyone sees it: a plain line through `OnPlayerText`, a `/` -- line through `OnPlayerCommandText`. A `/` line the mode does not answer goes to the server's own -- built-in commands (`/help`, `/pos`, `/give`, `/tp`, `/horse` ...), then to `Unknown command`; a mode -- overrides a built-in by handling its name. `/register`, `/login`, `/fight` and `/peace` are the server's and are answered -- before the mode sees them. The mode's own lines go out with `SendClientMessage` and `SendClientMessageToAll`. ---**Called by the server** - A plain chat line - return `false` and nobody sees it. --- ---Never a `/` command (those are `OnPlayerCommandText`). Anything but `false` lets the line through to everyone ---connected, in the player's own colour. Filters, team channels, a muted player, a whisper: return `false` and send the line ---on yourself with `SendClientMessage`. --- ---Return value: `false` suppresses the line; anything else (or nothing) lets it through ---@param pid number who typed it ---@param text string the line, as typed function OnPlayerText(pid, text) end ---**Called by the server** - A `/` command - return `true` when the mode answered it. --- ---`/tp 1 2 3` arrives as `cmd = "tp"`, `args = "1 2 3"`: the word after the slash as typed (compare it lower-cased if you want ---to be lenient) and the rest of the line, trimmed. Return `true` to say the mode answered - even when the answer was "you ---may not". Return `false` (or nothing) and the server's built-in commands get the line, then ---`Unknown command: /x`. A mode takes a built-in over by answering its name; a `/help` that prints a line and returns `false` ---is followed by the server's own list. Commands are never echoed to the chat. --- ---Return value: `true` = handled; `false` or nothing = the server's built-ins, then "Unknown command" ---@param pid number who typed it ---@param cmd string the command without the slash, as typed ---@param args string everything after the command, trimmed; `""` when nothing function OnPlayerCommandText(pid, cmd, args) end ---The arguments of a command as typed values - a player, a number, a word, the rest of the line - in one call. --- ---The name is SA-MP's on purpose: the same job, one letter per argument. `args` is the string `OnPlayerCommandText` hands ---you; `format` is one letter per argument, in order: --- ---| letter | the argument | what you get | ---|---|---|---| ---| `u` | a player: a pid or a name (or a fragment of one), as `GetPlayerId` reads it | the pid | ---| `d` | a whole number (`-3`, `50`) | a number | ---| `f` | a number (`0.5`, `12`) | a number | ---| `s` | one word - or a `"quoted string"` taken whole | a string | ---| `z` | the rest of the line, from here to the end | a string | --- ---A `?` after a letter makes that argument optional: `nil` when it is not there. Words are split on spaces; whatever ---follows the last letter is ignored. It returns the values in the format's order. When a required argument is ---missing or does not read - a number that is not one, a player nobody is called - it returns **`false` and the reason** ---(`"argument 2 (abc) is not a whole number"`, `"no player called xyz"`), ready for a usage line: check the first ---value against `false`, not against `nil`, when the first letter is optional. ---@param args string the command's arguments as `OnPlayerCommandText` gives them ---@param format string one letter per argument (`u d f s z`), a `?` after a letter for an optional one ---@return any ... the values in order, or `false, reason` function sscanf(args, format) end ---A line in one player's chat. --- ---The line appears in the player's chat window in `colour` (`0xRRGGBBAA`; the colour ---constants name the usual ones). Long lines wrap; keep them to a sentence or two. ---@param pid number the player ---@param colour number `0xRRGGBBAA` ---@param text string the line ---@return boolean `false` when not connected function SendClientMessage(pid, colour, text) end ---The same line in everyone's chat. ---@param colour number `0xRRGGBBAA` ---@param text string the line function SendClientMessageToAll(colour, text) end -- ======== Vitals, stats and skills ============================================== -- The server owns every player's **health, stamina, injuries and bleeding** (`[combat]` in `server.toml`; the -- Combat guide has how a hit becomes damage). Health and stamina are full at every spawn; `0` health is dead -- until the respawn. Stats and skills are the game's own character levels, raised by the server and kept on the record. ---The player's health. ---@param pid number the player ---@return number `0` .. `GetPlayerMaxHealth`; `-1` when not connected function GetPlayerHealth(pid) end ---The player's maximum health (100). ---@param pid number the player ---@return number `-1` when not connected function GetPlayerMaxHealth(pid) end ---Sets the player's health; 0 kills. --- ---Clamped to `0 .. max`; the player's client shows the new value. `0` kills the player at once - `OnPlayerDeath` with ---attacker `-1`, the respawn after `[combat] respawn_seconds`. A dead player's health stays `0` until they respawn; use ---`HealPlayer` or `SpawnPlayer` to bring one back. ---@param pid number the player ---@param health number the new health ---@return boolean `false` when not connected function SetPlayerHealth(pid, health) end ---Whether the player's health is 0 and they wait for the respawn. ---@param pid number the player ---@return boolean function IsPlayerDead(pid) end ---The player's stamina - the bar they see. --- ---Swings, hits taken, blocks, shots, sprints and jumps cost it; it regenerates after a pause (Combat). ---What the player sees on their stamina bar **is** this number. ---@param pid number the player ---@return number `0` .. `GetPlayerMaxStamina`; `-1` when not connected function GetPlayerStamina(pid) end ---The player's maximum stamina (`[combat] max_stamina`). ---@param pid number the player ---@return number `-1` when not connected function GetPlayerMaxStamina(pid) end ---Sets the player's stamina. --- ---Clamped to `0 .. max`. A swing thrown with less stamina than it costs lands weakly - a mode may tire a player on purpose. ---@param pid number the player ---@param stamina number the new stamina ---@return boolean `false` when not connected function SetPlayerStamina(pid, stamina) end ---The player's injured body parts. --- ---A list of body parts, `BODY_PART_HEAD` .. `BODY_PART_LEG_RIGHT` (`1` .. `6`); `{}` when whole. An injured arm makes the ---swings weaker and costlier, an injured head or torso halves the stamina regeneration. A hit of at least ---`[combat] injury_threshold` injures the part it struck; `OnPlayerInjury` says so. ---@param pid number the player ---@return table a list of body part ids function GetPlayerInjuries(pid) end ---Whether the player has an injury - anywhere, or on one part. ---@param pid number the player ---@param part? number a body part `1` .. `6`; without it, any part ---@return boolean function IsPlayerInjured(pid, part) end ---The name of a body part id. ---@param part number `1` head, `2` torso, `3` left arm, `4` right arm, `5` left leg, `6` right leg ---@return string `"head"`, `"torso"`, `"arm_left"`, `"arm_right"`, `"leg_left"`, `"leg_right"`; `""` for anything else function GetBodyPartName(part) end ---How fast the player is bleeding, in health per second. --- ---A stab or a slash opens a bleed for `[combat] bleed_seconds`; `0` means not bleeding. A bleed-out is a death by the last ---attacker. A bandage stops it, so do `HealPlayer` and the respawn. ---@param pid number the player ---@return number health lost per second; `0` = not bleeding function GetPlayerBleeding(pid) end ---Whether the player is bleeding. ---@param pid number the player ---@return boolean function IsPlayerBleeding(pid) end ---Makes the player whole - health, stamina, injuries, bleeding, buffs, drink. --- ---Full health and stamina, every injury healed, the bleeding stopped, every buff the server gave taken back, sober; the ---player's client shows it and the others see the body straighten. The `/heal` built-in does the same. ---@param pid number the player ---@return boolean `false` when not connected function HealPlayer(pid) end ---Raises a core stat of the player's character to a level. --- ---`stat` is one of the game's core stats - `strength`, `agility`, `vitality`, `speech` (Stats and ---skills) - and `level` `1` .. `30`. The level is kept on the player's record for the session and re-applied at every spawn; ---the game **never lowers** a level, so this only raises. Every player starts as the level's character, level 5 everywhere, ---and `[spawn] stat_level` raises the four core stats for everyone at the spawn; a hunting bow needs strength 13 to be held ---drawn. The name is not checked against the game's list - a misspelt one is recorded and does nothing. ---@param pid number the player ---@param stat string the stat's name ---@param level number `1` .. `30` ---@return boolean `false` for an empty name, a level outside `1`..`30` or a player not connected function SetPlayerStat(pid, stat, level) end ---Raises a skill of the player's character to a level. --- ---`skill` is one of the game's skill names - `marksmanship`, `fencing`, `weapon_sword`, `heavy_weapons`, `horse_riding`, ---`stealth` ... (Stats and skills) - and `level` `1` .. `30`. Kept on the record, re-applied at ---every spawn, never lowered; an unknown name does nothing. ---@param pid number the player ---@param skill string the skill's name ---@param level number `1` .. `30` ---@return boolean `false` for an empty name, a level outside `1`..`30` or a player not connected function SetPlayerSkill(pid, skill, level) end ---The level of record of a core stat. ---@param pid number the player ---@param stat string the stat's name ---@return number the level the server set; `0` = never set (the character's own level is not read back) function GetPlayerStat(pid, stat) end ---The level of record of a skill. ---@param pid number the player ---@param skill string the skill's name ---@return number the level the server set; `0` = never set function GetPlayerSkill(pid, skill) end -- ======== Combat ================================================================ -- A player's game only reports what its swing or its arrow hit; the server decides what that did and tells the mode. The -- Combat guide walks through the model - the tables, stamina, injuries and bleeding, fights and the lock-on, -- teams and pvp. The callbacks let a mode change or cancel every hit; the functions manage fights. ---**Called by the server** - The server accepted a hit on a player - change the damage, cancel it, or let it through. --- ---Called before the damage comes off the health. `attacker` is the pid who struck, or `-1` for damage without one (an NPC ---actor's blow when the mode has no `OnActorAttack`, `SetPlayerHealth`). `zone` is the attack zone the attacker's game ---recorded; `part` the body part struck, `1` .. `6` (`0` unknown; `GetBodyPartName`); `weapon` the attacker's weapon by its ---table name (`shortswordBroad`, `bow_c + arrow_normal`; `""` bare-handed or without the tables); `dtype` `"stab"`, `"slash"`, ---`"smash"` or `""`. **Return a number** to change the damage (`0` cancels the hit, so do a stamina cost, an injury and a ---bleed), **`false`** to cancel it, nothing to keep it. Hits between teammates never get here. --- ---Return value: a number replaces the damage (`0` cancels); `false` cancels the hit; nothing keeps it ---@param pid number the victim ---@param attacker number who struck; `-1` = nobody ---@param damage number what the victim is about to lose ---@param zone number the attack zone the attacker's game recorded ---@param part number the body part struck, `1` .. `6`; `0` unknown ---@param weapon string the weapon's table name; `""` bare-handed ---@param dtype string `"stab"`, `"slash"`, `"smash"` or `""` function OnPlayerDamage(pid, attacker, damage, zone, part, weapon, dtype) end ---**Called by the server** - A hit injured one of the player's body parts. --- ---A hit of at least `[combat] injury_threshold` injures the part it struck. An injured arm makes the player's swings weaker ---and costlier; an injured head or torso halves the stamina regeneration. `HealPlayer` and the respawn heal it. ---@param pid number the victim ---@param attacker number who struck; `-1` = nobody ---@param part number the body part, `1` .. `6` function OnPlayerInjury(pid, attacker, part) end ---**Called by the server** - The player's health reached 0. --- ---A hit, a bleed-out (the last attacker is named) or `SetPlayerHealth(pid, 0)` (attacker `-1`). Every client shows the death; ---the respawn follows after `[combat] respawn_seconds` at the player's spawn point - with `0` there the mode calls ---`SpawnPlayer` itself. Every fight of the player ends (`OnFightEnd` with `"death"`). ---@param pid number who died ---@param attacker number who killed them; `-1` = nobody function OnPlayerDeath(pid, attacker) end ---**Called by the server** - Two players are in a fight from now on. --- ---Their clients let the game's lock-on pick each other's body from here. `reason` is `"hit"` (a swing of one reached the ---other's body), `"command"` (`/fight `) or `"mode"` (`StartFight`). Both players read a chat line about it. ---@param a number one player ---@param b number the other ---@param reason string `"hit"`, `"command"` or `"mode"` function OnFightStart(a, b, reason) end ---**Called by the server** - A fight between two players is over. --- ---`reason` is `"timeout"` (`[combat] fight_timeout` seconds without a blow), `"death"`, `"left"` (a disconnect), `"peace"` ---(`/peace`) or `"mode"` (`EndFight`). Both clients drop the lock. ---@param a number one player ---@param b number the other ---@param reason string `"timeout"`, `"death"`, `"left"`, `"peace"` or `"mode"` function OnFightEnd(a, b, reason) end ---Puts two players in a fight so their games can lock on to each other. --- ---From here either one's game may pick the other's body as the opponent - the direction indicators, the combat stance. The ---server starts a fight by itself when a swing reaches a body and on `/fight `; this is the mode's way (`reason` ---`"mode"`). On a fight that is already running it **restarts the `[combat] fight_timeout` clock** - a duel mode calls it ---every second so two circling duelists never lose the lock. `false` when pvp is off, one of the two is dead or not in the ---world, or they are in different virtual worlds. Teammates can be put in a fight, but their hits stay refused. ---@param a number one player ---@param b number the other ---@return boolean `true` when the two fight now function StartFight(a, b) end ---Ends the fight between two players. --- ---Both clients drop the lock; `OnFightEnd` fires with `"mode"`. Nothing happens when the two were not fighting. ---`/peace` ends every fight of the caller the same way. ---@param a number one player ---@param b number the other ---@return boolean `false` when one of them is not connected function EndFight(a, b) end ---Whether two players are in a fight right now. ---@param a number one player ---@param b number the other ---@return boolean function AreFighting(a, b) end ---Everyone the player is fighting right now. ---@param pid number the player ---@return table a list of pids, `{}` at peace function GetPlayerOpponents(pid) end ---The weapon the damage model charges the player's hits to. --- ---The table name of the melee weapon the player has equipped and drawn (`shortswordBroad`, `longSwordDuel` ...), as the ---`weapon` argument of `OnPlayerDamage` names it; `""` bare-handed, with the weapon sheathed, or without the tables export. ---`GetItemInfo` turns the name into its catalogue entry. ---@param pid number the player ---@return string the weapon's name; `""` when none function GetPlayerWeapon(pid) end -- ======== Buffs and the drink =================================================== -- A **buff** is the game's own timed or permanent modifier on a character - a potion's effect, an injury, drunkenness, a perk's -- bonus. The server gives and takes them by **id, name or GUID** from the buff list; the player's client -- adds the game's buff once and removes it by GUID. The server also keeps a **blood-alcohol level** per player from the drinks -- their game consumed, and judges when they are drunk. A player's game consuming anything - a potion, food, an ointment - goes -- through the server (`OnPlayerUseItem`), which applies the tables' effect (Consumables). ---**Called by the server** - The player's game consumed an item - the server is about to apply its effect; return `false` to cancel. --- ---A potion drunk, food eaten, an ointment applied. The server looked the class up in the game's tables ---(Consumables) and is about to add `health` to its own vitals (a potion's heal-over-time runs at ---`[combat] potion_speed` times the game's pace) and give the buff `buff` (`GivePlayerBuff`). Return `false` to cancel both ---- the item is gone from the player's inventory either way, their game consumed it. Item classes the tables do not know ---never get here; a use of an item the player never held is refused by the inventory audit first. ---A drink raises the alcohol level on the side (`OnPlayerDrunk`). --- ---Return value: `false` cancels the health and the buff; anything else lets them through ---@param pid number the player ---@param class string the item's class GUID (`GetItemName` turns it into a name) ---@param health number the health the server is about to add (a negative number hurts) ---@param buff string the buff GUID the server is about to give; `""` = none function OnPlayerUseItem(pid, class, health, buff) end ---**Called by the server** - The player got drunk, or sobered up. --- ---`true` when the blood-alcohol level crossed `[combat] drunk_threshold` upwards (the game's drunkenness is on, the others see ---the body sway); `false` when it fell back under half of it (the hangover follows for `[combat] hangover_seconds`). ---@param pid number the player ---@param drunk boolean `true` = drunk now, `false` = sober again function OnPlayerDrunk(pid, drunk) end ---Gives the player a buff of the game's tables. --- ---`buff` is a key of the buff list: the id, the name (`well_rested`, case-insensitive) or the GUID. ---The player's client adds the game's buff once; the record lasts until `RemovePlayerBuff`, the `seconds` given, `HealPlayer` ---or the respawn. `seconds` is the server's own clock - `0` or none means no clock; the game's own duration (the list's ---`duration` column, in game minutes) may end a timed buff's *visible* effect earlier, and the server does not re-apply it. ---`false` for an unknown key or a player not in the world. ---@param pid number the player ---@param buff string|number the buff's name, id or GUID ---@param seconds? number take it back after this long; `0` or none = keep it ---@return boolean `true` when given function GivePlayerBuff(pid, buff, seconds) end ---Takes a buff off the player. --- ---Removes the server's record and every copy of the buff on the player's character, including ones the game gave by itself. ---@param pid number the player ---@param buff string|number the buff's name, id or GUID ---@return boolean `true` when the key resolved and the player is connected function RemovePlayerBuff(pid, buff) end ---Whether the server gave the player this buff and has not taken it back. ---@param pid number the player ---@param buff string|number the buff's name, id or GUID ---@return boolean function HasPlayerBuff(pid, buff) end ---The buffs the server gave the player, as GUIDs. ---@param pid number the player ---@return table a list of buff GUIDs; `{}` when none function GetPlayerBuffs(pid) end ---Takes every server-given buff off the player. ---@param pid number the player function ClearPlayerBuffs(pid) end ---The buff classes the server has claimed. --- ---A claimed class is one the server takes over: every client undoes the game's own application of any buff of that class ---unless the server gave it. `[combat] claimed_buffs` sets the list at startup; `ClaimBuffClasses` changes it. ---@return table a list of class names (`"Potion"`, `"Poison"` ...); `{}` when nothing is claimed function GetClaimedBuffClasses() end ---Names the buff classes the server takes over from the game. --- ---With a class claimed, a buff of that class a player's game applies by itself - a potion drunk, a poison, the game's own ---drunkenness - is undone on their client within a second unless the server gave it (`GivePlayerBuff`). The way a mode keeps ---the game's own potions from opening a hole in the server-owned health: with `Potion` claimed, a potion only works through the ---server's consumption path. The class names are the pages of the buff list - ---`Potion`, `Poison`, `Alcohol`, `Hangover`, `Unconsciousness`, `Plague` ...; an unknown one is logged and ignored. The whole ---list replaces the previous one and goes to every client; `{}` claims nothing. Nothing is claimed by default. ---@param classes table a list of class names function ClaimBuffClasses(classes) end ---The player's blood-alcohol level, 0 to 1. --- ---Each drink adds its alcohol content × `[combat] alcohol_per_content`; time takes `[combat] alcohol_decay` off per second. ---Drunk from `[combat] drunk_threshold` up, sober again from half of it down (`OnPlayerDrunk`). ---@param pid number the player ---@return number `0` .. `1` function GetPlayerAlcohol(pid) end ---Whether the player is drunk. ---@param pid number the player ---@return boolean function IsPlayerDrunk(pid) end ---Sets the player's blood-alcohol level; the drunk state is judged at once. --- ---Above the threshold the player is drunk on the spot - the game's drunkenness buff on their character, the sway on the ---others' screens, `OnPlayerDrunk(pid, true)`; `0` sobers them (the hangover follows as after a real night). ---@param pid number the player ---@param level number `0` .. `1` function SetPlayerAlcohol(pid, level) end -- ======== Items and inventory =================================================== -- What a player carries, what the server gives them, and the pickups lying in the world. An item is named by any key of -- the item catalogue - the id, the game's name, the English name or the class GUID; the client reports -- equipment and inventory as class GUIDs (`GetItemName` turns one into a name). Items the server hands out - the spawn outfit, -- `GivePlayerItem`, a pickup taken, a take from a chest - are the ones the inventory audit can explain. ---**Called by the server** - The player picked a pickup up - return `false` to take it back. --- ---The player's client already holds the item when this runs. Return `false` and the item is taken from them and the pickup ---stays in the world for everyone. Otherwise the pickup is gone for everyone and the item is the player's - the audit counts ---it as explained. --- ---Return value: `false` refuses the pickup; anything else lets them keep it ---@param pid number the player ---@param id number the pickup entity (`GetEntityTemplate` is its class GUID) function OnPlayerPickup(pid, id) end ---**Called by the server** - The player dropped an item and the world made a pickup of it. --- ---The player's own game dropped the item; the server made pickup `id` of it so everyone sees it lying there and anyone may take ---it. Nothing to veto - the dropper's screen already shows it; a mode that wants it gone calls `DestroyEntity`. ---@param pid number the player ---@param id number the new pickup entity function OnPlayerDrop(pid, id) end ---What the player's client reports as equipped - clothing, armour, the weapons in the slots. --- ---Class GUIDs, as the client last reported them. The damage model reads the armour from here; `GetPlayerWeapon` names the ---weapon it charges the hits to. ---@param pid number the player ---@return table a list of item class GUIDs; `{}` before the first report function GetPlayerEquipment(pid) end ---The player's whole inventory as their client last reported it. --- ---One entry per stack: the class GUID, how many, the item's condition in percent. Reported 1.5 s after a spawn, then every 10 s ---or within a second of a change; `{}` before the first report. Money is not reported. ---@param pid number the player ---@return table a list of `{class=, amount=, health=}` function GetPlayerInventory(pid) end ---Puts items in the player's inventory - or takes them out. --- ---`amount` (default `1`) of the item; a **negative** amount takes that many away. `item` is any key of ---the item catalogue: the id, the game's name (`shortswordBroad`), the English name (`Duelling ---longsword`) or the class GUID; an unknown key is logged and nothing happens. Items given here are the server's own in the ---inventory audit. The `/give` built-in is the same call. ---@param pid number the player ---@param item string|number the item's name, id, English name or GUID ---@param amount? number how many (`1`); negative takes ---@return boolean `false` when not connected function GivePlayerItem(pid, item, amount) end ---Puts an item on the ground for everyone to see and anyone to take. --- ---A pickup entity of `ENTITY_ITEM`: every client in range shows the item lying at the point; whoever takes it gets the item ---(`OnPlayerPickup`) and the pickup is gone for everyone. `item` is any key of the item catalogue. ---`world` is the virtual world (`nil` = the shared one). `nil` when the key is unknown or the world is full ---(`[world] max_entities`). The `/item` built-in places one in front of an admin. ---@param item string|number the item's name, id, English name or GUID ---@param x number metres ---@param y number metres ---@param z number metres ---@param yaw? number degrees (`0` without) ---@param world? number the virtual world; `nil` = the shared one ---@return number the pickup's entity id; `nil` when it could not be made function CreatePickup(item, x, y, z, yaw, world) end -- ======== GameText and HUD ====================================================== -- Two ways to put text on a player's screen besides the chat: a **GameText** - one big line for a moment ("Round 3", "You win", -- a subtitle) - and a **HUD text** - a line the mode places at a fraction of the screen and keeps there, changing it whenever -- (a clock, a score, a timer). Both draw under the game's own menus and vanish behind the loading screen. For anything richer a -- client script draws it. ---One big line on the player's screen for a while. --- ---A line in a large serif, fading out over its last half second; a new one replaces the old. `style` is `GAMETEXT_CENTRE` ---(`0`, big in the middle), `GAMETEXT_TOP` (`1`, under the top edge) or `GAMETEXT_LOWER` (`2`, the lower third, like a ---subtitle). ---@param pid number the player ---@param text string the line ---@param ms? number how long it stays, milliseconds (`3000`; `100` .. `60000`) ---@param style? number `GAMETEXT_CENTRE` (the default), `GAMETEXT_TOP` or `GAMETEXT_LOWER` ---@return boolean `false` when not connected function GameText(pid, text, ms, style) end ---One big line on every screen. ---@param text string the line ---@param ms? number milliseconds (`3000`; `100` .. `60000`) ---@param style? number `GAMETEXT_CENTRE`, `GAMETEXT_TOP` or `GAMETEXT_LOWER` function GameTextForAll(text, ms, style) end ---A line of text at a screen position, shown to the players you choose. --- ---`x` and `y` are fractions of the screen from the top left - `0.5, 0.02` is the top centre, `0.99, 0.02` the top right with ---`HUD_ALIGN_RIGHT`, `0.02, 0.5` the left edge halfway down - so the line lands in the same place at every resolution. The ---element is shown to **nobody** until `ShowHudText` or `ShowHudTextForAll`; a change to its text or look is re-sent to ---everyone it is shown to. A shown element survives its player's respawns and goes with their disconnect; the mode's ---elements go with a reload. Ids start at `1`; there are 4096. ---@param x number `0` .. `1` of the screen width from the left ---@param y number `0` .. `1` of the screen height from the top ---@param text string the line ---@param colour? number `0xRRGGBBAA` (white) ---@param scale? number `1` = the HUD's own text size; `0.5` .. `5` ---@param align? number `HUD_ALIGN_LEFT` (the default), `HUD_ALIGN_CENTRE` or `HUD_ALIGN_RIGHT` - which side of the line sits at `x` ---@return number the element's id; `nil` when the ids are used up function CreateHudText(x, y, text, colour, scale, align) end ---Removes a HUD text from every screen. ---@param id number the element ---@return boolean `false` when there is no such element function DestroyHudText(id) end ---Changes a HUD text's text. --- ---Re-sent to everyone the element is shown to. A change every second is fine; every tick is not. ---@param id number the element ---@param text string the new line ---@return boolean `false` when there is no such element function SetHudText(id, text) end ---A HUD text's current text. ---@param id number the element ---@return string `""` when there is no such element function GetHudText(id) end ---Moves a HUD text. ---@param id number the element ---@param x number `0` .. `1` of the width ---@param y number `0` .. `1` of the height ---@return boolean function SetHudTextPos(id, x, y) end ---Recolours a HUD text. ---@param id number the element ---@param colour number `0xRRGGBBAA` ---@return boolean function SetHudTextColour(id, colour) end ---Resizes a HUD text. ---@param id number the element ---@param scale number `1` = the HUD's own size; `0.5` .. `5` ---@return boolean function SetHudTextScale(id, scale) end ---Changes which side of a HUD text sits at its x. ---@param id number the element ---@param align number `HUD_ALIGN_LEFT`, `HUD_ALIGN_CENTRE` or `HUD_ALIGN_RIGHT` ---@return boolean function SetHudTextAlign(id, align) end ---Shows a HUD text on one player's screen. --- ---Usually called from `OnPlayerSpawn` so a late joiner gets the mode's elements too - `ShowHudTextForAll` only reaches ---the players connected at the time. ---@param id number the element ---@param pid number the player ---@return boolean `false` when the element or the player does not exist function ShowHudText(id, pid) end ---Takes a HUD text off one player's screen. ---@param id number the element ---@param pid number the player ---@return boolean function HideHudText(id, pid) end ---Shows a HUD text to everyone connected now. ---@param id number the element ---@return boolean function ShowHudTextForAll(id) end ---Takes a HUD text off every screen (the element stays for later). ---@param id number the element ---@return boolean function HideHudTextForAll(id) end ---Whether a HUD text is on a player's screen. ---@param id number the element ---@param pid number the player ---@return boolean function IsHudTextShown(id, pid) end ---Every HUD text the mode has made. ---@return table a list of element ids function GetHudTexts() end -- ======== Effects and sounds ==================================================== -- One-shot things at a point in the world for everyone nearby: a **particle effect** of the game's own libraries (smoke, fire, -- sparks), a **decal** on the ground or a wall, a **sound** from the game's audio triggers. They reach the players within -- `[effects] range` metres (150; `0` = everyone in that virtual world) and are fire-and-forget - a player who arrives later sees -- and hears nothing. Each returns how many players got it. A name the game does not know is not an error on the server: it only -- warns in the clients' logs. ---Plays one of the game's particle effects at a point for everyone nearby. --- ---`name` is a particle effect of the game's libraries by its full name - `WH_Particels.smokes.smithery`, ---`professions.blacksmith.forge_fire`, `cinematics.fires.fire_big_a` ... (the particle effects list ---all 2,600). `scale` `1` plays it as authored. `dir` is the effect's ---**up** - `{x, y, z}` or three numbers; straight up (`0, 0, 1`) without it. A looping effect plays until the player's level ---unloads. `world` is the virtual world (`0`, the shared one, without it). ---@param name string the particle effect's full name ---@param x number metres ---@param y number metres ---@param z number metres ---@param scale? number `1` = as authored ---@param dir? table|number the effect's up as `{x=, y=, z=}` (or three numbers `dx, dy, dz` in its place); straight up without ---@param world? number the virtual world (`0`) ---@return number how many players got it; `0` for an empty name or nobody in range function SpawnEffect(name, x, y, z, scale, dir, world) end ---Puts a decal of a material on whatever is at a point. --- ---A mark on the ground under a spawn, a stain on a wall: `material` is one of the game's decal materials ---(the decal materials: `Materials/decals/decal_blood_a`, `decal_burned_ash`, `chalk_cross` ...), `size` metres across, ---`seconds` how long it stays (`0` = the engine's own default). `normal` is which way the decal faces - `{x, y, z}` or three ---numbers; a floor (`0, 0, 1`) without it. The same reach and return as `SpawnEffect`. ---@param material string the decal material ---@param x number metres ---@param y number metres ---@param z number metres ---@param size? number metres across (`1`) ---@param seconds? number how long it stays; `0` = the engine's default ---@param normal? table|number which way it faces as `{x=, y=, z=}` (or three numbers `nx, ny, nz`); a floor without ---@param world? number the virtual world (`0`) ---@return number how many players got it function SpawnDecal(material, x, y, z, size, seconds, normal, world) end ---Plays one of the game's sounds at a point for everyone nearby. --- ---`trigger` is an audio trigger of the game's sound banks by name - `lightning`, `c_neck_snap`, `male_spit`, ---`special_barber_scissors` ... (the audio triggers list all 15,000) - played the game's own way from a short-lived emitter at the point: ---each player hears it from where it is. The emitter stays `seconds` (`0` = 10); a looping trigger ends with it. The same ---reach and return as `SpawnEffect`. ---@param trigger string the audio trigger's name ---@param x number metres ---@param y number metres ---@param z number metres ---@param seconds? number how long the sound source stays; `0` = 10 ---@param world? number the virtual world (`0`) ---@return number how many players heard it function PlaySound(trigger, x, y, z, seconds, world) end -- ======== Script events ========================================================= -- A mode that needs something on the client the server cannot draw - a marker in the world, a sound, a bit of UI, a value read -- from the game - keeps a client script in the `client/` folder next to itself (the server sends it -- to every player who joins) and talks to it through **named events with a string payload**, both ways: `SendClientEvent` -- down, `KcdMp.send_event` up into `OnClientEvent`. The payload is whatever string the two halves agree on - a number, a -- comma list, JSON. For values every client should simply *know* - a team, a round, a flag carrier - the -- state bags are the better fit. The `marker` example mode in the server folder is the round trip whole. ---**Called by the server** - A player's client script sent an event. --- ---The client's `KcdMp.send_event(name, payload)` lands here. `payload` is whatever string the client sent - trust it no ---further than any other input from a player (parse defensively, check the pid may do what it asks). At most 30 events a ---second and 4 KB each per client; more is dropped. ---@param pid number whose client sent it ---@param name string the event's name ---@param payload string the string the client sent; `""` when none function OnClientEvent(pid, name, payload) end ---A named event with a string payload to one player's client script. --- ---The client script's `KcdMp.on_event(name, fn)` handler for `name` receives it (or its `KcdMp.on_any_event`); a client ---without a script, or without a handler for the name, ignores it. `payload` is a string - format it however the two halves ---agree. Nothing is queued for a client that has not loaded the level yet. ---@param pid number the player ---@param name string the event's name ---@param payload? string the string to send (`""` without) ---@return boolean `false` when not connected function SendClientEvent(pid, name, payload) end ---The same event to every connected client. ---@param name string the event's name ---@param payload? string the string to send (`""` without) function SendClientEventToAll(name, payload) end -- ======== State bags ============================================================ -- String keys and values the mode sets on the **world**, a **player** or an **entity**, and **every client's script reads** - -- `KcdMp.state.global[key]`, `KcdMp.state.player[pid][key]`, `KcdMp.state.entity[id][key]`, with a change hook on each -- (the client API). The way a mode's client half learns a team, a round, a marker, a flag carrier -- without a script event per client: the global and the players' bags reach every client from its join on, an entity's follows -- its spawn to whoever sees it. Numbers and booleans become strings; `nil` removes a key. Nothing is persisted - a player's bag -- goes with the session, an entity's with the entity, all of them with a reload. Limits: a key of 1-48 characters, a value of at -- most 1 KB, 64 keys a bag (a set beyond them returns `false` and logs). The mode's *private* storage is -- `SetPlayerData` / `SetEntityData`. ---Sets a key of the world's bag, read by every client. ---@param key string 1-48 characters ---@param value string|number|boolean|nil kept as a string; `nil` removes the key ---@return boolean `false` when the key or the value is out of bounds or the bag is full function SetGlobalState(key, value) end ---A key of the world's bag. ---@param key string the key ---@return string|nil function GetGlobalState(key) end ---The whole world bag. ---@return table `{key = value, ...}` function GetGlobalStates() end ---Sets a key of a player's bag, read by every client. --- ---Every client has every player's bag from its join on - `KcdMp.state.player[pid][key]`; the client's own pid is ---`KcdMp.player_id`. Gone with the player's session. ---@param pid number the player ---@param key string 1-48 characters ---@param value string|number|boolean|nil kept as a string; `nil` removes the key ---@return boolean `false` when not connected or out of bounds function SetPlayerState(pid, key, value) end ---A key of a player's bag. ---@param pid number the player ---@param key string the key ---@return string|nil function GetPlayerState(pid, key) end ---A player's whole bag. ---@param pid number the player ---@return table `{key = value, ...}` function GetPlayerStates(pid) end ---Sets a key of an entity's bag, read by every client that sees the entity. --- ---The bag travels with the entity's spawn to whoever comes into range and is dropped when it leaves their view - ---`KcdMp.state.entity[id][key]` while the entity is in view. Gone with the entity. An NPC actor's pose rides in its bag ---under the key `anim` (`SetActorAnim`). ---@param id number the entity ---@param key string 1-48 characters ---@param value string|number|boolean|nil kept as a string; `nil` removes the key ---@return boolean `false` when there is no such entity or out of bounds function SetEntityState(id, key, value) end ---A key of an entity's bag. ---@param id number the entity ---@param key string the key ---@return string|nil function GetEntityState(id, key) end ---An entity's whole bag. ---@param id number the entity ---@return table `{key = value, ...}` function GetEntityStates(id) end -- ======== Storage and persistence =============================================== -- Three places to keep a value, by how long it should live. **Data** (`SetPlayerData`, `SetEntityData`, `SetZoneData`) is the -- mode's private bag on a player, an entity or a zone - any Lua value, gone with the player's session, the entity or a reload; -- nothing leaves the server. **Saved data** is written to the player's **record** under their name (`[persistence] file`, -- `data/players.json`) and is there on their next visit, next to the visits, the play time and the last position the server keeps -- by itself. **Server data** is one key/value store for the mode, persisted in `data/server.json`. What every *client* should read -- is the state bags instead. ---Stores a value on the player, private to the server, for the session. --- ---Any Lua value - a string, a number, a boolean, a table. Cleared when the player disconnects and on a reload. Never ---replicated: for a value the clients read use `SetPlayerState`; for one that should survive the visit, `SetSavedData`. ---@param pid number the player ---@param key string the key ---@param value any the value; `nil` removes the key ---@return boolean `false` when not connected function SetPlayerData(pid, key, value) end ---A value stored on the player with SetPlayerData. ---@param pid number the player ---@param key string the key ---@return any the value; `nil` when unset or not connected function GetPlayerData(pid, key) end ---Stores a value on a world entity, private to the server. --- ---Any Lua value; gone with the entity and on a reload. For a value the clients read use `SetEntityState`. ---@param id number the entity ---@param key string the key ---@param value any the value; `nil` removes the key ---@return boolean `false` when there is no such entity function SetEntityData(id, key, value) end ---A value stored on an entity with SetEntityData. ---@param id number the entity ---@param key string the key ---@return any the value; `nil` when unset or no such entity function GetEntityData(id, key) end ---What the server remembers about the player's name between visits. --- ---The record the server keeps by itself: how many visits, the seconds played, and the last position - refreshed on the ---disconnect and every minute (`x`, `y`, `z`, `yaw` are absent until the first visit ended). `nil` when the name has no ---record yet. A **registered** name's record is written for its owner only: a guest who typed the name reads nothing and ---leaves no trace. Persistence is `[persistence] file` in `server.toml`; names are case-insensitive. ---@param pid number the player ---@return table `{visits=, playTime=, x=, y=, z=, yaw=}` (the position absent on a first visit); `nil` without a record function GetSavedPlayer(pid) end ---A value the mode saved on the player's name. ---@param pid number the player ---@param key string the key ---@return string|nil function GetSavedData(pid, key) end ---Saves a value on the player's name - it is there on their next visit. --- ---Strings (a number is converted); `nil` removes the key. Written into the player's record with the visits and the position; ---for a registered name, only when its owner is logged in. ---@param pid number the player ---@param key string the key ---@param value string|nil the value; `nil` removes the key ---@return boolean `false` when not connected function SetSavedData(pid, key, value) end ---A value of the server-wide store. ---@param key string the key ---@return string|nil function GetServerData(key) end ---Saves a value in the server-wide store (data/server.json). --- ---One key/value store for the mode, persisted beside the player records; strings, `nil` removes the key. A record for the ---whole server: rounds played, a leaderboard, the last map rotation. ---@param key string the key ---@param value string|nil the value; `nil` removes the key function SetServerData(key, value) end -- ======== World entities ======================================================== -- A **world entity** is something the server owns and every client in range sees: a horse (`ENTITY_HORSE`), a pickup -- (`ENTITY_ITEM`), an NPC actor (`ENTITY_NPC`), a prop (`ENTITY_PROP`), a dog (`ENTITY_DOG`) - the kinds. -- Its `id` is unique while it lives and `nil` from every reader once it is gone. A horse is simulated by its **controller** - the -- client of the player who rides or minds it - and carries at most one **rider**; a loose horse is handed to the nearest player -- within 30 m once a second. Entities live within a virtual world. These are the calls every kind -- shares; horses, pickups, props, dogs and actors have their own. ---Every entity in the world, or every entity of one kind. ---@param kind? number `ENTITY_HORSE`, `ENTITY_ITEM`, `ENTITY_NPC`, `ENTITY_PROP` or `ENTITY_DOG`; without it, every kind ---@return table a list of entity ids function GetEntities(kind) end ---An entity's position and heading. ---@param id number the entity ---@return number x `x, y, z, yaw` in metres and degrees; `nil` when there is no such entity ---@return number y ---@return number z ---@return number yaw function GetEntityPos(id) end ---Moves an entity. --- ---Its controller, if any, puts the real thing there; a static prop or a loose horse is moved outright on every screen. ---Without `yaw` it keeps its heading. ---@param id number the entity ---@param x number metres ---@param y number metres ---@param z number metres ---@param yaw? number degrees ---@return boolean `false` when there is no such entity function SetEntityPos(id, x, y, z, yaw) end ---What an entity is. ---@param id number the entity ---@return number `ENTITY_HORSE`, `ENTITY_ITEM`, `ENTITY_NPC`, `ENTITY_PROP` or `ENTITY_DOG`; `nil` when there is no such entity function GetEntityKind(id) end ---What an entity is made of - the item class, the soul, the mesh path. --- ---A pickup: its item class GUID (`GetItemName` names it). A horse or a dog: the soul GUID (`GetSoulInfo`). A prop: the ---mesh path. An actor: its soul GUID. ---@param id number the entity ---@return string `""` when there is no such entity function GetEntityTemplate(id) end ---An NPC actor's label; empty for everything else. ---@param id number the entity ---@return string the name over the actor's head; `""` for other kinds or no such entity function GetEntityName(id) end ---Removes an entity from the world, for everyone. --- ---A horse under a rider dismounts them; a pickup vanishes; an actor's corpse is gone; a dog leaves. Anything a mode created ---is also removed by a reload. ---@param id number the entity ---@return boolean `false` when there is no such entity function DestroyEntity(id) end ---The player whose client simulates the entity. --- ---A horse's controller is the player who rides or minds it; a dog's is its master for life; a pickup, a prop and an actor have ---none (the server itself moves an actor). ---@param id number the entity ---@return number a pid; `nil` when nobody controls it function GetEntityController(id) end ---Hands the simulation of an entity to a player, or to nobody. --- ---The way a horse changes hands: the new controller's client spawns and drives the real thing, the others see a puppet. ---`nil` gives it to nobody - it stands still until the minder hands it to the nearest player. Refused while someone else ---rides it. ---@param id number the entity ---@param pid number|nil the new controller; `nil` = nobody ---@return boolean `false` when refused function SetEntityController(id, pid) end ---The player in the saddle of a horse. ---@param id number the entity ---@return number a pid; `nil` when nobody rides it (or it is not a horse) function GetEntityRider(id) end ---Seconds since the entity's pose was last reported. --- ---A controlled horse reports its pose all the time, so its idle time stays near zero; a loose one counts up from the moment ---it was left. Since the creation for anything that never reported. ---@param id number the entity ---@return number seconds function GetEntityIdleTime(id) end ---The virtual world the entity is replicated in. ---@param id number the entity ---@return number the world, `0` = the shared one; `nil` when there is no such entity function GetEntityVirtualWorld(id) end ---Moves an entity into another virtual world. --- ---Only the players of that world see it from the next snapshot on. A ridden horse is refused - it is where its rider is. ---@param id number the entity ---@param world number the world; `0` = the shared one ---@return boolean `false` when refused or no such entity function SetEntityVirtualWorld(id, world) end ---The entity nearest to a player, of a kind, within a radius. --- ---Horizontal distance, in the player's own virtual world only. ---@param pid number the player ---@param kind number|nil an entity kind; `nil` = any ---@param radius? number metres; without it, any distance ---@return number the entity `id` and its `distance` in metres; `nil` when none ---@return number function GetNearestEntity(pid, kind, radius) end -- ======== Horses ================================================================ -- A horse is a world entity of `ENTITY_HORSE` simulated by its **controller** - the client of the player who rides or minds it; -- the others see a puppet following its pose. Its **soul** is the breed, a key of the Horse archetype of -- the souls. Players get a horse with the `/horse` built-in (an admin command by default); a mode gives one -- with `CreateHorse` and puts a player in the saddle with `MountPlayer`. A mounted player's position and velocity are the -- horse's. ---**Called by the server** - The player is in the saddle of a horse. ---@param pid number the player ---@param id number the horse function OnPlayerMount(pid, id) end ---**Called by the server** - The player got off the horse - or left while riding, or the horse was destroyed. ---@param pid number the player ---@param id number the horse function OnPlayerDismount(pid, id) end ---Puts a horse in the world. --- ---`controllerPid` is the player whose client simulates it (usually the one it is for); with `nil` nobody does and it stands ---still until the server hands it to the nearest player within 30 m. `world` is the virtual world (`nil` = the controller's; ---`0` without one). `soul` is the breed - a Horse-archetype soul by name (`Horse2`, `Pebbles`), id or GUID from ---the horse souls; `nil` = the server's `[spawn] horse_soul`; a key that is not a horse makes no horse. ---`nil` when the world is full (`[world] max_entities`). ---@param x number metres ---@param y number metres ---@param z number metres ---@param yaw number degrees (`0` without) ---@param controllerPid? number the player whose client simulates it; `nil` = nobody yet ---@param world? number the virtual world; `nil` = the controller's ---@param soul? string|number the breed - a horse soul's name, id or GUID; `nil` = the server default ---@return number the horse's entity id; `nil` when it could not be made function CreateHorse(x, y, z, yaw, controllerPid, world, soul) end ---Puts a player in the saddle of a horse. --- ---Control goes to the player and their client mounts the horse - it may be anywhere; the game walks or teleports the player ---onto it. `false` when it is not a horse, someone else rides it, or the player is not in the world. ---@param pid number the player ---@param id number the horse ---@return boolean function MountPlayer(pid, id) end ---The horse the player rides right now. ---@param pid number the player ---@return number the horse's entity id; `nil` on foot function GetPlayerMount(pid) end ---The horse the player rides, or else the newest one they control. ---@param pid number the player ---@return number a horse's entity id; `nil` when they have none function GetPlayerHorse(pid) end -- ======== Props ================================================================= -- A **prop** is a static mesh of the game's object files placed in the world for everyone in range to see - a barrel, a fence, a -- table, a stone - like a pickup nobody can take. The mesh is a key of the mesh list: the id, the file's -- name (`barrel_a`, when only one file carries it) or the path. A static prop stands where it is placed and blocks the way; a -- **rigid** one is a physics body on each client - pushable, but its motion is not synchronised, so a barrel one player kicks stays -- put for the others. The `/prop` and `/props` built-ins place and search them. ---Places a static mesh in the world. --- ---An entity of `ENTITY_PROP` every client in range shows. `mesh` is a key of the mesh list; without the ---tables export only a path passes. `scale` is uniform (`1` = the mesh's own size); `rigid` makes it a physics body on each ---client (false = static); `world` is the virtual world (`nil` = the shared one). Nobody controls a prop, nobody mounts or ---takes it; `DestroyEntity` removes it, a reload removes them all. `nil` when the mesh resolves to nothing or the world is ---full. ---@param mesh string|number the mesh's id, file name or path ---@param x number metres ---@param y number metres ---@param z number metres ---@param yaw? number degrees (`0` without) ---@param scale? number uniform scale (`1`) ---@param rigid? boolean `true` = a pushable physics body on each client; `false` = static ---@param world? number the virtual world; `nil` = the shared one ---@return number the prop's entity id; `nil` when it could not be made function CreateProp(mesh, x, y, z, yaw, scale, rigid, world) end ---The path a mesh key stands for. ---@param key string|number the mesh's id, file name or path ---@return string the path (`objects/manmade/.../barrel_a.cgf`); `nil` when the key resolves to nothing or to several files function GetMeshPath(key) end ---Meshes whose path holds every word of a pattern. ---@param pattern string words to look for in the path, case-insensitive ---@param max? number at most this many (`10`) ---@return table a list of `{id=, path=, name=}` function FindMeshes(pattern, max) end ---A prop's scale. ---@param id number the entity ---@return number the uniform scale; `1` for anything but a prop function GetEntityScale(id) end ---Whether a prop is a physics body. ---@param id number the entity ---@return boolean `true` for a rigid prop function IsEntityRigid(id) end -- ======== Dogs ================================================================== -- A player's **dog**: a world entity of `ENTITY_DOG` whose controller is its master for life. On the master's screen it is the -- game's own companion - it follows, waits or roams on the game's dog AI, it can be praised - and everyone in range sees the same -- dog following them. One dog per player; it goes with the master's disconnect or `DestroyEntity`. The `/dog` built-in gives -- the caller one (and sends it away on the second call); `/dog stay`, `/dog follow` and `/dog free` set its mode. -- -- The mode is the dog's state bag key `mode` (`GetEntityState`), a number of the game's own list: `DOG_STAY` 0, `DOG_FOLLOW` 1 -- (the default), `DOG_FREE` 2, `DOG_AGGRESSIVE` 3, `DOG_SEARCH` 4, `DOG_HUNT` 5, `DOG_GUARD` 6, `DOG_AMBUSH` 7. Stay, follow and -- free are the tested ones. ---Gives a player a dog that follows them. --- ---`soul` names the look - a soul of the Dog archetype from the dog souls by name, id or GUID; `nil` = the ---plain dog. `x, y, z, yaw` is where it appears; without them, two metres in front of the master. A player who already has a ---dog gets the one they have. `nil` when the player is not in the world or the world is full. ---@param pid number the master ---@param soul? string|number a dog soul's name, id or GUID; `nil` = the plain dog ---@param x? number metres; without a point the dog appears in front of the master ---@param y? number metres ---@param z? number metres ---@param yaw? number degrees ---@return number the dog's entity id; `nil` when it could not be made function CreateDog(pid, soul, x, y, z, yaw) end ---The player's dog. ---@param pid number the player ---@return number the dog's entity id; `nil` when they have none function GetPlayerDog(pid) end ---Tells a dog to stay, follow or roam. --- ---`mode` is one of the game's dog modes - `DOG_STAY` (0), `DOG_FOLLOW` (1, what a new dog does), `DOG_FREE` (2) and the ---others of the list above. It is kept on the dog's state bag as `mode`, so it survives the master walking out of range and ---back, and `GetEntityState``(dog, "mode")` reads the same number. False for an id that is not a dog or a mode outside 0-7. ---The `/dog stay|follow|free` built-in does exactly this. ---@param id number the dog's entity id ---@param mode number `DOG_STAY`, `DOG_FOLLOW`, `DOG_FREE`, ... (0-7) ---@return boolean true when the mode was set function SetDogMode(id, mode) end ---A dog's mode. ---@param id number the dog's entity id ---@return number the mode (`DOG_FOLLOW` for a dog nobody told otherwise); `false` when the id is not a dog function GetDogMode(id) end -- ======== NPC actors ============================================================ -- An **NPC actor** is a dressed, named human body the server owns outright - a guard, a merchant, an arena opponent, a crowd - -- without the game's own AI. The mode creates it, walks it in straight lines, poses it and sets it on a player; it takes hits, -- dies and fights back. Its `id` is a world entity of `ENTITY_NPC`: `GetEntityPos`, `GetEntityName`, `SetEntityState` and -- `DestroyEntity` work on it. Its look is a soul of the souls, its clothes and arms are -- clothing and weapon presets, its poses are clips of -- the animation list. It fights like a player: an armed actor raises its guard against a swing part -- of the time (`[actors] block_chance`, `block_hold`), a heavy blow wounds the part it hits, a cut bleeds, a bleed-out kills it. -- `[actors]` in `server.toml` tunes how it fights. Not yet: paths around obstacles (a straight line through a wall stops at the -- wall), riding. ---**Called by the server** - An actor reached its MoveActor target. --- ---It stands there until the next `MoveActor`. Chain the legs of a route here. ---@param id number the actor function OnActorArrive(id) end ---**Called by the server** - A player hit an actor - change the damage, cancel it, or let it through. --- ---The same shape and the same return rules as `OnPlayerDamage`: a number replaces the damage (`0` cancels), `false` ---cancels, nothing keeps it. The hit went through the same model as a hit on a player, without armour on the actor. --- ---Return value: a number replaces the damage (`0` cancels); `false` cancels the hit; nothing keeps it ---@param id number the actor ---@param attacker number the player who struck ---@param damage number what the actor is about to lose ---@param zone number the attack zone the attacker's game recorded ---@param part number the body part struck, `1` .. `6`; `0` unknown ---@param weapon string the weapon's table name; `""` bare-handed ---@param dtype string `"stab"`, `"slash"`, `"smash"` or `""` function OnActorDamage(id, attacker, damage, zone, part, weapon, dtype) end ---**Called by the server** - A hit wounded one of an actor's body parts. --- ---The shape of `OnPlayerInjury`: a blow of at least `[combat] injury_threshold` injures the part it struck; every client ---shows the limp. A cut bleeds for `[combat] bleed_seconds` (`GetActorBleeding`) and drains the health - a bleed-out is the ---last attacker's kill. `HealActor` makes the actor whole. ---@param id number the actor ---@param attacker number the player who struck; `-1` = nobody ---@param part number the body part, `1` .. `6` function OnActorInjury(id, attacker, part) end ---**Called by the server** - An actor's health reached 0. --- ---`attacker` is the player who killed it - by a blow or by the bleed they opened - or `-1` for `SetActorHealth(id, 0)`. The ---corpse stays until `DestroyEntity` - an actor has no respawn of its own; a mode creates a new one. ---@param id number the actor ---@param attacker number the killer; `-1` = nobody function OnActorDeath(id, attacker) end ---**Called by the server** - An actor's blow landed on its opponent - change the damage, cancel it, or let it through. --- ---The same shape and return rules as `OnPlayerDamage`. The blow is priced by the victim's own game - the actor's weapon ---through their armour - times `[actors] attack_scale`, at most `[actors] max_damage`. A mode **without** this callback hears ---the blow as `OnPlayerDamage(pid, -1, ...)`. --- ---Return value: a number replaces the damage (`0` cancels); `false` cancels the blow; nothing keeps it ---@param id number the actor ---@param pid number the player struck ---@param damage number what the player is about to lose ---@param zone number the attack zone ---@param part number the body part struck, `1` .. `6`; `0` unknown ---@param weapon string the actor's weapon by its table name; `""` bare-handed ---@param dtype string `"stab"`, `"slash"`, `"smash"` or `""` function OnActorAttack(id, pid, damage, zone, part, weapon, dtype) end ---Creates an NPC actor - a dressed, named body the server owns. --- ---`soul` is the face and build: a soul of any archetype from the souls by name, id or GUID (`nil` = the ---server's appearance pool for the name, like a player without a `SetSpawnInfo` face). `name` is the label over its head (`nil` ---= none). `clothing` and `weapons` are preset GUIDs (clothing, ---weapons; `nil` = the server's `[spawn]` presets, like a player; `weapons = "none"` makes an ---unarmed one that fights with its fists). `world` is the virtual world (`nil` = the shared one). The actor stands where it is ---put until `MoveActor`; its health is 100. `nil` when the soul is unknown or the world is full. ---@param soul string|number|nil a soul's name, id or GUID; `nil` = the server's pool ---@param x number metres ---@param y number metres ---@param z number metres ---@param yaw number degrees (`0` without) ---@param name? string the label over its head; `nil` = none ---@param clothing? string a clothing preset GUID; `nil` = the server default ---@param weapons? string a weapon preset GUID; `nil` = the server default; `"none"` = unarmed ---@param world? number the virtual world; `nil` = the shared one ---@return number the actor's entity id; `nil` when it could not be made function CreateActor(soul, x, y, z, yaw, name, clothing, weapons, world) end ---Walks an actor to a point - around the walls when the server has the navigation mesh. --- ---At `speed` metres per second, facing its way - about 1.5 walks, 4 runs, 6.5 sprints (the body's clips follow the speed). ---`OnActorArrive` fires when it gets there. A new target replaces the old one; a pose (`SetActorAnim`) is cleared. With ---the level's navigation mesh (`HasNavmesh`, the navigation guide) the actor takes the walk the game's own ---people would - corner by corner, around walls and through doorways; a target off the mesh (in a wall, on a roof) or a ---server without the mesh gets the straight line, where the body stops at a wall and catches up when the line comes out. ---@param id number the actor ---@param x number metres ---@param y number metres ---@param z number metres ---@param speed? number metres per second (`1.5`) ---@return boolean `false` for anything but a living actor function MoveActor(id, x, y, z, speed) end ---Stops an actor where it is. --- ---No `OnActorArrive`. Also ends a chase started by `SetActorHostile` only as far as the walk goes - the fight of record stays ---until its timeout. ---@param id number the actor ---@return boolean `false` for anything but an actor function StopActor(id) end ---Turns a standing actor to face a direction. ---@param id number the actor ---@param yaw number degrees; `0` = facing +Y, counter-clockwise ---@return boolean `false` for anything but an actor function TurnActor(id, yaw) end ---Whether an actor is on its way to a MoveActor target. ---@param id number the actor ---@return boolean `false` once arrived or stopped function IsActorMoving(id) end ---Puts a pose on a standing actor - a clip of the game's animation set. --- ---`clip` is a clip name of the male animation set (`behavior_sitting_variation01_loop`, ---`greetings_wave_big_over`, `woodchopping_loop_01` ...) or one of the aliases the API names: `sit`, `wave`, `bow`, `nod`, ---`pray`, `chop`, `sweep`, `smith` (`ACTOR_ANIM` in Constants). `loop` `true` (the default) plays it ---until cleared; `false` plays it once. `nil` clears the pose; so do `MoveActor` and a death. The pose rides in the actor's ---state bag (key `anim`), so a player who arrives later finds the guard sitting. A chore without its prop mimes - a smith ---without an anvil. ---@param id number the actor ---@param clip string|nil a clip name or an alias; `nil` clears the pose ---@param loop? boolean `true` (the default) loops; `false` plays once ---@return boolean `false` for anything but a living actor function SetActorAnim(id, clip, loop) end ---An actor's health. ---@param id number the actor ---@return number `0` .. `100`; `0` for anything but an actor function GetActorHealth(id) end ---Sets an actor's health; 0 kills it. --- ---Clamped to `0` .. `100`; `0` kills it now (`OnActorDeath` with attacker `-1`). Refused on a dead actor - a corpse stays a ---corpse; `DestroyEntity` and `CreateActor` again. ---@param id number the actor ---@param health number the new health ---@return boolean `false` for a dead actor or anything but an actor function SetActorHealth(id, health) end ---Whether an actor is a corpse. ---@param id number the actor ---@return boolean function IsActorDead(id) end ---Makes an actor whole - full health, no wounds, no bleeding. --- ---Every client shows the body straighten. Refused on a corpse. ---@param id number the actor ---@return boolean `false` for a dead actor or anything but an actor function HealActor(id) end ---An actor's wounded body parts. --- ---A list of body parts, `BODY_PART_HEAD` .. `BODY_PART_LEG_RIGHT` (`1` .. `6`); `{}` when whole. A blow of at least ---`[combat] injury_threshold` wounds the part it struck (`OnActorInjury`). ---@param id number the actor ---@return table a list of body part ids function GetActorInjuries(id) end ---Whether an actor has a wound - anywhere, or on one part. ---@param id number the actor ---@param part? number a body part `1` .. `6`; without it, any part ---@return boolean function IsActorInjured(id, part) end ---How fast an actor is bleeding, in health per second. --- ---A cut opens a bleed for `[combat] bleed_seconds`; `0` = not bleeding. A bleed-out is the last attacker's kill ---(`OnActorDeath`); `HealActor` stops it. ---@param id number the actor ---@return number health lost per second; `0` = not bleeding function GetActorBleeding(id) end ---Whether an actor is bleeding. ---@param id number the actor ---@return boolean function IsActorBleeding(id) end ---Sets an actor on a player - or stands it down. --- ---`true` makes the player the actor's opponent: their game may lock on to the actor's body, and the actor faces them, walks ---after them (`[actors] chase_speed`, up to `chase_range`) and swings every `[actors] swing_interval` seconds within ---`[actors] reach`, with the weapon of its preset or its fists; a blow that lands comes to the mode as `OnActorAttack`. A ---player's blow on the actor does the same by itself when `[actors] fight_back` is on. `false` stands it down - so do the ---opponent's death or leaving, another world, `chase_range`, `MoveActor` and the actor's own death. ---@param pid number the player ---@param id number the actor ---@param hostile boolean `true` = the actor fights the player; `false` = peace ---@return boolean `false` for anything but a living actor or a player not in the world function SetActorHostile(pid, id, hostile) end -- ======== Zones ================================================================= -- A **zone** is a region the server watches for the mode: a box between two corners, or a circle around a point with any height -- unless a `zMin`/`zMax` band is given. Once per tick every player in the world is tested against every zone and the mode hears -- `OnPlayerEnterZone` and `OnPlayerLeaveZone` on the edges. Ids start at `1` and are reused after a destroy; there are 4096. -- A zone has a private data bag (`SetZoneData`). Zones go with a reload. ---**Called by the server** - A player's position of record entered a zone. ---@param pid number the player ---@param zone number the zone function OnPlayerEnterZone(pid, zone) end ---**Called by the server** - A player left a zone - walked or was moved out, despawned, respawned elsewhere, disconnected. ---@param pid number the player ---@param zone number the zone function OnPlayerLeaveZone(pid, zone) end ---A box zone between two corners. --- ---The corners may be given in any order. `nil` when the 4096 ids are used up. ---@param x1 number one corner, metres ---@param y1 number metres ---@param z1 number metres ---@param x2 number the opposite corner ---@param y2 number metres ---@param z2 number metres ---@return number the zone's id; `nil` when none is free function CreateZone(x1, y1, z1, x2, y2, z2) end ---A circular zone around a point - a cylinder of any height, or of a band. --- ---Without `zMin` and `zMax` the height does not matter; with `zMin < zMax` only that band counts. ---@param x number the centre, metres ---@param y number metres ---@param radius number metres ---@param zMin? number the bottom of the band ---@param zMax? number the top of the band; without a band any height counts ---@return number the zone's id; `nil` when none is free function CreateCircleZone(x, y, radius, zMin, zMax) end ---Removes a zone. --- ---Nobody hears a leave for it. Its id may be reused by the next zone. ---@param id number the zone ---@return boolean `false` when there is no such zone function DestroyZone(id) end ---Whether the player is inside a zone, as of the last tick's test. ---@param pid number the player ---@param id number the zone ---@return boolean function IsPlayerInZone(pid, id) end ---Whether a point lies inside a zone. ---@param id number the zone ---@param x number metres ---@param y number metres ---@param z? number metres (`0` without) ---@return boolean function IsPointInZone(id, x, y, z) end ---The players inside a zone right now. ---@param id number the zone ---@return table a list of pids function GetZonePlayers(id) end ---The zones a player is inside right now. ---@param pid number the player ---@return table a list of zone ids function GetPlayerZones(pid) end ---Every zone the mode has made. ---@return table a list of zone ids function GetZones() end ---A zone's shape. ---@param id number the zone ---@return table `{circle=, minX=, minY=, minZ=, maxX=, maxY=, maxZ=, x=, y=, radius=}`: `circle` true for a circle zone, the box's bounds, the circle's centre and radius (a box's centre and half its diagonal); `nil` when there is no such zone function GetZoneInfo(id) end ---Stores a value on a zone, private to the server. --- ---Any Lua value; gone with the zone. The mode's way to mark what a zone is for. ---@param id number the zone ---@param key string the key ---@param value any the value; `nil` removes the key ---@return boolean `false` when there is no such zone function SetZoneData(id, key, value) end ---A value stored on a zone with SetZoneData. ---@param id number the zone ---@param key string the key ---@return any the value; `nil` when unset or no such zone function GetZoneData(id, key) end -- ======== The world - clock, weather, terrain, the navmesh, the geometry ======== -- The server owns the **world clock** and the **weather**: every client follows them, so the whole server sees one time of day and -- one sky (`[world]` in `server.toml` sets the start). The clock is hours since midnight (`13.5` = 13:30) and runs at a ratio of -- game seconds per real second; the weather is a **preset** name or one of the level's own sky profiles -- (Weather); the rain is a lever on top. The **terrain height** comes from the level's heightmap when the server -- has one, and the **navigation mesh** - the game's own, when the operator exported it (World data) - -- answers for walks, floors and reachability: the NPC actors walk around walls on it by themselves. The **collision geometry** -- - the level's walls, roofs, floors and trees, exported from the game's own physics world - answers rays: what is in the -- way, whether two points see each other, the true floor under a point. The doors the server knows are open let a ray through. ---The world clock, in hours since midnight. ---@return number `0` .. `24`; `13.5` = 13:30 function GetWorldTime() end ---Sets the world clock for everyone. --- ---Every client's calendar follows. The game's own calendar only moves **forward**: a jump backwards is applied as a jump to ---the same time the next day. ---@param hours number hours since midnight, `0` .. `24` (`13.5` = 13:30) function SetWorldTime(hours) end ---Hours as HH:MM. ---@param hours? number hours since midnight; without it, the world clock now ---@return string `"13:30"` function FormatWorldTime(hours) end ---How fast the world clock runs - game seconds per real second. ---@return number `15` is the game's own pace, `0` frozen function GetTimeRatio() end ---Sets how fast the world clock runs. ---@param ratio number game seconds per real second; `15` = the game's own pace, `0` = frozen function SetTimeRatio(ratio) end ---The rain override. ---@return number `0` .. `1` when forced; `-1` = the level's own weather function GetRain() end ---Forces rain on every client, or hands the rain back to the weather. --- ---The rain is a lever on top of the weather profile: the profile sets the clouds, the fog, the light and its own rain ---probability; this forces the amount. `-1` lets the profile decide again. `/rain` is the built-in. ---@param intensity number `0` .. `1`; `-1` = off, the weather decides function SetRain(intensity) end ---The sky profile every client follows. ---@return string a profile name (`cloudless_sunny`, `foggy_storm` ...); `""` = each client's own function GetWeather() end ---Changes the sky for everyone - by a preset name or a level profile. --- ---A **preset** is a friendly name for one of the level's time-of-day profiles: `clear` (or `sunny`), `fair`, `cloudy`, `overcast`, ---`showers`, `drizzle` (or `fog`), `storm`, `dry_storm` (`GetWeatherPresets` maps them; Weather lists the ---profiles). A profile name passes through as it is. Each client blends the new sky in over `blendSeconds` (`[world] ---weather_blend`, 10 s, without them). `""` leaves every client's sky as it is. The `/weather` built-in is the same call. ---@param presetOrProfile string a preset or a profile name; `""` = leave the skies alone ---@param blendSeconds? number seconds the change blends in over (`[world] weather_blend`) ---@return boolean `false` for a name that is neither a preset nor a profile function SetWeather(presetOrProfile, blendSeconds) end ---The preset names and the profiles they stand for. ---@return table `{preset = profile, ...}` function GetWeatherPresets() end ---The terrain height at a point, from the level's heightmap. --- ---The server has a heightmap when `[validation] heightmap` names one the operator exported from the game; without one, or ---outside the sampled area, `nil`. Use it to place things on the ground where a `z` below `0` is not accepted. ---@param x number metres ---@param y number metres ---@return number metres; `nil` without a heightmap or outside it function GetTerrainHeight(x, y) end ---Whether the server has the level's navigation mesh. --- ---`[validation] navmesh` names the file the operator exported from their game (the navigation guide). With it ---the NPC actors walk around walls and the functions below answer; without it they answer `nil` / `false` and an actor ---walks a straight line to its target. ---@return boolean function HasNavmesh() end ---The corners of a walk between two points on the navigation mesh. --- ---The route an NPC actor would take, string-pulled to its corners: the first is the start snapped to the mesh, the last ---the end. `nil` when either point is off the mesh (more than 2 m from it sideways or 4 m up or down - a wall, a roof, the ---air), when no way joins them, or without a navmesh. Positions in metres, the level's world space. A path takes well ---under a millisecond across a village; a mode that asks every tick for every actor should not. ---@param x1 number the start ---@param y1 number ---@param z1 number ---@param x2 number the end ---@param y2 number ---@param z2 number ---@return table of `{x=, y=, z=}` corners, the start first; `nil` for no way function FindPath(x1, y1, z1, x2, y2, z2) end ---Whether a walk joins two points on the navigation mesh. --- ---The same test as `FindPath` without the corners - a spawn point that can be walked out of, a goal that can be reached. ---@param x1 number the start ---@param y1 number ---@param z1 number ---@param x2 number the end ---@param y2 number ---@param z2 number ---@return boolean `false` off the mesh, unreachable, or without a navmesh function IsReachable(x1, y1, z1, x2, y2, z2) end ---The navigation mesh's floor at a point. --- ---The height of the walkable surface under (or near) the point - a floor, a bridge, a stair - where ---`GetTerrainHeight` only knows the terrain. `nil` more than 2 m from the mesh sideways or 4 m up or down, or without ---a navmesh. ---@param x number metres ---@param y number metres ---@param z number a height near the floor asked for (the floor above or below within 4 m) ---@return number metres; `nil` off the mesh function GetNavmeshHeight(x, y, z) end ---The nearest point on the navigation mesh. --- ---Where to put a spawn, a prop or an actor so that it stands on walkable ground: the point on the mesh nearest the one ---given, within 2 m sideways and 4 m up or down; `nil` when the mesh is farther, or without a navmesh. ---@param x number metres ---@param y number metres ---@param z number metres function NearestNavmeshPoint(x, y, z) end ---Whether the server holds the level's collision geometry. --- ---`true` when the operator exported the level's geometry and `server.toml` names it (`[validation] collision`, ---the collision guide): `RayCast` answers, `IsLineOfSight` can say no, the floor under a player counts as the ---ground of the terrain check. Without it the three functions answer `nil`, `true` and `nil`. ---@return true when the geometry is loaded function HasCollision() end ---The nearest surface along a line. --- ---Shoots a ray from one point to the other through the level's static geometry and answers with the first surface it ---meets: where, which way it faces, how far along, the engine's material id of a mesh triangle (0 for the primitives), ---and - when the surface belongs to a game entity (a door, a chest, a ladder) - the entity's class and name. Players, ---actors and horses are not in the geometry; the doors the server's records say are open are let through. ---@param x1 number metres, the start ---@param y1 number metres ---@param z1 number metres ---@param x2 number metres, the end ---@param y2 number metres ---@param z2 number metres function RayCast(x1, y1, z1, x2, y2, z2) end ---Whether nothing stands between two points. --- ---`true` when a ray from the first point reaches the second without meeting the level's geometry - a wall, a roof, a ---tree, a closed door. Always `true` without the geometry. The server uses the same test on hit claims when ---`[validation] line_of_sight` is on (a blow through a wall is refused). ---@param x1 number metres ---@param y1 number metres ---@param z1 number metres ---@param x2 number metres ---@param y2 number metres ---@param z2 number metres ---@return true when the line is clear function IsLineOfSight(x1, y1, z1, x2, y2, z2) end ---The surface under a point. --- ---The height of the first surface under the point - a ray from half a metre over it, 100 m down: the paving, a bridge, a ---roof, an upper storey, wherever the level's geometry is. Where the geometry has nothing (open terrain), `nil`: ask ---`GetTerrainHeight` then. Where a spawn, a prop or a teleport should land. ---@param x number metres ---@param y number metres ---@param z number metres, the height to look down from function GetGroundZ(x, y, z) end -- ======== Doors and containers ================================================== -- The level's own **doors** and **stashes** are in sync on every client whatever the mode does: a door one player opens swings on -- every screen; a chest one player loots is emptier for the next. A door's state of record is written by whoever uses it; a -- container's contents are the server's - the first opener's own loot seeds the record, one player holds a container at a time -- ("Someone is rummaging in it." for the next), and what they leave in it is what the next opener finds. The **key** of a door or a -- container is the entity's level name - `AnimDoor[Door/door_village_left32_77d417c2-...]`, `Stash7[Stash/stash_shelf_...]` - -- listed per level in Levels. A mode needs nothing for the sync; it may veto (`OnPlayerUseDoor`, -- `OnPlayerOpenContainer`) or drive it (`SetDoorState`, `SetContainerItems`). ---**Called by the server** - A player's game opened, closed, locked or unlocked a door - return `false` to put it back. --- ---`open` and `locked` are the door's state **as it is now** on the player's client. Return `false` to refuse: the record stands, ---the player's door is put back, nobody else hears of it. Otherwise the state becomes the record and every client shows it. --- ---Return value: `false` refuses the change; anything else accepts it ---@param pid number the player ---@param key string the door's level name ---@param open boolean open now ---@param locked boolean locked now function OnPlayerUseDoor(pid, key, open, locked) end ---**Called by the server** - A player wants to open a container - return `false` to refuse. --- ---Nothing has opened yet. Return `false` and the container stays shut for them. Otherwise their client's loot window opens on ---the record's contents (`GetContainerItems`) and they hold the container until they close it. --- ---Return value: `false` refuses; anything else lets them open it ---@param pid number the player ---@param key string the container's level name function OnPlayerOpenContainer(pid, key) end ---**Called by the server** - A player closed a container; the record holds what they left in it. ---@param pid number the player ---@param key string the container's level name function OnPlayerCloseContainer(pid, key) end ---Every door anyone touched. --- ---A door nobody used is at the level's default and not listed; the level lists have every door's key. ---@return table a list of door keys function GetDoors() end ---A door's state of record. ---@param key string the door's level name ---@return boolean open two booleans `open, locked`; `nil` when nobody ever touched the door (the level's default) ---@return boolean locked function GetDoorState(key) end ---Opens, closes, locks or unlocks a door on every client. ---@param key string the door's level name ---@param open boolean open ---@param locked boolean locked function SetDoorState(key, open, locked) end ---Every container anyone opened. ---@return table a list of container keys function GetContainers() end ---A container's contents of record. --- ---One entry per stack: the item class GUID (`GetItemName` names it), how many, the item's condition in percent. `nil` when ---nobody has opened the container yet - its contents are still the level's own, unknown to the server. ---@param key string the container's level name ---@return table a list of `{class=, amount=, health=}`; `nil` when never opened function GetContainerItems(key) end ---Rewrites a container's contents; whoever has it open sees the new list. --- ---Each entry is a stack: the item **class GUID** (names are not resolved here - `GetItemClass` turns a name or an id into ---the GUID), an amount (`1`) and a condition in percent (`100`). An empty list empties the chest. Items taken from a container ---the server filled are the server's own in the inventory audit. ---@param key string the container's level name ---@param items table a list of `{class=, amount=, health=}` (`amount` and `health` optional) function SetContainerItems(key, items) end ---Who has a container open right now. ---@param key string the container's level name ---@return number a pid; `nil` when nobody function GetContainerUser(key) end -- ======== Accounts, admins, bans and the audit ================================== -- A name is open until a player claims it with `/register `; from then on whoever joins under it plays as a **guest** - -- held in a world of their own, no record, no admin flag - until `/login `, and is kicked after `[accounts] -- login_grace_seconds` without it. **Admins** are the logged-in owners of the names on `[accounts] admins`, or players the mode -- promotes for the session; the flag unlocks the server's admin-only built-in commands and whatever the -- mode gates on it. **Bans** are kept in `data/bans.json` beside the player records - a plain list an admin may edit by hand. The -- **inventory audit** (`[audit]`) compares what a player holds with what the server can explain - the spawn outfit, `GivePlayerItem`, -- pickups, takes from containers - and calls the mode before it acts on a discrepancy. ---**Called by the server** - The player proved a registered name, or just registered it. --- ---After `/login ` or `/register `. A registered name held in its own world is released into the shared one ---now; its record (`GetSavedPlayer`) is theirs; if the name is on `[accounts] admins`, `IsPlayerAdmin` is `true` from here. ---@param pid number the player function OnPlayerLogin(pid) end ---**Called by the server** - The inventory audit found items the server cannot explain - return `false` to vouch for them. --- ---The player holds `amount` of a guarded item class (`[audit] guarded_categories`: weapons, armour, ammunition) where the server's ---records explain `allowed`, in `[audit] strikes` reports in a row - or used a consumable they never held (`amount` `1`, ---`allowed` `0`). Return `false` to vouch: the records take the amount and nothing happens. Anything else and the ---`[audit] action` follows - `log` (the default; the excess is then accepted, so it is judged once), `kick` or `ban`. --- ---Return value: `false` vouches for the items; anything else lets the `[audit] action` happen ---@param pid number the player ---@param class string the item class GUID (`GetItemName` names it) ---@param amount number how many the player holds ---@param allowed number how many the server's records explain function OnPlayerAuditViolation(pid, class, amount, allowed) end ---Whether the player's name has a password on record. ---@param pid number the player ---@return boolean function IsPlayerRegistered(pid) end ---Whether the player proved their registered name this session. --- ---A guest name is never "logged in"; a registered one is after `/login` or `/register`. ---@param pid number the player ---@return boolean function IsPlayerLoggedIn(pid) end ---Whether the player is an admin. --- ---A logged-in owner of a name on `[accounts] admins`, or a player the mode promoted with `SetPlayerAdmin`. It unlocks the ---server's admin-only built-in commands and whatever the mode gates on it. ---@param pid number the player ---@return boolean function IsPlayerAdmin(pid) end ---Makes the player an admin for the session - or takes it back. --- ---The `[accounts] admins` list in `server.toml` is the persistent way; this one lasts until the disconnect or a reload (the ---listed admins keep theirs). ---@param pid number the player ---@param admin boolean `true` promotes, `false` demotes (`true` without) ---@return boolean `false` when not connected function SetPlayerAdmin(pid, admin) end ---The names on the server's admin list. ---@return table a list of names (`[accounts] admins`) function GetAdminNames() end ---Kicks the player and bans their name and address. --- ---A `Hello` under the name or from the address is refused with the reason until the ban runs out; `seconds` `0` or none = ---for good. Written to `data/bans.json`. ---@param pid number the player ---@param reason string shown to the player now and at every refused join ---@param seconds? number how long; `0` or none = for good ---@return boolean `false` when not connected function Ban(pid, reason, seconds) end ---Bans a name; whoever is on under it is kicked. ---@param name string the player name (case-insensitive) ---@param reason string the reason ---@param seconds? number how long; `0` or none = for good function BanName(name, reason, seconds) end ---Bans an address; whoever is on from it is kicked. ---@param address string `"a.b.c.d"` ---@param reason string the reason ---@param seconds? number how long; `0` or none = for good function BanAddress(address, reason, seconds) end ---Lifts every ban on a name or an address. ---@param nameOrAddress string a name or an address ---@return boolean `true` when there was one function Unban(nameOrAddress) end ---Whether a name or an address is banned right now, and why. ---@param nameOrAddress string a name or an address ---@return string the reason, e.g. `"banned: speed hacking (9,000 min left)"`; `nil` when not banned function IsBanned(nameOrAddress) end ---How many audit violations were acted on for the player this session. ---@param pid number the player ---@return number function GetPlayerAuditViolations(pid) end -- ======== Catalogues ============================================================ -- The server resolves the game's things by **id, name or GUID** through the tables export (`[combat] tables`): items -- (the item catalogue), souls (the souls), buffs (the buff -- list) and meshes (the meshes; `GetMeshPath` and `FindMeshes` are with the props). Every function -- that takes an item, a soul or a buff accepts any of the keys; these look them up, search them and turn one key into another. The -- **id** is the row number of the name-sorted export - stable for one export of one game build, so keep the name or the GUID in -- anything durable. Without the export only GUIDs pass, unchecked. ---The class GUID an item key stands for. --- ---`key` is an item's id, the game's name (`shortswordBroad`, case-insensitive), its English name (`Duelling longsword`; when ---several classes share one, the plainest answers) or a GUID (passed through). `nil` when the catalogue knows no such item. ---@param key string|number an item's id, name, English name or GUID ---@return string the class GUID; `nil` when unknown function GetItemClass(key) end ---The game's name of an item key. --- ---Turns a class GUID - what the client reports, what the callbacks carry - into the name the catalogue lists. ---@param key string|number an item's id, name, English name or GUID ---@return string the name (`shortswordBroad`); `""` when unknown function GetItemName(key) end ---The catalogue's entry for an item key. ---@param key string|number an item's id, name, English name or GUID ---@return table `{id=, name=, class=, category=, display=, weight=, price=}`: the id, the game's name, the class GUID, the category (`MeleeWeapon`, `Armor`, `Food` ...), the English name (`""` when the export had none), the weight and the price; `nil` when unknown function GetItemInfo(key) end ---Items whose name, English name or category holds every word of a pattern. ---@param pattern string words to look for, case-insensitive ---@param max? number at most this many (`10`) ---@return table a list of `{id=, name=, class=, category=, display=}` function FindItems(pattern, max) end ---The soul GUID a horse key stands for - the Horse archetype only. ---@param key string|number a soul's name (`Horse2`, `Pebbles`), id or GUID ---@return string the soul GUID; `nil` when the key is not a horse soul function GetHorseSoul(key) end ---The soul catalogue's entry for a key, of any archetype. ---@param key string|number a soul's name, id or GUID ---@return table `{id=, name=, guid=, archetype=}`; `nil` when unknown function GetSoulInfo(key) end ---Souls whose name or archetype holds every word of a pattern. --- ---`"Horse"` alone lists the breeds; `"Dog"` the dogs; a word of a name narrows it. ---@param pattern string words to look for, case-insensitive ---@param max? number at most this many (`10`) ---@return table a list of `{id=, name=, guid=, archetype=}` function FindSouls(pattern, max) end ---The GUID a buff key stands for. ---@param key string|number a buff's name (`well_rested`), id or GUID ---@return string the buff GUID; `nil` when unknown function GetBuffGuid(key) end ---The buff catalogue's entry for a key. ---@param key string|number a buff's name, id or GUID ---@return table `{id=, name=, guid=, class=, display=, duration=}`: the class is what `claimed_buffs` names, the duration the game's own in game minutes (`-1` = until removed); `nil` when unknown function GetBuffInfo(key) end ---Buffs whose name, English name or class holds every word of a pattern. ---@param pattern string words to look for, case-insensitive ---@param max? number at most this many (`10`) ---@return table a list of `{id=, name=, guid=, class=, display=}` function FindBuffs(pattern, max) end -- ======== Parties =============================================================== -- Players grouped with a leader (v38, the guide): the server keeps the group, the invitation with its -- timeout and the toast on the target's screen, the party frames every member sees (the others' name, health, stamina, wounds, -- at any distance and in any world) and the no-friendly-fire rule. **The server ships no party commands**: `/invite`, -- `/accept`, `/p` and every rule around them - who may invite, a level gate, leader-only invitations - are the mode's, written -- around these callbacks and functions (the shipped freeroam mode carries the plain ones). A party is a **number**; ids count -- up and are never reused while the server runs. A party exists with two or more members and ends when it falls to one - there -- is no party of one. One party and one pending invitation per player. `[party]` in the server's configuration holds the size -- (5), the invitation's timeout (30 s), the frames' default, what the leader's leaving does and the friendly fire. ---**Called by the server** - A player wants to invite another; return false to refuse. --- ---Fires from `InviteToParty` before the toast goes out, after the server's own checks (the target free, the party not ---full, no invitation pending). The place for the mode's rule: leader-only invitations, a level gate, a cooldown. Without ---the callback every invitation the server admits goes through. --- ---Return value: `false` refuses the invitation (`InviteToParty` returns `false, "refused"`); anything else lets it through ---@param from number the inviter ---@param target number the player invited function OnPartyInvite(from, target) end ---**Called by the server** - An invitation was answered - or ran out, or fell through. --- ---`answer` is `"accepted"` (the join follows at once), `"declined"`, `"timeout"` (`[party] invite_timeout` passed) or ---`"cancelled"` - the party filled or ended before the answer, a side disconnected, or the target joined another party. ---@param from number the inviter ---@param target number the player invited ---@param answer string `"accepted"`, `"declined"`, `"timeout"` or `"cancelled"` function OnPartyInviteResponse(from, target, answer) end ---**Called by the server** - A party came into being. --- ---The first accepted invitation (or the mode's first `AddPlayerToParty`) makes the group with the inviter leading. Fires ---before the two joins (`OnPlayerJoinParty` with `"create"` for the leader, then the newcomer's reason). ---@param party number the new party's id ---@param leader number the leader function OnPartyCreate(party, leader) end ---**Called by the server** - A player joined a party - the leader too, at the party's birth. --- ---Every member arrives through here: `reason` is `"create"` (the leader, as the party is made), `"invite"` (an accepted ---invitation) or `"mode"` (`AddPlayerToParty`). ---@param party number the party ---@param pid number the member ---@param reason string `"create"`, `"invite"` or `"mode"` function OnPlayerJoinParty(party, pid, reason) end ---**Called by the server** - A member is gone from the party. --- ---`reason` is `"left"` (`RemovePlayerFromParty`), `"kicked"` (the same with `"kicked"`), `"disconnect"`, or `"disband"` ---- the mode's `DisbandParty`, the leader's leaving under `leader_leaves = "disband"`, or the last member standing when ---the party fell to one. The member's label is gone with the membership. ---@param party number the party ---@param pid number the member who left ---@param reason string `"left"`, `"kicked"`, `"disconnect"` or `"disband"` function OnPlayerLeaveParty(party, pid, reason) end ---**Called by the server** - The lead changed hands. --- ---By the mode (`SetPartyLeader`) or by the leader leaving, when the next member in join order takes over (`previous` is ---then the one who left). ---@param party number the party ---@param pid number the new leader ---@param previous number the one before function OnPartyLeaderChange(party, pid, previous) end ---**Called by the server** - The party is over. --- ---Fires last, after every member's `OnPlayerLeaveParty`. `reason` is `"empty"` (the party fell to one member), `"mode"` ---(`DisbandParty`) or `"leader"` (the leader left and `[party] leader_leaves` is `"disband"`). A reload of the mode ---drops every party without this callback. ---@param party number the party that ended ---@param reason string `"empty"`, `"mode"` or `"leader"` function OnPartyDisband(party, reason) end ---Sends a party invitation - the mode's /invite. --- ---The server checks both players (connected, not the same, the target in no party and with no invitation pending, the ---inviter's party not full), asks `OnPartyInvite`, and puts the toast with its countdown on the target's screen - two ---keys answer it, or the mode's `AcceptPartyInvite` / `DeclinePartyInvite`. The party is made when the invitation is ---accepted, with the inviter leading, when they have none; an inviter who is already in one invites into it. The ---invitation belongs to that party: the inviter leaving it does not withdraw it; the party filling or ending, or a side ---disconnecting, does. ---@param from number the inviter ---@param target number the player to invite ---@return true , or `false, reason` - `"not connected"`, `"self"`, `"in a party"` (the target), `"full"`, `"pending"` (the target has one already) or `"refused"` (`OnPartyInvite` said no) function InviteToParty(from, target) end ---Accepts the player's pending invitation - the mode's /accept. --- ---The same road as the toast's accept key: the player joins the inviter's party (making it when there is none). `false` ---without a pending invitation. When the party filled or ended meanwhile the invitation is cancelled instead ---(`OnPartyInviteResponse` `"cancelled"`). ---@param pid number the invited player ---@return boolean `false` when nothing was pending function AcceptPartyInvite(pid) end ---Declines the player's pending invitation - the mode's /decline. ---@param pid number the invited player ---@return boolean `false` when nothing was pending function DeclinePartyInvite(pid) end ---The player's pending invitation. ---@param pid number the player function GetPlayerPartyInvite(pid) end ---Puts a player into another's party without an invitation. --- ---A queue, a raid maker, a mode that groups its players itself: `pid` joins `host`'s party, which is made first (with ---`host` leading) when there is none. The join's reason is `"mode"`. `false` when either is not connected, `pid` is in a ---party already, or the party is full. ---@param host number a member of the party (or the leader of the new one) ---@param pid number the player to add ---@return boolean function AddPlayerToParty(host, pid) end ---Takes a player out of their party - the mode's /leave and /kick. --- ---`reason` `"left"` (the default) or `"kicked"` is what `OnPlayerLeaveParty` hears. The leader leaving hands the lead ---on (or ends the party, by `[party] leader_leaves`); a party left with one member ends. ---@param pid number the member ---@param reason? string `"left"` or `"kicked"` ---@return boolean `false` when in no party function RemovePlayerFromParty(pid, reason) end ---Hands the lead to a member - the mode's /leader. ---@param party number the party ---@param pid number the member who leads from now ---@return boolean `false` when they are not a member function SetPartyLeader(party, pid) end ---Ends a party. --- ---Every member leaves with `"disband"`, then `OnPartyDisband` fires with `"mode"`. ---@param party number the party ---@return boolean `false` for an unknown party function DisbandParty(party) end ---The party the player is in. ---@param pid number the player ---@return number the party's id; `nil` in none function GetPlayerParty(pid) end ---The party's leader. ---@param party number the party ---@return number the leader's pid; `nil` for an unknown party function GetPartyLeader(party) end ---The members, in join order. ---@param party number the party ---@return table of pids in join order; `{}` for an unknown party function GetPartyMembers(party) end ---How many members the party has. ---@param party number the party ---@return number 0 for an unknown party function GetPartySize(party) end ---Whether the party is at [party] max_size. ---@param party number the party ---@return boolean function IsPartyFull(party) end ---Whether two players are in one party. --- ---For the mode's own rules - loot shared with the party, a duel refused between friends, a party chat. ---@param a number one player ---@param b number the other ---@return boolean function ArePartyMembers(a, b) end ---Every party on the server. ---@return table of party ids function GetParties() end ---The party's title, shown over the members' frames. ---@param party number the party ---@param text string the title; `""` none ---@return boolean `false` for an unknown party function SetPartyName(party, text) end ---The party's title. ---@param party number the party ---@return string `""` when none or unknown function GetPartyName(party) end ---A line under the member's name in the frames - a role, a score. --- ---Cosmetic; goes with the membership. `""` clears it. ---@param pid number the member ---@param text string the label; `""` none ---@return boolean `false` when in no party function SetPartyMemberLabel(pid, text) end ---The member's label. ---@param pid number the member ---@return string `""` when none function GetPartyMemberLabel(pid) end ---Whether this player sees the party frames. --- ---`[party] frames` is the default for everyone; a mode that draws its own frames from a client script ---(`KcdMp.party`, `KcdMp.on_party_change` on the client) hides the server's for its players. ---@param pid number the player ---@param shown boolean the frames on or off ---@return boolean `false` when not connected function ShowPartyFrames(pid, shown) end ---One chat line to every member - the mode's /p. ---@param party number the party ---@param colour number 0xRRGGBBAA ---@param text string the line ---@return boolean `false` for an unknown party function SendPartyMessage(party, colour, text) end ---The mode's private storage on a party. --- ---A key and any value the mode keeps with the party; gone with it. `nil` removes the key. ---@param party number the party ---@param key string the key ---@param value any the value; `nil` removes ---@return boolean `false` for an unknown party function SetPartyData(party, key, value) end ---A value of the mode's private storage on a party. ---@param party number the party ---@param key string the key function GetPartyData(party, key) end -- ======== Constants ============================================================= -- Colours ---amber - the server's own lines and the freeroam modes' COLOUR_SERVER = 0xFFD070FF COLOUR_WHITE = 0xFFFFFFFF COLOUR_RED = 0xFF4040FF COLOUR_GREEN = 0x40FF40FF COLOUR_YELLOW = 0xFFFF40FF -- Body parts ---`head` BODY_PART_HEAD = 1 ---`torso` BODY_PART_TORSO = 2 ---`arm_left` BODY_PART_ARM_LEFT = 3 ---`arm_right` BODY_PART_ARM_RIGHT = 4 ---`leg_left` BODY_PART_LEG_LEFT = 5 ---`leg_right` BODY_PART_LEG_RIGHT = 6 -- GameText styles ---big, in the middle of the screen GAMETEXT_CENTRE = 0 ---under the top edge GAMETEXT_TOP = 1 ---the lower third, like a subtitle GAMETEXT_LOWER = 2 -- HUD alignment HUD_ALIGN_LEFT = 0 HUD_ALIGN_CENTRE = 1 HUD_ALIGN_RIGHT = 2 -- Teams ---no team - what `SetPlayerTeam` takes to remove a player from theirs and `GetPlayerTeam` answers without one NO_TEAM = -1 -- Entity kinds ---a player's body - never an entity id a mode holds; players are pids ENTITY_PLAYER = 0 ---a horse (`CreateHorse`) ENTITY_HORSE = 1 ---a pickup lying in the world (`CreatePickup`, a player's drop) ENTITY_ITEM = 2 ---an NPC actor (`CreateActor`) ENTITY_NPC = 3 ---a static mesh (`CreateProp`) ENTITY_PROP = 4 ---a player's dog (`CreateDog`) ENTITY_DOG = 5 -- Dog modes ---waits where it is DOG_STAY = 0 ---at its master's heel (what a new dog does) DOG_FOLLOW = 1 ---roams near its master DOG_FREE = 2 ---the game's aggressive mode DOG_AGGRESSIVE = 3 ---the game's search mode DOG_SEARCH = 4 ---the game's hunt mode DOG_HUNT = 5 ---the game's guard mode DOG_GUARD = 6 ---the game's ambush mode DOG_AMBUSH = 7 -- Poses ---the pose aliases, alias -> clip ---@type table ACTOR_ANIM = { sit = "behavior_sitting_variation01_loop", -- loops wave = "greetings_wave_big_over|once", -- once bow = "greetings_bow|once", -- once nod = "greetings_head_nod_over|once", -- once pray = "pray_stand_long", -- loops chop = "woodchopping_loop_01", -- loops sweep = "sweeping_floor_idle_loop", -- loops smith = "armorsmith_loop", -- loops }