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