Lua client API: the client script API alone - the `KcdMp` table, its events, state bags and console commands
# Getting started
> What a client script is, how the server sends it to the players, what of the game's own Lua the sandbox gives it, its limits and where its output goes.
A **client script** is a Lua file that runs inside a player's game, in the game's own Lua state, next to the KCD:MP client.
It is the game mode's half on the player's screen: a marker in the world, a sound, a bit of UI, a value read from the game
that the server cannot see. A game mode works without one - the server's chat lines, GameTexts and HUD texts need nothing on
the client - and most modes need none. A mode that wants more puts its client files next to itself, and the server sends
them to every player who joins.
## How a script reaches the player
The server sends it. A mode with a client half lives in a folder of its own, the way a C# plugin does, with the client files
in `client/` next to it:
```
gamemodes/arena/arena.lua the server half - [gamemode] script names it
gamemodes/arena/client/*.lua the client half - sent to every joining player, run in name order
```
Nothing is asked of the players: the files arrive with the join, before the roster and the mode's first events, and run
once the level is ready - so a handler registered at the top of a file sees the event the mode sends from `OnPlayerSpawn`.
The launcher and the game say so when a server does this ("runs 2 client scripts in your game, sandboxed to the game").
`[client] scripts` in the server's configuration names another folder (a mode in a single file, or the built-in one, has no
`client/` of its own). The limits: 64 files, 256 KB each, 2 MB together. `/reload` on the server sends the folder again -
the running scripts are dropped first (their handlers, their timers), then the new ones run; the `watch` setting does the
same by itself when a client file changes on disk.
A script runs once, when it arrives; what it defines stays for the session and is gone with the game or replaced by the next
`/reload`. Several files of one folder share one environment: a function the first file defines, the second can call.
For development, a file on the player's own disk can still be run by hand: [`KcdMp_exec`](/lua/client/console/kcdmp_exec/) in the
**F9** window, or `-KcdMp_exec ` in the launcher's *Game arguments*. Such a file has the game's whole Lua, no sandbox -
it is the player's own.
## What the script has
A script the server sent runs in a **sandbox**: the boundary is the game. It has everything it needs to draw, read the world
and talk to the server, and nothing that reaches the player's computer beyond the game - no files, no other programs, no
browser, no console, no saves. What is there is listed below; a name that is not listed is not there (`nil`), and a
script that wants one more should say so - the list grows on request.
### The KcdMp table
The API on this side, every member on [its own page](/lua/client/):
- [script events](/lua/client/#script-events) to and from the game mode - `KcdMp.on_event`, `KcdMp.send_event`;
- [the state bags](/lua/client/#state-bags) the mode set - `KcdMp.state`, `KcdMp.on_state`, `KcdMp.player_id`;
- [helpers](/lua/client/#helpers) and [console commands](/lua/client/#console-commands).
### The game's own Lua, as the sandbox gives it
The script runs in the game's Lua state, in an environment of its own. What it holds:
| | |
|---|---|
| the base library | `assert`, `error`, `ipairs`, `next`, `pairs`, `pcall`, `select`, `tonumber`, `tostring`, `type`, `unpack`, `xpcall`, `rawequal`, `rawget`, `rawset`, `setmetatable`, `getmetatable` (not on strings), `collectgarbage`, `loadstring` (its chunks run in the sandbox too), `print` (into the client log) |
| `string`, `math`, `table`, `coroutine` | copies of the game's - a script may change its own copy, not the game's |
| `os.clock()`, `os.time()` | the two the game has |
| `System` | the log (`LogAlways`, `Log`, `Warning`, `Error`), the drawing for this frame (`DrawLabel(pos, size, text, r, g, b, a)`, `DrawLine(a, b, r, g, b, a)`, `DrawText`, `Draw2DLine`), the entities (`GetEntity`, `GetEntityByName`, `GetEntities`, `GetEntitiesByClass`, `GetEntitiesInSphere`, `GetNearestEntityByClass`, `GetPhysicalEntitiesInBox`, `SpawnEntity`, `RemoveEntity` ...), the world (`RayTraceCheck`, `RayWorldIntersection`, `GetTerrainElevation({x=, y=, z=})`, `IsPointIndoors`, `IsPointVisible`, `ProjectToScreen`, the view camera's `GetViewCameraPos` / `Dir` / `Fov`, `GetViewport`), the clocks (`GetCurrTime`, `GetFrameTime`, `GetFrameID`, `GetLocalOSTime`), the look of the world (`SetPostProcessFxParam`, `SetWind`, the ambient colour, the sky highlight, `ActivateLight`) |
| `Script.SetTimer(ms, fn)`, `Script.SetTimerForFunction(ms, fn)`, `Script.KillTimer(id)` | the game's own timers - one shot; call again for a loop. A `/reload` kills the ones a script left running |
| `Game` | the game's own table without its saves, loads and the recording |
| `Calendar` | the game's clock - `GetWorldHourOfDay()`, `GetWorldTime()` (game seconds since day zero) |
| `UIAction` | the game's own UI elements from Lua - `ShowElement`, `HideElement`, `CallFunction`, `SetVariable`, the listeners: the road to UI in the game's own look |
| `Particle` | `SpawnEffect`, `CreateDecal` |
| `player` | the local player entity: `player:GetWorldPos()`, `player.soul` (`GetStatLevel`, `GetSkillLevel`, `HasPerk` ...), `player.actor`, `player.human` (`IsMounted`, `IsWeaponDrawn` ...), `player.inventory` (`GetInventoryTable`, `HasItem` ...) |
| `KcdMp` | [the API](/lua/client/) - the events, the state bags, the helpers |
What is not there, on purpose: `dofile`, `loadfile`, `require` (any file on the disk), `io`, `package`, `debug`,
`getfenv` / `setfenv`, `System.ExecuteCommand` and the console, `System.BrowseURL`, `System.Quit`, `System.LoadTextFile`,
the saves, `Script.LoadScript`. The entity tables (`player`, what `System.GetEntity` returns) are the game's own with
every function of theirs - its scripts (`Scripts.pak`) show the names and signatures, and a list of them is planned for
this reference. Two warnings: inside the game the script has the game's power over the player's own client, so it can
still break their game; and a script that changes the player's own health, items or position is cheating in the server's
eyes - the server judges what the client reports, and the [inventory audit](/lua/server/callbacks/onplayerauditviolation/)
is one of the judges. Values, combat, health and items stay the server's: a client script gets no say in them.
### Not an API
The `KcdMp` table also holds the client's own machinery - `KcdMp.remote` (the other players' bodies by net
id), `KcdMp.labels`, the locomotion and animation helpers. They change without notice; a script that reads them should
expect to be fixed after an update.
## A first script
The marker round trip: the mode sends a point, the script draws a label there until the player is close, then tells the mode.
The server folder ships it whole as the **marker** example mode (`gamemodes/marker/marker.lua` with `client/marker.lua`: a
checkpoint run around the spawn, laps counted by the server).
```lua
-- gamemodes/marker/client/marker.lua
local marker -- {x=, y=, z=} or nil
KcdMp.on_event("marker", function(payload)
local x, y, z = payload:match("^([^,]+),([^,]+),(.+)$")
marker = {x = tonumber(x), y = tonumber(y), z = tonumber(z)}
print("marker at " .. payload)
end)
-- the drawing functions show for one frame: draw from the frame hook, not a timer
KcdMp.on_frame(function()
if marker and player then
local p = player:GetWorldPos()
local d = math.sqrt((p.x - marker.x) ^ 2 + (p.y - marker.y) ^ 2)
System.DrawLabel({x = marker.x, y = marker.y, z = marker.z + 1.5}, 1.4, string.format("%.0f m", d), 1, 0.85, 0.3, 1)
if d < 2 then
KcdMp.send_event("marker_reached", "")
marker = nil
end
end
end)
```
```lua
-- gamemodes/marker/marker.lua, the game mode's side
function OnPlayerSpawn(pid)
SendClientEvent(pid, "marker", "1290.0,1095.0,26.3")
end
function OnClientEvent(pid, name, payload)
-- the client says it is there; the mode checks GetPlayerPos before it counts
if name == "marker_reached" then GameText(pid, "Checkpoint!", 1500) end
end
```
## Limits and errors
- A script may send at most **30 events a second and 4 KB each** to the server; more is dropped.
- A client half is at most **64 files, 256 KB each, 2 MB together**; a file over the limit is left out with a line in the
server's log.
- An error inside an event or state handler is logged (`[KcdMp] event 'name' handler: ...`) and the handler is left in
place; a frame handler that fails is logged and removed; a syntax or load-time error in a file is logged with the file's
name and line (`[KcdMp] client script marker.lua: marker.lua:12: ...`) and the other files still run.
- `print(...)` and `System.LogAlways("[KcdMp] ...")` land in the KCD:MP client log, `%LOCALAPPDATA%\KcdMp\client.log`; the
F9 window, where the server allows it, shows the console's own output.
- The game's console splits a line on `;` and treats `a=b` as an assignment: a text passed through a console command must
avoid both. The script events encode their payload, so they carry anything.
# Client API
> Everything a client script may use on a player's game - the KcdMp table's functions and properties and the console commands - each with its own page.
A **client script** is a Lua file the server sends to every player who joins and their game runs, in a sandbox - the mode's
own half on the screen: a marker, a sound, a bit of UI, a value read from the game. It talks to the server's game mode through
**script events** and reads the mode's **state bags**; everything else it does is the game's own Lua, as far as the sandbox
lets it. The `KcdMp` table is the whole API on this side; the [guide](/lua/client/getting-started/) says how a script reaches
the player and what the game gives it.
| Guide | |
|---|---|
| [Getting started](/lua/client/getting-started/) | what a client script is, how the server sends it, what of the game's Lua the sandbox gives it, limits and logging |
| Topic | |
|---|---|
| [Script events](#script-events) | 2 functions, 1 property |
| [State bags](#state-bags) | 1 function, 3 properties |
| [Helpers](#helpers) | 5 functions, 1 property |
| [Console commands](#console-commands) | 4 console commands |
| [The party](#the-party) | 2 properties |
## Script events
Named events with a string payload, both ways between the game mode and the client script: the mode's `SendClientEvent`
lands in a handler registered with [`KcdMp.on_event`](/lua/client/functions/on_event/); [`KcdMp.send_event`](/lua/client/functions/send_event/) goes up into the mode's `OnClientEvent`. The
payload is whatever string the two halves agree on - a number, a comma list, JSON.
| Function | What it does |
|---|---|
| [`KcdMp.on_event`](/lua/client/functions/on_event/) | Registers the handler for one event name from the game mode. |
| [`KcdMp.send_event`](/lua/client/functions/send_event/) | Sends an event to the game mode's OnClientEvent. |
| Property | What it holds |
|---|---|
| [`KcdMp.on_any_event`](/lua/client/properties/on_any_event/) | A catch-all handler for events without one of their own. |
## State bags
The game mode's **state bags** as every client sees them: string keys and values the mode set with `SetGlobalState`,
`SetPlayerState` and `SetEntityState`. The global and the players' bags arrive whole when the client joins and every change
arrives at once; an entity's bag comes with the entity when it enters view and goes when it leaves. Values are strings
(`"3"`, `"true"`); a removed key reads `nil`. Two hooks tell a script about changes.
| Function | What it does |
|---|---|
| [`KcdMp.on_state`](/lua/client/functions/on_state/) | Registers a handler for one key, whatever bag it changes in. |
| Property | What it holds |
|---|---|
| [`KcdMp.state`](/lua/client/properties/state/) | The bags - global, per player, per entity - as tables of strings. |
| [`KcdMp.player_id`](/lua/client/properties/player_id/) | This client's own player id. |
| [`KcdMp.on_state_change`](/lua/client/properties/on_state_change/) | A hook called on every change of any bag. |
## Helpers
The frame hook, small conveniences the `KcdMp` table offers on top of the game's own Lua, and a switch a script may flip.
Everything else a client script does - drawing, sounds, reading the player - is the game's Lua, described in the
[guide](/lua/client/getting-started/#the-games-own-lua-as-the-sandbox-gives-it).
| Function | What it does |
|---|---|
| [`KcdMp.on_frame`](/lua/client/functions/on_frame/) | Runs a function every frame - where a script draws. |
| [`KcdMp.level`](/lua/client/functions/level/) | The name of the level the game runs. |
| [`KcdMp.player_pos`](/lua/client/functions/player_pos/) | The local player's position as a string. |
| [`KcdMp.count`](/lua/client/functions/count/) | How many entities of a class the level holds. |
| [`KcdMp.census`](/lua/client/functions/census/) | The entity classes of the level with the most instances. |
| Property | What it holds |
|---|---|
| [`KcdMp.label_occlusion`](/lua/client/properties/label_occlusion/) | Whether the labels over the other players hide behind walls. |
## Console commands
The client adds a few commands to the game's console. A player reaches them through the **F9** window of the KCD:MP overlay -
a line typed there is a console command, and a line starting with `lua ` runs Lua directly. The window is closed unless the
server opens it (`[client] console` in its configuration; a development server does, a public one has no reason to) or the
game runs offline with `-KcdMp_console`. A script the server sent has no console at all - the sandbox keeps
`System.ExecuteCommand` away from it - and talks to the server through the script events; a script run by hand through
`KcdMp_exec` has the game's whole Lua and may call `System.ExecuteCommand("...")`. Two things to know about the game's console:
it splits a line on `;` and treats `a=b` as a variable assignment, so a text with either has to avoid them (the script events
encode their payload for exactly this reason).
| Command | What it does |
|---|---|
| [`KcdMp_exec`](/lua/client/console/kcdmp_exec/) | Runs a Lua file from disk - the development way to try a client script. |
| [`KcdMp_log`](/lua/client/console/kcdmp_log/) | Writes a line into the KCD:MP client log. |
| [`KcdMp_say`](/lua/client/console/kcdmp_say/) | Sends a chat line, as if typed. |
| [`KcdMp_net`](/lua/client/console/kcdmp_net/) | The connection's figures - snapshots decoded, bytes, the acknowledgement. |
## The party
The party this player is in (v38), as the server keeps it - the members with their labels and the others' vitals at any
distance - for a script that draws its own frames or reacts to the group. The server draws the standard frames unless the
mode hides them per player (`ShowPartyFrames` on the server); a script that draws its own reads [`KcdMp.party`](/lua/client/properties/party/) and hooks
[`KcdMp.on_party_change`](/lua/client/properties/on_party_change/). The invitation toast and its keys (Y / N, `KcdMp_party_keys` changes them) are the client's own.
| Property | What it holds |
|---|---|
| [`KcdMp.party`](/lua/client/properties/party/) | The party as the server last sent it. |
| [`KcdMp.on_party_change`](/lua/client/properties/on_party_change/) | A hook called with the party after every change. |
# KcdMp_exec
> Runs a Lua file from disk - the development way to try a client script.
Runs a Lua file from disk - the development way to try a client script.
The file is read from disk and run on the game thread on the next frame, with the game's whole Lua (no sandbox: it is the
player's own file); a relative path is relative to the KCD:MP install folder (where `KcdMp_client.dll` lives). The same
file can be named on the game's command line as `-KcdMp_exec ` - through the launcher's *Game arguments* - to
run two seconds after the level is ready. A syntax error is reported in the client log with its line. The scripts a
server sends need none of this: they arrive with the join and run by themselves.
## Syntax
```text
KcdMp_exec
```
| Parameter | Type | |
|---|---|---|
| `file` | path | the Lua file, relative to the install folder or absolute |
## Returns
nothing
## Example
```lua
KcdMp_exec scripts/arena_client.lua
```
## See also
[KcdMp_log](/lua/client/console/kcdmp_log/) · the [Console commands](/lua/client/#console-commands) group of the index
# KcdMp_log
> Writes a line into the KCD:MP client log.
Writes a line into the KCD:MP client log.
The client log is `%LOCALAPPDATA%\KcdMp\client.log`. A script's `System.LogAlways("[KcdMp] ...")` lines land there too -
any line starting with `[KcdMp]` is mirrored - which is the easier way from Lua.
## Syntax
```text
KcdMp_log
```
| Parameter | Type | |
|---|---|---|
| `text` | string | the line; no `;` or `=` |
## Returns
nothing
## Example
```lua
KcdMp_log the marker script is loaded
```
## See also
[KcdMp_exec](/lua/client/console/kcdmp_exec/) · the [Console commands](/lua/client/#console-commands) group of the index
# KcdMp_net
> The connection's figures - snapshots decoded, bytes, the acknowledgement.
The connection's figures - snapshots decoded, bytes, the acknowledgement.
A diagnostic line in the client log and the F9 window: how many snapshots arrived as deltas, whole or were dropped, their
bytes, and the last acknowledgement - the client's side of the server's traffic figures. For a player who asks "is it me or
the server?".
## Syntax
```text
KcdMp_net
```
## Returns
nothing
## Example
```lua
KcdMp_net
```
## See also
[KcdMp_log](/lua/client/console/kcdmp_log/) · the [Console commands](/lua/client/#console-commands) group of the index
# KcdMp_say
> Sends a chat line, as if typed.
Sends a chat line, as if typed.
The line goes to the server like one typed in the chat box: a `/` line is a command for the mode and the server's
built-ins.
## Syntax
```text
KcdMp_say
```
| Parameter | Type | |
|---|---|---|
| `text` | string | the line; no `;` or `=` |
## Returns
nothing
## Example
```lua
KcdMp_say /duel
```
## See also
[KcdMp_exec](/lua/client/console/kcdmp_exec/) · the [Console commands](/lua/client/#console-commands) group of the index
# KcdMp.census
> The entity classes of the level with the most instances.
The entity classes of the level with the most instances.
## Syntax
```lua
KcdMp.census(top)
```
| Parameter | Type | |
|---|---|---|
| `top` | number | how many classes to list |
## Returns
`number, string` - `total, list` - the number of entities and a string `"Class n, Class n, ..."` of the `top` most common
## Example
```lua
local total, list = KcdMp.census(5)
System.LogAlways(string.format("[KcdMp] %d entities: %s", total, list))
```
## See also
[KcdMp.count](/lua/client/functions/count/) · the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.count
> How many entities of a class the level holds.
How many entities of a class the level holds.
## Syntax
```lua
KcdMp.count(cls)
```
| Parameter | Type | |
|---|---|---|
| `cls` | string | an entity class name (`"NPC"`, `"Horse"`, `"AnimDoor"`, `"Stash"` ...) |
## Returns
`number` - `0` when none or the class is unknown
## Example
```lua
System.LogAlways("[KcdMp] doors: " .. KcdMp.count("AnimDoor"))
```
## See also
[KcdMp.census](/lua/client/functions/census/) · the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.level
> The name of the level the game runs.
The name of the level the game runs.
## Syntax
```lua
KcdMp.level()
```
## Returns
`string` - `klaster`, `trosecko`, `kutnohorsko`; `nil` when unknown
## Example
```lua
if KcdMp.level() == "klaster" then System.LogAlways("[KcdMp] the monastery") end
```
## See also
[KcdMp.player_pos](/lua/client/functions/player_pos/) · the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.on_event
> Registers the handler for one event name from the game mode.
Registers the handler for one event name from the game mode.
One handler per name; a second call replaces the first. The handler gets the payload and the name. An error inside it
is logged (`[KcdMp] event 'name' handler: ...`), never fatal. Events without a handler go to [`KcdMp.on_any_event`](/lua/client/properties/on_any_event/).
## Syntax
```lua
KcdMp.on_event(name, fn)
```
| Parameter | Type | |
|---|---|---|
| `name` | string | the event's name, as the mode sends it |
| `fn` | function | `function(payload, name) end` |
## Returns
nothing
## Example
```lua
KcdMp.on_event("marker", function(payload)
local x, y, z = payload:match("^([^,]+),([^,]+),(.+)$")
marker = {x = tonumber(x), y = tonumber(y), z = tonumber(z)}
System.LogAlways("[KcdMp] marker at " .. x .. " " .. y)
end)
```
## See also
[KcdMp.on_any_event](/lua/client/properties/on_any_event/) · [KcdMp.send_event](/lua/client/functions/send_event/) · the [Script events](/lua/client/#script-events) group of the index
# KcdMp.on_frame
> Runs a function every frame - where a script draws.
Runs a function every frame - where a script draws.
The game's drawing functions (`System.DrawLabel`, `System.DrawLine` ...) show what they draw for one frame only, so a
mark that should stay is drawn again every frame from here; a timer would blink. The handler gets the frame's length in
seconds. Several handlers may be registered; one that raises an error is logged (`[KcdMp] frame handler: ...`) and
removed, so a broken script cannot fill the log sixty times a second. The handlers go with the script set on a
`/reload`. Keep the work small: it runs on the game's thread, every frame.
## Syntax
```lua
KcdMp.on_frame(fn)
```
| Parameter | Type | |
|---|---|---|
| `fn` | function | `function(dt) end` - `dt` the frame time in seconds |
## Returns
nothing
## Example
```lua
KcdMp.on_frame(function()
if marker then
System.DrawLabel({x = marker.x, y = marker.y, z = marker.z + 1.6}, 1.4, "here", 1, 0.85, 0.3, 1)
end
end)
```
## See also
[KcdMp.on_event](/lua/client/functions/on_event/) · the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.on_state
> Registers a handler for one key, whatever bag it changes in.
Registers a handler for one key, whatever bag it changes in.
One handler per key. The handler gets the new value (`nil` when removed), the scope (`"global"`, `"player"`, `"entity"`)
and the id. Runs before [`KcdMp.on_state_change`](/lua/client/properties/on_state_change/) for the same change.
## Syntax
```lua
KcdMp.on_state(key, fn)
```
| Parameter | Type | |
|---|---|---|
| `key` | string | the key to watch |
| `fn` | function | `function(value, scope, id) end` |
## Returns
nothing
## Example
```lua
-- remember every player's team as the mode puts it in their bags
KcdMp.on_state("team", function(value, scope, pid)
if scope == "player" then teamOf[pid] = tonumber(value) end
end)
```
## See also
[KcdMp.on_state_change](/lua/client/properties/on_state_change/) · [KcdMp.state](/lua/client/properties/state/) · the [State bags](/lua/client/#state-bags) group of the index
# KcdMp.player_pos
> The local player's position as a string.
The local player's position as a string.
A quick readout for logs - `"1280.5 1088.0 26.3"`. For numbers, read the player entity directly:
`player:GetWorldPos()` gives `{x=, y=, z=}`.
## Syntax
```lua
KcdMp.player_pos()
```
## Returns
`string` - `"x y z"` with one decimal; `"none"` before the player exists
## Example
```lua
System.LogAlways("[KcdMp] I am at " .. KcdMp.player_pos())
```
## See also
[KcdMp.level](/lua/client/functions/level/) · the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.send_event
> Sends an event to the game mode's OnClientEvent.
Sends an event to the game mode's OnClientEvent.
The server accepts at most 30 events a second and 4 KB each from one client; more is dropped. The payload travels as the
string given (`""` without one) - the mode trusts it no further than any other input.
## Syntax
```lua
KcdMp.send_event(name [, payload])
```
| Parameter | Type | |
|---|---|---|
| `name` | string | the event's name |
| `payload` | string | the string to send *(optional)* |
## Returns
nothing
## Example
```lua
KcdMp.send_event("marker_reached", tostring(markerIndex))
```
## See also
[KcdMp.on_event](/lua/client/functions/on_event/) · the [Script events](/lua/client/#script-events) group of the index
# KcdMp.label_occlusion
> Whether the labels over the other players hide behind walls.
Whether the labels over the other players hide behind walls.
`true` by default: a label is hidden when something stands between the player's eyes and the body. Set it to `false` to see
every label through everything - a debugging aid, and a choice a mode may make for its players.
## Syntax
```lua
KcdMp.label_occlusion
```
## Returns
`boolean`; `nil` counts as `true`
## Example
```lua
KcdMp.label_occlusion = false
```
## See also
the [Helpers](/lua/client/#helpers) group of the index
# KcdMp.on_any_event
> A catch-all handler for events without one of their own.
A catch-all handler for events without one of their own.
Set it to a function to receive every event no [`KcdMp.on_event`](/lua/client/functions/on_event/) handler claims. `nil` (the default) ignores them.
## Syntax
```lua
KcdMp.on_any_event
```
## Returns
`function | nil` - `function(name, payload) end`, or `nil` for no hook
## Example
```lua
KcdMp.on_any_event = function(name, payload)
System.LogAlways("[KcdMp] unhandled event " .. name .. ": " .. payload)
end
```
## See also
[KcdMp.on_event](/lua/client/functions/on_event/) · the [Script events](/lua/client/#script-events) group of the index
# KcdMp.on_party_change
> A hook called with the party after every change.
A hook called with the party after every change.
Set it to a function to hear every PartyState (membership, leader, name, labels, the frames switch) and every vitals
update (at most twice a second). The argument is [`KcdMp.party`](/lua/client/properties/party/); an empty party (`id` 0) means the player left or the
party ended. An error inside is logged (`[KcdMp] on_party_change: ...`).
## Syntax
```lua
KcdMp.on_party_change
```
## Returns
`function | nil` - `function(party) end`, or `nil` for no hook
## Example
```lua
KcdMp.on_party_change = function(party)
if party.id ~= 0 then print("party " .. party.id .. ": " .. #party.members .. " member(s)") end
end
```
## See also
[KcdMp.party](/lua/client/properties/party/) · the [The party](/lua/client/#the-party) group of the index
# KcdMp.on_state_change
> A hook called on every change of any bag.
A hook called on every change of any bag.
Set it to a function to hear every change: `scope` is `"global"`, `"player"` or `"entity"`; `id` the pid or entity id
(`0` for the global bag); `value` the new string, `nil` when the key was removed. An error inside it is logged, never fatal.
## Syntax
```lua
KcdMp.on_state_change
```
## Returns
`function | nil` - `function(scope, id, key, value) end`, or `nil` for no hook
## Example
```lua
KcdMp.on_state_change = function(scope, id, key, value)
System.LogAlways(string.format("[KcdMp] state %s %s %s = %s", scope, tostring(id), key, tostring(value)))
end
```
## See also
[KcdMp.on_state](/lua/client/functions/on_state/) · [KcdMp.state](/lua/client/properties/state/) · the [State bags](/lua/client/#state-bags) group of the index
# KcdMp.party
> The party as the server last sent it.
The party as the server last sent it.
`id` is 0 in no party. `members` come in join order, the client's own player among them; each has the pid, the name,
the mode's `label`, and the vitals of the last update - `health`, `maxHealth`, `stamina`, `maxStamina`, `injuries`
(bits as the game's body parts 1-6), `dead`, `bleeding`, `loading` (not in the world) - with `vitals` false until the
first update arrived (the own entry never has them: the game's HUD does). `frames` says whether the server's frames are
shown to this player. Read it live; a copy goes stale within half a second.
## Syntax
```lua
KcdMp.party
```
## Returns
`table` - `{id = number, leader = pid, name = string, frames = boolean, members = {{pid, name, label, health, maxHealth, stamina, maxStamina, injuries, dead, bleeding, loading, vitals}, ...}}`
## Example
```lua
-- the weakest other member, for a script that marks who needs help
local function weakest()
local party, best, low = KcdMp.party, nil, 2
if not party or party.id == 0 then return nil end
for _, m in ipairs(party.members) do
if m.pid ~= KcdMp.player_id and m.vitals and not m.dead and m.maxHealth > 0 and m.health / m.maxHealth < low then
best, low = m, m.health / m.maxHealth
end
end
return best
end
```
## See also
[KcdMp.on_party_change](/lua/client/properties/on_party_change/) · [KcdMp.player_id](/lua/client/properties/player_id/) · the [The party](/lua/client/#the-party) group of the index
# KcdMp.player_id
> This client's own player id.
This client's own player id.
Set when the server welcomes the client; `nil` before. The key into `KcdMp.state.player` for the client's own bag, and
the pid the mode sees this player as.
## Syntax
```lua
KcdMp.player_id
```
## Returns
`number` - the pid; `nil` before the welcome
## Example
```lua
local me = KcdMp.state.player[KcdMp.player_id] or {}
```
## See also
[KcdMp.state](/lua/client/properties/state/) · the [State bags](/lua/client/#state-bags) group of the index
# KcdMp.state
> The bags - global, per player, per entity - as tables of strings.
The bags - global, per player, per entity - as tables of strings.
`KcdMp.state.global[key]` is the world's bag; `KcdMp.state.player[pid][key]` a player's (every player's, from the join
on; the client's own pid is [`KcdMp.player_id`](/lua/client/properties/player_id/)); `KcdMp.state.entity[id][key]` an entity's while it is in view. A
player's table appears with their first key and goes with their leave; read `KcdMp.state.player[pid]` defensively.
## Syntax
```lua
KcdMp.state
```
## Returns
`table` - `{global = {key = value}, player = {[pid] = {key = value}}, entity = {[id] = {key = value}}}`
## Example
```lua
local round = tonumber(KcdMp.state.global.round) or 0
local mine = KcdMp.state.player[KcdMp.player_id]
local team = mine and mine.team
```
## See also
[KcdMp.on_state](/lua/client/functions/on_state/) · [KcdMp.on_state_change](/lua/client/properties/on_state_change/) · [KcdMp.player_id](/lua/client/properties/player_id/) · the [State bags](/lua/client/#state-bags) group of the index