@kingdomsconnected/types 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,16 +88,38 @@ declare global {
88
88
  */
89
89
  playerReady: [player: Player];
90
90
 
91
+ /**
92
+ * An inventory changed. Raised on the next server tick in the order the changes happened, once per inventory an operation touched: a transfer raises it for both players. A handler may change inventories; those changes arrive on a later tick. Every change of a player who disconnects is raised before `playerDisconnect`. Save from here to keep inventories across sessions -- the server keeps nothing itself.
93
+ */
94
+ playerInventoryChanged: [player: Player, change: InventoryChange];
95
+
96
+ /**
97
+ * The player's game spent items: ate, drank, applied or fired them. Raised after the `playerInventoryChanged` that removed them. `item` is the class GUID.
98
+ *
99
+ * This is the player's own game saying so: the server checked that the units existed and were of a kind that can be spent that way, and took them, but did not see the meal or the shot. A handler that rewards a use -- a heal, a buff -- can be had for the price of the item.
100
+ */
101
+ playerItemUsed: [player: Player, item: string, kind: "food" | "potion" | "ointment" | "shot", amount: number];
102
+
103
+ /**
104
+ * A player's game shows their inventory for the first time this session. Their inventory exists from `playerConnect`; restore a saved one there with `Inventory.set`, and it is what they load in with.
105
+ */
106
+ playerInventoryReady: [player: Player];
107
+
91
108
  /**
92
109
  * Dispatched immediately after a horse is created and replicated, whether by `Horse.spawn`, the `/horse` command, or anything else.
93
110
  */
94
111
  horseSpawn: [horse: Horse];
95
112
 
96
113
  /**
97
- * Dispatched while a horse is being despawned. The handle still resolves, so its rider and name can be read one last time.
114
+ * Dispatched while a horse is being despawned, including the despawn its owner's disconnect implies. The handle still resolves, so its owner and name can be read one last time.
98
115
  */
99
116
  horseDestroy: [horse: Horse];
100
117
 
118
+ /**
119
+ * Dispatched after a horse is handed to another player, or left ownerless -- by `giveTo`, or by its owner disconnecting while `destroyWithOwner` is false.
120
+ */
121
+ horseOwnerChanged: [horse: Horse, player: Player | null];
122
+
101
123
  /**
102
124
  * Dispatched after a player climbs into a saddle and the horse's authority has been handed to their client.
103
125
  */
@@ -172,6 +194,31 @@ declare global {
172
194
  */
173
195
  playerPickpocketCaught: [thief: Player, victim: Player];
174
196
 
197
+ /**
198
+ * A player asks to open an alchemy table. Every handler runs; one returning literal `false` refuses it. An async handler cannot refuse.
199
+ */
200
+ craftingStarting: [player: Player, proposal: CraftStartProposal];
201
+
202
+ /**
203
+ * A batch is brewing.
204
+ */
205
+ craftingStarted: [player: Player, event: CraftStartedEvent];
206
+
207
+ /**
208
+ * A batch finished and its result is computed. Every handler runs; one returning literal `false` refuses it: the batch ends as failed, what was spent stays spent, and nothing is granted.
209
+ */
210
+ craftingCompleting: [player: Player, proposal: CraftCompletionProposal];
211
+
212
+ /**
213
+ * A batch's result was granted, followed by `craftingEnded`. Raised after the `playerInventoryChanged` it caused.
214
+ */
215
+ craftingCompleted: [player: Player, event: CraftCompletedEvent];
216
+
217
+ /**
218
+ * A batch is over. Raised after the `playerInventoryChanged` of any refund.
219
+ */
220
+ craftingEnded: [player: Player, event: CraftEndedEvent];
221
+
175
222
  /**
176
223
  * Dispatched immediately after a dog is created and replicated, whether by `Dog.spawn` or anything else.
177
224
  */
@@ -297,6 +344,16 @@ declare global {
297
344
  */
298
345
  groundItemPickup: [groundItem: GroundItem, player: Player | null];
299
346
 
347
+ /**
348
+ * A player picked a plant within their reach, and the server is about to give them the herb. Return false to refuse it: nothing is given and the plants stay. The proposal is frozen; every handler runs whatever an earlier one returned, and an async handler cannot refuse.
349
+ */
350
+ gatheringHarvest: [player: Player, proposal: GatheringProposal];
351
+
352
+ /**
353
+ * A player was given a herb, after the `playerInventoryChanged` it caused. The plant and the same-kind plants harvested with it are picked for everyone in the virtual world until they regrow; nothing about them survives a restart.
354
+ */
355
+ gatheringHarvested: [player: Player, event: GatheringHarvestedEvent];
356
+
300
357
  /**
301
358
  * Dispatched when a player's client reports working a door, before the server applies it. `action` is `open`, `close`, `lock`, `unlock` or `lockpick`; a key turned in the same use as the push arrives as `unlock` and then `open`. `keySide` says whether the player stood on the side with the keyhole, which is where an unlock needs a key.
302
359
  *
@@ -304,6 +361,31 @@ declare global {
304
361
  */
305
362
  doorInteract: [player: Player, door: Door, action: "open" | "close" | "lock" | "unlock" | "lockpick", keySide: boolean];
306
363
 
364
+ /**
365
+ * A container now exists: one a script spawned, or one the level places, built in a virtual world the first time anything there asked for it. Every container starts empty; restore saved contents here with `setInventory`. The level's containers in the global world are built before any resource runs, so restore those from `resourceStart` by walking `Stash.all()`.
366
+ */
367
+ stashSpawn: [stash: Stash];
368
+
369
+ /**
370
+ * A player opened a container and sees what it holds.
371
+ */
372
+ stashOpen: [stash: Stash, player: Player];
373
+
374
+ /**
375
+ * A player no longer has a container open: they closed it, walked away, died or changed world (`lostAccess`), sent nothing for two minutes, left, or the container went.
376
+ */
377
+ stashClose: [stash: Stash, player: Player, reason: "closed" | "lostAccess" | "timeout" | "disconnected" | "destroyed"];
378
+
379
+ /**
380
+ * What a container holds changed. `player` moved the units -- `change.reason` is `deposit` or `withdraw`, and their inventory raises `playerInventoryChanged` too -- or is null for a script's `addItem`, `removeItem` or `setInventory`, or `destroy` when the container went with something in it. Save from here to keep contents across restarts: the server keeps nothing itself. A linked child's `stash` is the one the player used; its stock is its master's.
381
+ */
382
+ stashInventoryChanged: [stash: Stash, player: Player | null, change: InventoryChange];
383
+
384
+ /**
385
+ * A container is about to go. Raised after its close and its contents' removal, while it can still be read.
386
+ */
387
+ stashDestroy: [stash: Stash];
388
+
307
389
  /**
308
390
  * Dispatched when a player presses a container's prompt, before anything happens: the player's client holds the game's own handler until the server answers. `action` is `open`, `unlock` -- a key turned, which opens it in the same use -- or `lockpick`, the minigame starting; a successful pick then opens it without asking again.
309
391
  *
@@ -346,6 +428,41 @@ declare global {
346
428
  */
347
429
  playerBuffBlocked: [player: Player, buff: string];
348
430
 
431
+ /**
432
+ * Dispatched when a player's own game produced XP -- a hit landed, a lock picked, a page read -- and asks for it. Return `false` to refuse it; the gain then never happens. `xp` is before this server's rate and the player's own multipliers. `source` is the game's name for what caused it: `Attack`, `LockpickingResult` and so on, or empty. Nothing is asked while `Progression.setNativeXp(false)` is in force.
433
+ */
434
+ playerXpGaining: [player: Player, track: string, xp: number, source: string];
435
+
436
+ /**
437
+ * Dispatched when XP landed on a player's character, from their game or from this server, after every multiplier.
438
+ */
439
+ playerXpGained: [player: Player, track: string, xp: number];
440
+
441
+ /**
442
+ * Dispatched when one of a player's tracks reaches a new level. `perkPoints` is what that track's tree now has unspent.
443
+ */
444
+ playerLevelUp: [player: Player, track: string, level: number, perkPoints: number];
445
+
446
+ /**
447
+ * Dispatched when a player confirmed a perk on the perk screen and every rule of the game allows it: the tree's level, the parent perk, the exclusive partner, a point to spend, and this server's block list. Return `false` to refuse it; the point is not spent and their client raises `progressionPerkRefused`.
448
+ */
449
+ playerPerkLearning: [player: Player, perk: string];
450
+
451
+ /**
452
+ * Dispatched when a perk appeared on a player's character: learnt on the perk screen, given by this server, or granted by the game on its own -- a codex entry, a recipe, a combat move it teaches.
453
+ */
454
+ playerPerkAdded: [player: Player, perk: string, source: "learned" | "server" | "native"];
455
+
456
+ /**
457
+ * Dispatched when a perk left a player's character: taken or respecced by this server, or removed by the game.
458
+ */
459
+ playerPerkRemoved: [player: Player, perk: string, source: "server" | "native"];
460
+
461
+ /**
462
+ * Dispatched when a player's client reported progression this server never ordered: a track that rose further than any gain it granted could take it, or a perk-screen perk nobody learnt. The report is kept -- the game has no way to take a level back -- so what happens to the player is the handler's call; a kick is the usual answer.
463
+ */
464
+ playerProgressionRejected: [player: Player, reason: string];
465
+
349
466
  /**
350
467
  * Dispatched after a resource entry point has run and immediately before the resource becomes running.
351
468
  */
@@ -360,6 +477,16 @@ declare global {
360
477
  * Dispatched when one key of an entity's state changes: on the server when a script writes it, on a client when the write arrives. `value` is undefined when the key was removed and `previous` is undefined when it held nothing before, so a stored null stays distinguishable from an absent key. The entity is whatever the game's WrapScriptEntity answers, and the base Entity handle by default.
361
478
  */
362
479
  entityStateChange: [entity: Entity, key: string, value: any, previous: any];
480
+
481
+ /**
482
+ * Dispatched for a line typed into the server console that no built-in command (help, ensure, refresh, ...) claimed. `args` is the rest of the line, split on whitespace. The console is the operator's, so this is the place for commands no player may run.
483
+ */
484
+ consoleCommand: [command: string, args: string[]];
485
+
486
+ /**
487
+ * Dispatched when a player asks to join, before the connection exists: they hold no player slot, are not counted as online, and are sent nothing -- no resource list, no download, no body. The request waits until every handler has returned and every Promise a handler returned has settled, then it is let in if a player slot is free (otherwise it is refused as full). `connection.reject()` turns it away instead, and so does a handler that throws or rejects, or handlers that have not settled within the server's admission timeout (30 seconds by default, restarted by every `connection.update()`). With no handler at all, every request is let in at once.
488
+ */
489
+ playerConnecting: [connection: PendingConnection];
363
490
  }
364
491
 
365
492
  /** Names of native events available in this scripting environment. */
@@ -494,6 +621,231 @@ declare global {
494
621
  unarmed: number;
495
622
  }
496
623
 
624
+ /**
625
+ * One skill or stat a player levels, as the game's own tables describe it.
626
+ */
627
+ interface TrackInfo {
628
+ /**
629
+ * The name every progression verb takes, as the game's tables spell it: `weapon_sword`, `thievery`, `strength`.
630
+ */
631
+ name: string;
632
+
633
+ /**
634
+ * Whether it is a skill or one of the stats the skills sit on.
635
+ */
636
+ kind: "skill" | "stat";
637
+
638
+ /**
639
+ * The highest level the game lets it reach.
640
+ */
641
+ cap: number;
642
+
643
+ /**
644
+ * True for fencing alone: it is never earned, the game derives it from the five weapon skills, so XP handed to it is refused.
645
+ */
646
+ induced: boolean;
647
+ }
648
+
649
+ /**
650
+ * One perk, as the game's own perk tables describe it.
651
+ */
652
+ interface PerkInfo {
653
+ /**
654
+ * The perk's `perk_name`, unique across the tables, and the spelling every perk verb takes alongside its GUID.
655
+ */
656
+ name: string;
657
+
658
+ /**
659
+ * The perk's GUID.
660
+ */
661
+ id: string;
662
+
663
+ /**
664
+ * The localisation key the perk screen shows, or empty for a perk it never shows.
665
+ */
666
+ uiName: string;
667
+
668
+ /**
669
+ * The track whose points pay for it: a track name, `main` for the main-level bank, or null for a perk no player's tree carries.
670
+ */
671
+ track: string | null;
672
+
673
+ /**
674
+ * The level that track has to reach before the perk can be learnt. 0 for none.
675
+ */
676
+ level: number;
677
+
678
+ /**
679
+ * The perk that has to be owned first, or null.
680
+ */
681
+ parent: string | null;
682
+
683
+ /**
684
+ * `visible` perks are the ones on the perk screen and the only ones a player can learn; `hidden` ones appear once something grants them; `system` ones implement game features and are never shown.
685
+ */
686
+ visibility: "system" | "hidden" | "visible" | "obsolete";
687
+
688
+ /**
689
+ * What the perk does when owned, from the game's side tables: `buff` (a real status effect), `script`, `technique` (a combat move), `ability`, `param` (rewrites a game rule), `companion` (the dog), `recipe`, `codex`. Empty for a perk that only gates others.
690
+ */
691
+ kinds: string[];
692
+
693
+ /**
694
+ * Whether the game grants it on its own once its requirements are met, rather than on the perk screen.
695
+ */
696
+ autolearnable: boolean;
697
+ }
698
+
699
+ /**
700
+ * Where a player stands on one track.
701
+ */
702
+ interface TrackProgress {
703
+ /**
704
+ * The level reached.
705
+ */
706
+ level: number;
707
+
708
+ /**
709
+ * XP earned towards the next level, in the game's own units.
710
+ */
711
+ xp: number;
712
+
713
+ /**
714
+ * XP the next level costs in total, from the start of this one. `xp / xpToNext` is the bar the character sheet draws.
715
+ */
716
+ xpToNext: number;
717
+
718
+ /**
719
+ * Unspent perk points in this track's tree.
720
+ */
721
+ perkPoints: number;
722
+ }
723
+
724
+ /**
725
+ * A player's level on every track, keyed by track name.
726
+ */
727
+ interface TrackLevels {
728
+ /**
729
+ * The level reached.
730
+ */
731
+ stealth: number;
732
+
733
+ /**
734
+ * The level reached.
735
+ */
736
+ horse_riding: number;
737
+
738
+ /**
739
+ * The level reached.
740
+ */
741
+ fencing: number;
742
+
743
+ /**
744
+ * The level reached.
745
+ */
746
+ thievery: number;
747
+
748
+ /**
749
+ * The level reached.
750
+ */
751
+ alchemy: number;
752
+
753
+ /**
754
+ * The level reached.
755
+ */
756
+ craftsmanship: number;
757
+
758
+ /**
759
+ * The level reached.
760
+ */
761
+ drinking: number;
762
+
763
+ /**
764
+ * The level reached.
765
+ */
766
+ survival: number;
767
+
768
+ /**
769
+ * The level reached.
770
+ */
771
+ weapon_sword: number;
772
+
773
+ /**
774
+ * The level reached.
775
+ */
776
+ heavy_weapons: number;
777
+
778
+ /**
779
+ * The level reached.
780
+ */
781
+ marksmanship: number;
782
+
783
+ /**
784
+ * The level reached.
785
+ */
786
+ weapon_large: number;
787
+
788
+ /**
789
+ * The level reached.
790
+ */
791
+ weapon_unarmed: number;
792
+
793
+ /**
794
+ * The level reached.
795
+ */
796
+ scholarship: number;
797
+
798
+ /**
799
+ * The level reached.
800
+ */
801
+ houndmaster: number;
802
+
803
+ /**
804
+ * The level reached.
805
+ */
806
+ strength: number;
807
+
808
+ /**
809
+ * The level reached.
810
+ */
811
+ agility: number;
812
+
813
+ /**
814
+ * The level reached.
815
+ */
816
+ vitality: number;
817
+
818
+ /**
819
+ * The level reached.
820
+ */
821
+ speech: number;
822
+
823
+ /**
824
+ * The level reached.
825
+ */
826
+ prestige: number;
827
+ }
828
+
829
+ /**
830
+ * Everything a server needs to put a player's progression back: plain JSON a resource can store however it likes. A player starts every session with a fresh character, so this is how progression outlives a disconnect.
831
+ */
832
+ interface ProgressionSnapshot {
833
+ /**
834
+ * Level and XP into the next level, per track name.
835
+ */
836
+ tracks: Record<string, { level: number; xp: number }>;
837
+
838
+ /**
839
+ * Every perk owned, by name.
840
+ */
841
+ perks: string[];
842
+
843
+ /**
844
+ * Unspent points per tree: track names, and `main`.
845
+ */
846
+ perkPoints: Record<string, number>;
847
+ }
848
+
497
849
  /**
498
850
  * The pace rule a server puts on one player. Both halves default to off, and a call to `setMovementMode` states both of them.
499
851
  */
@@ -761,6 +1113,26 @@ declare global {
761
1113
  */
762
1114
  readonly equipment: string[];
763
1115
 
1116
+ /**
1117
+ * The player's main level, the one the game derives from the stats, as their client last reported it. 0 until the first report.
1118
+ */
1119
+ readonly level: number;
1120
+
1121
+ /**
1122
+ * The level of every skill and stat, keyed by track name, as this server last accepted it. All zero until the first report.
1123
+ */
1124
+ readonly levels: TrackLevels;
1125
+
1126
+ /**
1127
+ * Every perk the player owns, by name.
1128
+ */
1129
+ readonly perks: string[];
1130
+
1131
+ /**
1132
+ * Everything about this player's progression, as plain JSON to store however the resource likes. A player starts every session with a fresh character, so `restoreProgression` with a stored snapshot is how progression outlives a disconnect. Null until their client's first report.
1133
+ */
1134
+ readonly progression: ProgressionSnapshot | null;
1135
+
764
1136
  /**
765
1137
  * Whether this player is in a saddle.
766
1138
  */
@@ -809,39 +1181,104 @@ declare global {
809
1181
  toString(): string;
810
1182
 
811
1183
  /**
812
- * Requests revival of this player after playerDied.
813
- * @returns True when sent; false when disconnected, no death was reported, or revival was already requested.
1184
+ * Where this player stands on one track: level, XP towards the next one, and unspent perk points.
1185
+ * @param track A track name, from `Progression.tracks()`.
1186
+ * @returns The progress, or null before their client's first report. Throws for a track name the tables do not carry.
814
1187
  */
815
- revive(): boolean;
1188
+ getTrack(track: string): TrackProgress | null;
816
1189
 
817
1190
  /**
818
- * Puts this player somewhere, as a spawn rather than as a teleport: their client holds the body still until there is real ground under it, so it cannot fall through a world that has not streamed in yet.
819
- *
820
- * Called from a `playerSpawning` handler this *is* the answer to that request -- the player is still behind their loading screen, and nothing is seen. Called at any other time it moves a player who is already in the world, which is visible.
821
- *
822
- * Nothing else names a spawn: with no handler calling this, everybody arrives at the level's own start point, because every client asks the game for the identical map start.
823
- * @param position Where the body goes; a Vector3 or any object carrying x, y and z.
824
- * @param rotation Which way they face: a Quaternion, or a Vector3 of Euler degrees.
825
- * @returns True when the placement was accepted; false for a position that is not somewhere in the world, or a player with no connection to ask.
1191
+ * Whether this player owns a perk.
1192
+ * @param perk A perk's name or GUID.
1193
+ * @returns True when their last report carried it.
826
1194
  */
827
- spawn(position: Vector3 | Partial<Vector3>, rotation?: Quaternion | Vector3): boolean;
1195
+ hasPerk(perk: string): boolean;
828
1196
 
829
1197
  /**
830
- * Asks this player's own client to put them somewhere else. The owning client is authoritative for its body's pose, so this is a request that lands on their next frame rather than a write.
831
- * @param position World-space destination; a Vector3 or any object carrying x, y and z.
832
- * @param label Optional name for the destination, echoed back in the client's own teleport panel. Display only.
833
- * @returns True when the request went out; false when the position is not finite or the player has no connection to ask.
1198
+ * Grants XP on one track, through the game's own path on the player's client -- so their perks' XP multipliers apply, a level crossed pops the game's own level-up, and a level grants its perk points. Rates, budgets and caps do not apply: those rule over what a player earns, and this is the server giving.
1199
+ * @param track A track name. Not `fencing`: the game derives it from the weapon skills.
1200
+ * @param xp XP, in the game's own units.
1201
+ * @returns True when the order went out. Throws for an unknown track or an xp that is not positive.
834
1202
  */
835
- teleport(position: Vector3 | Partial<Vector3>, label?: string): boolean;
1203
+ addXp(track: string, xp: number): boolean;
836
1204
 
837
1205
  /**
838
- * Makes this player's body play one of the game's animations, on their own screen and on everybody else's -- a wave, a bow, a woodcutter's swing with the axe in hand. It is state rather than a one-off: a player who streams in or joins while it plays sees it too, and it lasts until `stopAnimation` or the next `playAnimation`, even after a one-shot has finished.
839
- *
840
- * A new `playAnimation`, `stopAnimation` and `teleport` cut a running animation at once rather than waiting for it to finish. The game can cut it short too: a hit, a fall or drawing a weapon ends it, and so can the player walking off from one that leaves the legs free. `loop` starts it again when that happens, and keeps a one-shot going pass after pass with no gap between them.
841
- *
842
- * `playerAnimationEnd` fires once when the animation this request started is over, and says how. A loop ends only by being stopped or replaced.
843
- *
844
- * A hand tag is only half of holding something. `r_bucket` makes the body move as if it carried a bucket, but the bucket itself is a `props` entry.
1206
+ * Raises one track to a level, as the game's own `AdvanceToSkillLevel` does: exactly the XP between the two levels, with the level-ups and perk points on the way. The game has no way to lower a level, so asking for one below the current level throws.
1207
+ * @param track A track name. Not `fencing`.
1208
+ * @param level The level to raise it to, at most the game's cap of 30.
1209
+ * @returns True when the order went out; false for a level past the cap.
1210
+ */
1211
+ setLevel(track: string, level: number): boolean;
1212
+
1213
+ /**
1214
+ * Gives this player a perk outright, spending no point and skipping the perk screen's requirements. It still has to be one the game can add: an owned or blocked perk is turned down by the game itself.
1215
+ * @param perk A perk's name or GUID.
1216
+ * @returns True when the order went out. Throws for an unknown perk.
1217
+ */
1218
+ addPerk(perk: string): boolean;
1219
+
1220
+ /**
1221
+ * Takes a perk away. The point it cost is not refunded; `respecPerks` is the way to hand points back.
1222
+ * @param perk A perk's name or GUID.
1223
+ * @returns True when the order went out. Throws for an unknown perk.
1224
+ */
1225
+ removePerk(perk: string): boolean;
1226
+
1227
+ /**
1228
+ * Gives this player unspent perk points in one tree, on top of what their levels earned.
1229
+ * @param track The tree to add to: a track name, or `main` for the main-level bank.
1230
+ * @param count How many, from 1 to 65535.
1231
+ * @returns True when the order went out.
1232
+ */
1233
+ addPerkPoints(track: string, count: number): boolean;
1234
+
1235
+ /**
1236
+ * The game's own respec: every perk learnt on the perk screen is taken away and every tree's points are rebuilt from the player's current levels. Perks the game granted on its own stay.
1237
+ * @returns True when the order went out.
1238
+ */
1239
+ respecPerks(): boolean;
1240
+
1241
+ /**
1242
+ * Puts a stored progression back: levels, XP, perks and unspent points, through the game's own paths. Only ever raises -- a track already past the snapshot keeps its level -- so call it as the player arrives, from `playerReady`, on the fresh character every session starts with.
1243
+ * @param snapshot What `player.progression` returned, as the resource stored it.
1244
+ * @returns True when every order went out.
1245
+ */
1246
+ restoreProgression(snapshot: ProgressionSnapshot): boolean;
1247
+
1248
+ /**
1249
+ * Requests revival of this player after playerDied.
1250
+ * @returns True when sent; false when disconnected, no death was reported, or revival was already requested.
1251
+ */
1252
+ revive(): boolean;
1253
+
1254
+ /**
1255
+ * Puts this player somewhere, as a spawn rather than as a teleport: their client holds the body still until there is real ground under it, so it cannot fall through a world that has not streamed in yet.
1256
+ *
1257
+ * Called from a `playerSpawning` handler this *is* the answer to that request -- the player is still behind their loading screen, and nothing is seen. Called at any other time it moves a player who is already in the world, which is visible.
1258
+ *
1259
+ * Nothing else names a spawn: with no handler calling this, everybody arrives at the level's own start point, because every client asks the game for the identical map start.
1260
+ * @param position Where the body goes; a Vector3 or any object carrying x, y and z.
1261
+ * @param rotation Which way they face: a Quaternion, or a Vector3 of Euler degrees.
1262
+ * @returns True when the placement was accepted; false for a position that is not somewhere in the world, or a player with no connection to ask.
1263
+ */
1264
+ spawn(position: Vector3 | Partial<Vector3>, rotation?: Quaternion | Vector3): boolean;
1265
+
1266
+ /**
1267
+ * Asks this player's own client to put them somewhere else. The owning client is authoritative for its body's pose, so this is a request that lands on their next frame rather than a write.
1268
+ * @param position World-space destination; a Vector3 or any object carrying x, y and z.
1269
+ * @param label Optional name for the destination, echoed back in the client's own teleport panel. Display only.
1270
+ * @returns True when the request went out; false when the position is not finite or the player has no connection to ask.
1271
+ */
1272
+ teleport(position: Vector3 | Partial<Vector3>, label?: string): boolean;
1273
+
1274
+ /**
1275
+ * Makes this player's body play one of the game's animations, on their own screen and on everybody else's -- a wave, a bow, a woodcutter's swing with the axe in hand. It is state rather than a one-off: a player who streams in or joins while it plays sees it too, and it lasts until `stopAnimation` or the next `playAnimation`, even after a one-shot has finished.
1276
+ *
1277
+ * A new `playAnimation`, `stopAnimation` and `teleport` cut a running animation at once rather than waiting for it to finish. The game can cut it short too: a hit, a fall or drawing a weapon ends it, and so can the player walking off from one that leaves the legs free. `loop` starts it again when that happens, and keeps a one-shot going pass after pass with no gap between them.
1278
+ *
1279
+ * `playerAnimationEnd` fires once when the animation this request started is over, and says how. A loop ends only by being stopped or replaced.
1280
+ *
1281
+ * A hand tag is only half of holding something. `r_bucket` makes the body move as if it carried a bucket, but the bucket itself is a `props` entry.
845
1282
  * @param fragment A Mannequin fragment, as `Animations.list` names it. `""` plays none and only puts the props and tags on, which with a hand tag like `r_bucket` makes the player carry something while they walk.
846
1283
  * @param options `tags` pick the variant, `loop` repeats it until stopped, `lockMovement` holds the player still, `props` puts up to two models in their hands.
847
1284
  * @returns True when the request went out; false for a player with no body yet. Throws for a prop or option it cannot use.
@@ -906,25 +1343,34 @@ declare global {
906
1343
  setMovementMode(mode: Partial<MovementMode>): boolean;
907
1344
 
908
1345
  /**
909
- * Grants items into this player's inventory on their own client. The server holds no inventory of its own, so this is an instruction rather than a transfer.
1346
+ * Grants items into this player's inventory, which the server holds; their game shows them on the next tick. `Inventory.add` does the same and can also set the items' properties.
910
1347
  * @param item Item class GUID, or the exact name the game's own item tables use.
911
1348
  * @param amount How many to grant; defaults to 1, and at most 10000.
912
- * @returns True when the grant went out; false for an unknown item or an amount the wire refuses.
1349
+ * @returns True when the items were added; false for an unknown item, an amount outside 1..10000, or a player with no inventory.
913
1350
  */
914
1351
  giveItem(item: string, amount?: number): boolean;
915
1352
 
916
1353
  /**
917
- * Takes items back out of this player's inventory, on their own client -- the mirror of `giveItem`, and what makes a trade or a theft able to move in both directions.
918
- *
919
- * It is a promise rather than a boolean because a grant always lands and a take may not. The server holds no inventory of its own, so it cannot know what the player is carrying: it asks their client, and the answer is a round trip away. Await it, and read `ok` before crediting the other side of a trade -- a player who has only one of the three you asked for gives back `removed: 1, ok: false`, and their client is already one short.
920
- *
921
- * Across stacks of the same class, oldest first, and an item counts even while it is in the player's hand. Nothing else of theirs is touched.
1354
+ * Takes items of a class out of this player's inventory, across its rows, all of them or none. The server holds the inventory, so the promise is already settled when it is returned; it stays a promise so existing scripts keep working. To move items between players use `Inventory.transfer`, which cannot lose them half way.
922
1355
  * @param item Item class GUID, or the exact name the game's own item tables use. The same spelling `giveItem` takes.
923
1356
  * @param amount How many units to take; defaults to 1, and at most 10000. Zero is refused rather than read as "all of them".
924
- * @returns An object carrying `removed` (units that actually went), `requested` (what was asked for), `ok` (true only when the client answered and removed every unit), and `reason` (empty when it answered, otherwise what went wrong).
1357
+ * @returns An object carrying `removed` (the amount when it happened, otherwise 0), `requested`, `ok`, and `reason` (empty on success, otherwise the inventory code, such as `insufficientItems`).
925
1358
  */
926
1359
  takeItem(item: string, amount?: number): Promise<{ removed: number; requested: number; ok: boolean; reason: string }>;
927
1360
 
1361
+ /**
1362
+ * Moves this player's items into a container spawned at their body, as a death drop: `playerInventoryChanged` (reason `drop`) and `stashInventoryChanged` follow, then the container is anyone's to open. At most 128 rows go. What happens to it next -- who may loot it, when it goes -- is the script's.
1363
+ * @param options `keepEquipped` keeps the units their body wears or holds.
1364
+ * @returns The container, or null when there was nothing to drop or the player has no inventory.
1365
+ */
1366
+ dropInventory(options?: { keepEquipped?: boolean }): Stash | null;
1367
+
1368
+ /**
1369
+ * Reads this player's inventory; the same as `Inventory.get(player)`.
1370
+ * @returns A copy of it, or null for a player who is not connected.
1371
+ */
1372
+ getInventory(): InventoryState | null;
1373
+
928
1374
  /**
929
1375
  * Puts a status effect on this player's body. The server runs no effects of its own, so this asks their client rather than writing anything, and it lands a moment later -- `hasBuff` right after this call still says false. Watch `playerBuffAdded` for the moment it is really on.
930
1376
  *
@@ -999,6 +1445,172 @@ declare global {
999
1445
 
1000
1446
  interface Player extends BasePlayer {}
1001
1447
 
1448
+ /**
1449
+ * A count of units from one row.
1450
+ */
1451
+ interface InventoryUnit {
1452
+ /**
1453
+ * The row.
1454
+ */
1455
+ id: string;
1456
+
1457
+ /**
1458
+ * How many of its units.
1459
+ */
1460
+ amount: number;
1461
+ }
1462
+
1463
+ /**
1464
+ * A stack of one item class with one set of properties. Two rows never hold the same class with equal properties unless a restore put them there.
1465
+ */
1466
+ interface InventoryRow {
1467
+ /**
1468
+ * The row's identity within this player's inventory. Stable while the row exists; save it with the row and pass it back to `Inventory.set`.
1469
+ */
1470
+ id: string;
1471
+
1472
+ /**
1473
+ * Item class GUID.
1474
+ */
1475
+ item: string;
1476
+
1477
+ /**
1478
+ * The item's name in the game's own tables; not localized text.
1479
+ */
1480
+ name: string;
1481
+
1482
+ /**
1483
+ * Units in the row.
1484
+ */
1485
+ amount: number;
1486
+
1487
+ /**
1488
+ * Quality, from 1 up to the class's maximum. Same as `metadata.quality`.
1489
+ */
1490
+ quality: number;
1491
+
1492
+ /**
1493
+ * Absolute item health. Same as `metadata.health`.
1494
+ */
1495
+ health: number;
1496
+
1497
+ /**
1498
+ * Health as a fraction of what this quality allows, 0 to 1. Same as `metadata.condition`.
1499
+ */
1500
+ condition: number;
1501
+
1502
+ /**
1503
+ * Units of the row the player's body wears or holds, as their game last reported it. Only in `Inventory.get` and `player.getInventory()`; give it back to `Inventory.set` to dress a restored body.
1504
+ */
1505
+ equipped: number;
1506
+
1507
+ /**
1508
+ * Every property the server keeps: `quality`, `health`, `condition`, and on missiles `poison` (a buff GUID) and `poisonCharges`, and `onEquipBuffs` (buff GUIDs). A default is left out. Pass it back as it is to keep an item exactly.
1509
+ */
1510
+ metadata: Record<string, unknown>;
1511
+ }
1512
+
1513
+ /**
1514
+ * One player's inventory as the server holds it.
1515
+ */
1516
+ interface InventoryState {
1517
+ /**
1518
+ * The player's game shows this revision. False for a moment after every change, and until `playerInventoryReady`.
1519
+ */
1520
+ ready: boolean;
1521
+
1522
+ /**
1523
+ * Advances by one with every change. Pass it as a request's `revision` to refuse the request if anything changed in between.
1524
+ */
1525
+ revision: number;
1526
+
1527
+ /**
1528
+ * Every row.
1529
+ */
1530
+ items: InventoryRow[];
1531
+ }
1532
+
1533
+ /**
1534
+ * What one operation did to one player's inventory.
1535
+ */
1536
+ interface InventoryChange {
1537
+ /**
1538
+ * The revision the operation produced.
1539
+ */
1540
+ revision: number;
1541
+
1542
+ /**
1543
+ * `add`, `remove`, `properties`, `set`, `transfer`, `wear` when the player's game wore an item down in use, `use` for food, potions and ointments, `shot` for a fired round, `pickpocket`, `drop` for `player.dropInventory`, or the ground, stash and gathering reasons.
1544
+ */
1545
+ reason: string;
1546
+
1547
+ /**
1548
+ * Only the rows that changed. `before: null` is a new row and `after: null` an emptied one.
1549
+ */
1550
+ items: { id: string; before: InventoryRow | null; after: InventoryRow | null }[];
1551
+ }
1552
+
1553
+ /**
1554
+ * What an inventory operation did.
1555
+ */
1556
+ interface InventoryResult {
1557
+ /**
1558
+ * It happened. Nothing changes when it did not.
1559
+ */
1560
+ ok: boolean;
1561
+
1562
+ /**
1563
+ * Empty on success, otherwise why not: `inventoryUnavailable`, `invalidRequest`, `staleRevision`, `invalidItem`, `invalidItems`, `invalidAmount`, `unknownItem`, `insufficientItems`, `inventoryCapacity`, `sameInventory`, or a property policy code (`invalidMetadata`, `unknownItemClass`, `invalidQuality`, `immutableItemHealth`, `invalidItemHealth`, `contradictoryItemHealth`, `invalidCreationSentinel`, `unsupportedPoisonProperties`, `unsupportedOnEquipBuffs`).
1564
+ */
1565
+ code: string;
1566
+
1567
+ /**
1568
+ * The revision after the operation; for a transfer, the source's. 0 when refused.
1569
+ */
1570
+ revision: number;
1571
+
1572
+ /**
1573
+ * The rows that received units: the row an `add` merged into or created, a transfer's rows in the target, every row a `set` wrote. Empty for `remove`.
1574
+ */
1575
+ items: InventoryUnit[];
1576
+ }
1577
+
1578
+ /**
1579
+ * Player inventories. The server holds each connected player's items and their game shows them; nothing a player's game does adds an item. Every operation happens at once and in full, or not at all. `revision` is optional everywhere: give the one you read to refuse the operation when the inventory changed since.
1580
+ */
1581
+ const Inventory: {
1582
+ /**
1583
+ * Reads a player's inventory.
1584
+ * @returns A copy of it, or null for a player who is not connected.
1585
+ */
1586
+ get(player: Player): InventoryState | null;
1587
+
1588
+ /**
1589
+ * Gives a player items of a class, 1 to 10000 at a time. Left-out properties mean quality 1 at full condition. The units join the row that already holds this class with these properties, if there is one.
1590
+ */
1591
+ add(player: Player, request: { item: string; amount: number; metadata?: Record<string, unknown>; revision?: number }): InventoryResult;
1592
+
1593
+ /**
1594
+ * Takes exact units from named rows, every one of them or none.
1595
+ */
1596
+ remove(player: Player, request: { units: InventoryUnit[]; revision?: number }): InventoryResult;
1597
+
1598
+ /**
1599
+ * Replaces a row's properties. The row keeps its identity and amount. It replaces rather than merges: carry over anything you want to keep, and give `health` or `condition`, not two that disagree.
1600
+ */
1601
+ setProperties(player: Player, request: { id: string; metadata: Record<string, unknown>; revision?: number }): InventoryResult;
1602
+
1603
+ /**
1604
+ * Replaces a player's whole inventory, which is how a saved one comes back. Rows keep the ids they are given (letters, digits and `-_:.`, up to 64) and get new ones when they have none. `equipped` is how many units of a gear row the body wears, up to 48 in all; their game dresses in them. An empty list clears the inventory.
1605
+ */
1606
+ set(player: Player, request: { items: { id?: string; item: string; amount: number; metadata?: Record<string, unknown>; equipped?: number }[]; revision?: number }): InventoryResult;
1607
+
1608
+ /**
1609
+ * Moves exact units from one player to another with their properties, all or nothing. They join matching rows in the target, so the target's row ids are the ones in the result's `items`. Whether the two may trade -- distance, consent, price -- is for the script to decide.
1610
+ */
1611
+ transfer(source: Player, target: Player, request: { units: InventoryUnit[]; sourceRevision?: number; targetRevision?: number }): InventoryResult;
1612
+ };
1613
+
1002
1614
  /**
1003
1615
  * Replicated KCD2 horse handle.
1004
1616
  */
@@ -1049,6 +1661,21 @@ declare global {
1049
1661
  */
1050
1662
  readonly mounted: boolean;
1051
1663
 
1664
+ /**
1665
+ * Network ID of the player this horse belongs to, or 0 when it is nobody's. Not necessarily its rider.
1666
+ */
1667
+ readonly ownerId: number;
1668
+
1669
+ /**
1670
+ * The player this horse belongs to, or null when it is nobody's. Set with `giveTo`.
1671
+ */
1672
+ readonly owner: Player | null;
1673
+
1674
+ /**
1675
+ * Whether this horse is despawned when its owner disconnects. True by default. Set it to false to keep the horse in the world: it is left ownerless instead (`horseOwnerChanged` with a null player) until `giveTo` hands it to someone. Saving it across server restarts is the script's own business.
1676
+ */
1677
+ destroyWithOwner: boolean;
1678
+
1052
1679
  /**
1053
1680
  * Health, as the client running this horse last reported it off the animal's own soul -- 0 before any client has. Assigning sets it on that client, clamped to `maxHealth`; 0 kills. A dead horse ignores the write: `revive` is what brings one back.
1054
1681
  */
@@ -1085,6 +1712,12 @@ declare global {
1085
1712
  */
1086
1713
  destroy(): void;
1087
1714
 
1715
+ /**
1716
+ * Makes this horse another player's. Every client makes it that player's horse in the game's own terms -- theirs is never a stolen horse -- and `horseOwnerChanged` follows. Ownership decides nothing about who may ride it: that is `horseMounting`'s to refuse. Throws when `player` is not a connected player.
1717
+ * @param player The horse's new owner, or null to leave it ownerless.
1718
+ */
1719
+ giveTo(player: Player | null): void;
1720
+
1088
1721
  /**
1089
1722
  * Rears the horse on every client so it throws its rider off. The game's own animation, not a pose.
1090
1723
  * @returns True when the request went out; false when nobody is riding it.
@@ -1246,203 +1879,648 @@ declare global {
1246
1879
  update(session: number, page: DialoguePage): boolean;
1247
1880
 
1248
1881
  /**
1249
- * Ends a conversation and takes the list off that player's screen.
1250
- * @param session The session to end.
1251
- * @returns False when the session had already ended.
1882
+ * Ends a conversation and takes the list off that player's screen.
1883
+ * @param session The session to end.
1884
+ * @returns False when the session had already ended.
1885
+ */
1886
+ close(session: number): boolean;
1887
+
1888
+ /**
1889
+ * The conversation that player is in.
1890
+ * @param player NetworkID of the player to ask about.
1891
+ * @returns The session id, or 0 when they are not in one.
1892
+ */
1893
+ sessionOf(player: number): number;
1894
+ };
1895
+
1896
+ /**
1897
+ * How a vendor starts out.
1898
+ */
1899
+ interface VendorOptions {
1900
+ /**
1901
+ * Shown in the server's log only. The trade screen names whoever keeps the shop.
1902
+ */
1903
+ name: string | undefined;
1904
+
1905
+ /**
1906
+ * Money units the vendor starts with, and all it can pay out. Omit it for a purse that never runs out.
1907
+ */
1908
+ purse: number | undefined;
1909
+
1910
+ /**
1911
+ * Whether the vendor takes the player's items at all. On by default; `setBuyPrices` says which ones.
1912
+ */
1913
+ buys: boolean | undefined;
1914
+ }
1915
+
1916
+ /**
1917
+ * One thing a vendor sells.
1918
+ */
1919
+ interface VendorStockRow {
1920
+ /**
1921
+ * The item class, by GUID or by the game's own item name.
1922
+ */
1923
+ item: string;
1924
+
1925
+ /**
1926
+ * How many the vendor has. A row the players buy out disappears.
1927
+ */
1928
+ amount: number;
1929
+
1930
+ /**
1931
+ * What one costs, in money units -- the amount of the game's `money` item, which is also what `player.giveItem('money', n)` hands out.
1932
+ */
1933
+ price: number;
1934
+ }
1935
+
1936
+ /**
1937
+ * One thing a vendor buys from players.
1938
+ */
1939
+ interface VendorBuyRow {
1940
+ /**
1941
+ * The item class, by GUID or by the game's own item name.
1942
+ */
1943
+ item: string;
1944
+
1945
+ /**
1946
+ * What the vendor pays for one, in money units.
1947
+ */
1948
+ price: number;
1949
+ }
1950
+
1951
+ /**
1952
+ * One settled line of a deal.
1953
+ */
1954
+ interface VendorTradeLine {
1955
+ /**
1956
+ * The item class GUID.
1957
+ */
1958
+ item: string;
1959
+
1960
+ /**
1961
+ * The game's own name for the item class.
1962
+ */
1963
+ name: string;
1964
+
1965
+ /**
1966
+ * How many changed hands.
1967
+ */
1968
+ amount: number;
1969
+
1970
+ /**
1971
+ * What one was priced at when the deal settled.
1972
+ */
1973
+ price: number;
1974
+ }
1975
+
1976
+ /**
1977
+ * Price lists and purses the server owns, traded on the game's own shop screen.
1978
+ *
1979
+ * A vendor is attached to nothing: open one in front of a player from wherever the gamemode decides the counter is -- `npcInteract`, a dialogue option, a command. The screen is a preview. Its prices come from here, and pressing Trade sends a basket that the server re-prices, settles and moves itself; nothing the client shows is trusted.
1980
+ *
1981
+ * Prices count in money units, the amount of the game's `money` item.
1982
+ */
1983
+ const Vendor: {
1984
+ /**
1985
+ * Creates a vendor with nothing to sell and nothing it buys.
1986
+ * @param options Name, starting purse and whether it buys. All optional.
1987
+ * @returns The vendor id.
1988
+ */
1989
+ create(options?: VendorOptions): number;
1990
+
1991
+ /**
1992
+ * Closes every session at the vendor and forgets it. A deal already settling still completes.
1993
+ * @param vendor The vendor to remove.
1994
+ * @returns False when there was no such vendor.
1995
+ */
1996
+ destroy(vendor: number): boolean;
1997
+
1998
+ /**
1999
+ * Replaces what a vendor sells. Every player with its screen open sees the new shelf straight away, and a basket priced against the old one is refused.
2000
+ * @param vendor The vendor to stock.
2001
+ * @param rows Everything it sells, at most 128 rows and each item class once. Replaces the old list.
2002
+ * @returns False when there is no such vendor.
2003
+ */
2004
+ setStock(vendor: number, rows: VendorStockRow[]): boolean;
2005
+
2006
+ /**
2007
+ * Replaces what a vendor buys from players and what it pays. Anything not listed is shown at no value and a basket selling it is refused.
2008
+ * @param vendor The vendor to change.
2009
+ * @param rows Everything it buys, at most 128 rows and each item class once. Replaces the old list.
2010
+ * @returns False when there is no such vendor.
2011
+ */
2012
+ setBuyPrices(vendor: number, rows: VendorBuyRow[]): boolean;
2013
+
2014
+ /**
2015
+ * Sets what a vendor can pay out. Deals keep it current: what players pay goes in, what they are paid comes out.
2016
+ * @param vendor The vendor to change.
2017
+ * @param purse Money units it holds, or null for a purse that never runs out.
2018
+ * @returns False when there is no such vendor.
2019
+ */
2020
+ setPurse(vendor: number, purse: number | null): boolean;
2021
+
2022
+ /**
2023
+ * What a vendor holds.
2024
+ * @param vendor The vendor to ask about.
2025
+ * @returns Money units, or null for a purse that never runs out or a vendor that does not exist.
2026
+ */
2027
+ getPurse(vendor: number): number | null;
2028
+
2029
+ /**
2030
+ * Opens the game's own trade screen on a player. A player already trading has that session closed with reason 2 first, because the game has one trade screen.
2031
+ * @param vendor The vendor to trade with.
2032
+ * @param player NetworkID of the player to show it to.
2033
+ * @param npc NetworkID of the NPC who keeps the shop. The screen shows that NPC as the trader; omit it to trade with nobody in particular.
2034
+ * @returns The session id, or 0 when the vendor or the player is gone.
2035
+ */
2036
+ open(vendor: number, player: number, npc?: number): number;
2037
+
2038
+ /**
2039
+ * Takes the trade screen off that player.
2040
+ * @param session The session to end.
2041
+ * @returns False when the session had already ended.
2042
+ */
2043
+ close(session: number): boolean;
2044
+
2045
+ /**
2046
+ * The trading session a player is in.
2047
+ * @param player NetworkID of the player to ask about.
2048
+ * @returns The session id, or 0 when they are not trading.
2049
+ */
2050
+ sessionOf(player: number): number;
2051
+
2052
+ /**
2053
+ * The vendor a session trades with.
2054
+ * @param session The session to ask about.
2055
+ * @returns The vendor id, or 0 when the session has ended.
2056
+ */
2057
+ vendorOf(session: number): number;
2058
+ };
2059
+
2060
+ /**
2061
+ * One item class that left a victim's pockets for a thief's.
2062
+ */
2063
+ interface PickpocketLine {
2064
+ /**
2065
+ * The item class GUID.
2066
+ */
2067
+ item: string;
2068
+
2069
+ /**
2070
+ * The game's own name for the item class.
2071
+ */
2072
+ name: string;
2073
+
2074
+ /**
2075
+ * How many moved.
2076
+ */
2077
+ amount: number;
2078
+ }
2079
+
2080
+ /**
2081
+ * A table a player is about to open. Frozen: a handler can refuse it, not change it.
2082
+ */
2083
+ interface CraftStartProposal {
2084
+ /**
2085
+ * Station id, as `Crafting.stations` names it.
2086
+ */
2087
+ station: string;
2088
+
2089
+ /**
2090
+ * The player's virtual world; each world has its own tables.
2091
+ */
2092
+ virtualWorld: number;
2093
+
2094
+ /**
2095
+ * The batch this one follows at a table the player kept, or empty for a fresh entry.
2096
+ */
2097
+ continuationOf: string;
2098
+ }
2099
+
2100
+ /**
2101
+ * A batch that is now brewing: the table's opening animation finished, or the next batch started at a table the player kept.
2102
+ */
2103
+ interface CraftStartedEvent {
2104
+ /**
2105
+ * The batch's session id.
2106
+ */
2107
+ session: string;
2108
+
2109
+ /**
2110
+ * Station id.
2111
+ */
2112
+ station: string;
2113
+
2114
+ /**
2115
+ * The table's virtual world.
2116
+ */
2117
+ virtualWorld: number;
2118
+
2119
+ /**
2120
+ * The previous batch at this table, or empty for the first.
2121
+ */
2122
+ continuationOf: string;
2123
+ }
2124
+
2125
+ /**
2126
+ * What a finished batch is about to grant, computed by the server. Frozen: a handler can refuse it, not change it.
2127
+ */
2128
+ interface CraftCompletionProposal {
2129
+ /**
2130
+ * The batch's session id.
2131
+ */
2132
+ session: string;
2133
+
2134
+ /**
2135
+ * Station id.
2136
+ */
2137
+ station: string;
2138
+
2139
+ /**
2140
+ * `failed` brews the game's failed potion.
2141
+ */
2142
+ outcome: 'success' | 'failed';
2143
+
2144
+ /**
2145
+ * The recipe the brew matched, or empty when it matched none.
2146
+ */
2147
+ recipe: string;
2148
+
2149
+ /**
2150
+ * The product's native rank.
2151
+ */
2152
+ grade: number;
2153
+
2154
+ /**
2155
+ * Item class GUID of what would be granted, or empty when the yield came out at zero.
2156
+ */
2157
+ product: string;
2158
+
2159
+ /**
2160
+ * How many.
2161
+ */
2162
+ amount: number;
2163
+
2164
+ /**
2165
+ * Brewing quality, 0 to 1, after perks and the table-entry bonus.
2166
+ */
2167
+ quality: number;
2168
+
2169
+ /**
2170
+ * Base alchemy XP; the player's own multipliers apply on top.
2171
+ */
2172
+ xp: number;
2173
+ }
2174
+
2175
+ /**
2176
+ * A batch whose result was granted: the output is in the inventory and the XP was ordered.
2177
+ */
2178
+ interface CraftCompletedEvent {
2179
+ /**
2180
+ * The batch's session id.
2181
+ */
2182
+ session: string;
2183
+
2184
+ /**
2185
+ * Station id.
2186
+ */
2187
+ station: string;
2188
+
2189
+ /**
2190
+ * The table's virtual world.
2191
+ */
2192
+ virtualWorld: number;
2193
+
2194
+ /**
2195
+ * `failed` granted the game's failed potion.
2196
+ */
2197
+ outcome: 'success' | 'failed';
2198
+
2199
+ /**
2200
+ * The recipe matched, or empty.
2201
+ */
2202
+ recipe: string;
2203
+
2204
+ /**
2205
+ * The product's native rank.
2206
+ */
2207
+ grade: number;
2208
+
2209
+ /**
2210
+ * Brewing quality, 0 to 1.
2211
+ */
2212
+ quality: number;
2213
+
2214
+ /**
2215
+ * Base alchemy XP ordered.
2216
+ */
2217
+ xp: number;
2218
+
2219
+ /**
2220
+ * The inventory rows that received the output. Do not grant it again.
2221
+ */
2222
+ outputs: InventoryUnit[];
2223
+
2224
+ /**
2225
+ * The player's recipe knowledge after this batch, as `Crafting.knowledge` returns it.
2226
+ */
2227
+ knowledge: Record<string, number>;
2228
+ }
2229
+
2230
+ /**
2231
+ * A batch that is over, for any reason. A table kept for the next batch is not closed by this.
2232
+ */
2233
+ interface CraftEndedEvent {
2234
+ /**
2235
+ * The batch's session id.
2236
+ */
2237
+ session: string;
2238
+
2239
+ /**
2240
+ * Station id.
2241
+ */
2242
+ station: string;
2243
+
2244
+ /**
2245
+ * The table's virtual world.
2246
+ */
2247
+ virtualWorld: number;
2248
+
2249
+ /**
2250
+ * How it ended.
2251
+ */
2252
+ outcome: 'success' | 'failed' | 'cancelled';
2253
+
2254
+ /**
2255
+ * Empty for a completed batch. `craftingCompletingRejected` when a handler refused the result; `cancelled` by the player or a script; `disconnected`; `timeout` after 30 minutes; `contextInvalidated` when the player walked away, died or changed world.
2256
+ */
2257
+ reason: string;
2258
+
2259
+ /**
2260
+ * The inventory rows ingredients went back to. Wholly unmilled bowl, mortar and herb groups come back; everything else put on the table was spent.
2261
+ */
2262
+ refunded: InventoryUnit[];
2263
+ }
2264
+
2265
+ /**
2266
+ * Units required by a shipped recipe.
2267
+ */
2268
+ interface CraftMaterialRequirement {
2269
+ /**
2270
+ * Item class GUID.
2271
+ */
2272
+ item: string;
2273
+
2274
+ /**
2275
+ * Native item name, useful with Player.giveItem.
2276
+ */
2277
+ name: string;
2278
+
2279
+ /**
2280
+ * Units required for one attempt.
2281
+ */
2282
+ amount: number;
2283
+ }
2284
+
2285
+ /**
2286
+ * One possible product row. These are alternatives, not a reward list.
2287
+ */
2288
+ interface CraftProductInfo {
2289
+ /**
2290
+ * Product class GUID.
2291
+ */
2292
+ item: string;
2293
+
2294
+ /**
2295
+ * Alchemy product rank or smithing minimum quality percent.
2296
+ */
2297
+ threshold: number;
2298
+
2299
+ /**
2300
+ * Alchemy base maximum yield before modifiers; one for smithing.
2301
+ */
2302
+ maxYield: number;
2303
+ }
2304
+
2305
+ /**
2306
+ * Shipped recipe data allowed by server DLC policy. Presence is not proof of player knowledge, skill, quest eligibility or materials.
2307
+ */
2308
+ interface CraftRecipeInfo {
2309
+ /**
2310
+ * Tagged native recipe identity.
2311
+ */
2312
+ key: { kind: 'alchemy'; id: number } | { kind: 'smithing'; id: string };
2313
+
2314
+ /**
2315
+ * Localization key from the native table.
2316
+ */
2317
+ name: string;
2318
+
2319
+ /**
2320
+ * Native DLC id; zero for untagged content.
2321
+ */
2322
+ dlcId: number;
2323
+
2324
+ /**
2325
+ * Minimum craftsmanship skill, or zero for alchemy.
2326
+ */
2327
+ minSkill: number;
2328
+
2329
+ /**
2330
+ * Smithing recipe unlock perk GUID, empty for alchemy.
2331
+ */
2332
+ perk: string;
2333
+
2334
+ /**
2335
+ * Alchemy base liquid, empty for smithing. Supplied by the station.
2336
+ */
2337
+ base: string;
2338
+
2339
+ /**
2340
+ * Required ingredient quantities.
2341
+ */
2342
+ ingredients: CraftMaterialRequirement[];
2343
+
2344
+ /**
2345
+ * Possible products by native rank or threshold.
2346
+ */
2347
+ products: CraftProductInfo[];
2348
+ }
2349
+
2350
+ /**
2351
+ * An authored station in the configured level. The catalog does not guarantee that its quest layer is loaded or that native use is currently permitted.
2352
+ */
2353
+ interface CraftStationInfo {
2354
+ /**
2355
+ * Level and stable placement GUID.
2356
+ */
2357
+ id: string;
2358
+
2359
+ /**
2360
+ * The station's recipe family.
1252
2361
  */
1253
- close(session: number): boolean;
2362
+ kind: 'alchemy' | 'smithing';
1254
2363
 
1255
2364
  /**
1256
- * The conversation that player is in.
1257
- * @param player NetworkID of the player to ask about.
1258
- * @returns The session id, or 0 when they are not in one.
2365
+ * Level directory name.
1259
2366
  */
1260
- sessionOf(player: number): number;
1261
- };
2367
+ level: string;
1262
2368
 
1263
- /**
1264
- * How a vendor starts out.
1265
- */
1266
- interface VendorOptions {
1267
2369
  /**
1268
- * Shown in the server's log only. The trade screen names whoever keeps the shop.
2370
+ * Authored editor layer, for identifying the location.
1269
2371
  */
1270
- name: string | undefined;
2372
+ layer: string;
1271
2373
 
1272
2374
  /**
1273
- * Money units the vendor starts with, and all it can pay out. Omit it for a purse that never runs out.
2375
+ * World position of the station.
1274
2376
  */
1275
- purse: number | undefined;
2377
+ position: { x: number; y: number; z: number };
1276
2378
 
1277
2379
  /**
1278
- * Whether the vendor takes the player's items at all. On by default; `setBuyPrices` says which ones.
2380
+ * Horizontal facing direction.
1279
2381
  */
1280
- buys: boolean | undefined;
2382
+ forward: { x: number; y: number };
1281
2383
  }
1282
2384
 
1283
2385
  /**
1284
- * One thing a vendor sells.
2386
+ * Who holds an alchemy table. A player keeps it between batches until they leave it.
1285
2387
  */
1286
- interface VendorStockRow {
2388
+ interface CraftStationOccupant {
1287
2389
  /**
1288
- * The item class, by GUID or by the game's own item name.
2390
+ * The player's id.
1289
2391
  */
1290
- item: string;
2392
+ playerId: number;
1291
2393
 
1292
2394
  /**
1293
- * How many the vendor has. A row the players buy out disappears.
2395
+ * The first batch of this visit; the same across every batch of it.
1294
2396
  */
1295
- amount: number;
2397
+ entryId: string;
1296
2398
 
1297
2399
  /**
1298
- * What one costs, in money units -- the amount of the game's `money` item, which is also what `player.giveItem('money', n)` hands out.
2400
+ * The batch now running, or the last one to finish.
1299
2401
  */
1300
- price: number;
1301
- }
2402
+ sessionId: string;
1302
2403
 
1303
- /**
1304
- * One thing a vendor buys from players.
1305
- */
1306
- interface VendorBuyRow {
1307
2404
  /**
1308
- * The item class, by GUID or by the game's own item name.
2405
+ * `entering` until the opening animation finishes; `finishing` while a finished batch waits to settle.
1309
2406
  */
1310
- item: string;
2407
+ phase: 'entering' | 'brewing' | 'finishing' | 'betweenBatches';
1311
2408
 
1312
2409
  /**
1313
- * What the vendor pays for one, in money units.
2410
+ * Milliseconds until the table is taken back. Each batch has 30 minutes.
1314
2411
  */
1315
- price: number;
2412
+ expiresInMs: number;
1316
2413
  }
1317
2414
 
1318
2415
  /**
1319
- * One settled line of a deal.
2416
+ * One table in one virtual world. A free table may still be unusable in the game, for instance behind a quest layer.
1320
2417
  */
1321
- interface VendorTradeLine {
2418
+ interface CraftStationOccupancy {
1322
2419
  /**
1323
- * The item class GUID.
2420
+ * Station id.
1324
2421
  */
1325
- item: string;
2422
+ station: string;
1326
2423
 
1327
2424
  /**
1328
- * The game's own name for the item class.
2425
+ * The virtual world asked about.
1329
2426
  */
1330
- name: string;
2427
+ virtualWorld: number;
1331
2428
 
1332
2429
  /**
1333
- * How many changed hands.
2430
+ * Someone holds it, brewing or between batches.
1334
2431
  */
1335
- amount: number;
2432
+ occupied: boolean;
1336
2433
 
1337
2434
  /**
1338
- * What one was priced at when the deal settled.
2435
+ * Who, or null when free.
1339
2436
  */
1340
- price: number;
2437
+ occupant: CraftStationOccupant | null;
1341
2438
  }
1342
2439
 
1343
2440
  /**
1344
- * Price lists and purses the server owns, traded on the game's own shop screen.
1345
- *
1346
- * A vendor is attached to nothing: open one in front of a player from wherever the gamemode decides the counter is -- `npcInteract`, a dialogue option, a command. The screen is a preview. Its prices come from here, and pressing Trade sends a basket that the server re-prices, settles and moves itself; nothing the client shows is trusted.
1347
- *
1348
- * Prices count in money units, the amount of the game's `money` item.
2441
+ * A player's alchemy session, or the table they kept between batches. A copy: changing it changes nothing.
1349
2442
  */
1350
- const Vendor: {
2443
+ interface CraftSessionInfo {
1351
2444
  /**
1352
- * Creates a vendor with nothing to sell and nothing it buys.
1353
- * @param options Name, starting purse and whether it buys. All optional.
1354
- * @returns The vendor id.
2445
+ * The batch's session id.
1355
2446
  */
1356
- create(options?: VendorOptions): number;
2447
+ id: string;
1357
2448
 
1358
2449
  /**
1359
- * Closes every session at the vendor and forgets it. A deal already settling still completes.
1360
- * @param vendor The vendor to remove.
1361
- * @returns False when there was no such vendor.
2450
+ * Station id.
1362
2451
  */
1363
- destroy(vendor: number): boolean;
2452
+ station: string;
1364
2453
 
1365
2454
  /**
1366
- * Replaces what a vendor sells. Every player with its screen open sees the new shelf straight away, and a basket priced against the old one is refused.
1367
- * @param vendor The vendor to stock.
1368
- * @param rows Everything it sells, at most 128 rows and each item class once. Replaces the old list.
1369
- * @returns False when there is no such vendor.
2455
+ * The table's virtual world.
1370
2456
  */
1371
- setStock(vendor: number, rows: VendorStockRow[]): boolean;
2457
+ virtualWorld: number;
1372
2458
 
1373
2459
  /**
1374
- * Replaces what a vendor buys from players and what it pays. Anything not listed is shown at no value and a basket selling it is refused.
1375
- * @param vendor The vendor to change.
1376
- * @param rows Everything it buys, at most 128 rows and each item class once. Replaces the old list.
1377
- * @returns False when there is no such vendor.
2460
+ * Where the batch is.
1378
2461
  */
1379
- setBuyPrices(vendor: number, rows: VendorBuyRow[]): boolean;
2462
+ phase: 'entering' | 'brewing' | 'finishing' | 'betweenBatches';
1380
2463
 
1381
2464
  /**
1382
- * Sets what a vendor can pay out. Deals keep it current: what players pay goes in, what they are paid comes out.
1383
- * @param vendor The vendor to change.
1384
- * @param purse Money units it holds, or null for a purse that never runs out.
1385
- * @returns False when there is no such vendor.
2465
+ * Native actions accepted so far.
1386
2466
  */
1387
- setPurse(vendor: number, purse: number | null): boolean;
2467
+ sequence: number;
1388
2468
 
1389
2469
  /**
1390
- * What a vendor holds.
1391
- * @param vendor The vendor to ask about.
1392
- * @returns Money units, or null for a purse that never runs out or a vendor that does not exist.
2470
+ * What is on the table: item class, the inventory row it came from (empty for a base liquid), and the native table position.
1393
2471
  */
1394
- getPurse(vendor: number): number | null;
2472
+ resources: { id: number; item: string; itemId: string; position: number; base: boolean; milled: boolean; distilled: boolean }[];
1395
2473
 
1396
2474
  /**
1397
- * Opens the game's own trade screen on a player. A player already trading has that session closed with reason 2 first, because the game has one trade screen.
1398
- * @param vendor The vendor to trade with.
1399
- * @param player NetworkID of the player to show it to.
1400
- * @param npc NetworkID of the NPC who keeps the shop. The screen shows that NPC as the trader; omit it to trade with nobody in particular.
1401
- * @returns The session id, or 0 when the vendor or the player is gone.
2475
+ * Milliseconds until the session times out.
1402
2476
  */
1403
- open(vendor: number, player: number, npc?: number): number;
2477
+ expiresInMs: number;
2478
+ }
1404
2479
 
2480
+ /**
2481
+ * Crafting catalogs, alchemy table occupancy, sessions and recipe knowledge. Held in memory for each connection; nothing is saved.
2482
+ */
2483
+ const Crafting: {
1405
2484
  /**
1406
- * Takes the trade screen off that player.
1407
- * @param session The session to end.
1408
- * @returns False when the session had already ended.
2485
+ * True for alchemy, false for smithing, which is not synchronized yet. Omitted kind checks alchemy.
1409
2486
  */
1410
- close(session: number): boolean;
2487
+ isAvailable(kind?: 'alchemy' | 'smithing'): boolean;
1411
2488
 
1412
2489
  /**
1413
- * The trading session a player is in.
1414
- * @param player NetworkID of the player to ask about.
1415
- * @returns The session id, or 0 when they are not trading.
2490
+ * Placed stations in this server's level. Does not load deferred layers or bypass quests.
1416
2491
  */
1417
- sessionOf(player: number): number;
2492
+ stations(kind?: 'alchemy' | 'smithing'): readonly CraftStationInfo[];
1418
2493
 
1419
2494
  /**
1420
- * The vendor a session trades with.
1421
- * @param session The session to ask about.
1422
- * @returns The vendor id, or 0 when the session has ended.
2495
+ * Production recipes enabled by server DLC policy. The player must be connected but does not change the list. Catalog presence does not establish knowledge or skill.
1423
2496
  */
1424
- vendorOf(session: number): number;
1425
- };
2497
+ recipes(player: Player, kind?: 'alchemy' | 'smithing'): readonly CraftRecipeInfo[];
1426
2498
 
1427
- /**
1428
- * One item class that left a victim's pockets for a thief's.
1429
- */
1430
- interface PickpocketLine {
1431
2499
  /**
1432
- * The item class GUID.
2500
+ * The player's alchemy session or the table they kept between batches, or null.
1433
2501
  */
1434
- item: string;
2502
+ session(player: Player): CraftSessionInfo | null;
1435
2503
 
1436
2504
  /**
1437
- * The game's own name for the item class.
2505
+ * Who holds a table. World defaults to 0. Null for an unknown or non-alchemy station.
1438
2506
  */
1439
- name: string;
2507
+ occupancy(stationId: string, virtualWorld?: number): CraftStationOccupancy | null;
1440
2508
 
1441
2509
  /**
1442
- * How many moved.
2510
+ * Ends the player's session as leaving the table would: wholly unmilled groups go back to the inventory, the rest is spent, the table is released and their game closes it. `craftingEnded` follows next tick. False when there was nothing to end.
1443
2511
  */
1444
- amount: number;
1445
- }
2512
+ cancel(player: Player): boolean;
2513
+
2514
+ /**
2515
+ * The player's recipe knowledge: recipe id to a mask of its 29 authored steps, 536870911 when the whole recipe is known. A recipe not listed is unknown. Starts empty every session; save it from `craftingCompleted` or here and restore it with `setKnowledge`.
2516
+ */
2517
+ knowledge(player: Player): Record<string, number>;
2518
+
2519
+ /**
2520
+ * Sets which steps of one recipe the player knows, and sends it to their game's recipe book. 0 forgets the recipe. False for an unknown recipe, a mask above 536870911, or a player who is not connected.
2521
+ */
2522
+ setKnowledge(player: Player, recipeId: string | number, mask: number): boolean;
2523
+ };
1446
2524
 
1447
2525
  /**
1448
2526
  * Replicated KCD2 dog companion handle.
@@ -1474,6 +2552,11 @@ declare global {
1474
2552
  */
1475
2553
  readonly owner: Player | null;
1476
2554
 
2555
+ /**
2556
+ * Whether this dog is despawned when its owner disconnects. True by default. Set it to false to keep the dog in the world: it is left masterless instead (`dogOwnerChanged` with a null player), and with nobody's game running its brain it stands where it was until `giveTo` hands it to someone. Saving it across server restarts is the script's own business.
2557
+ */
2558
+ destroyWithOwner: boolean;
2559
+
1477
2560
  /**
1478
2561
  * The dog's companion mode: 0 Wait, 1 Follow, 2 Free, 3 Aggressive, 4 Search, 5 Hunt, 6 Guard, 7 Ambush. Assignment applies it on every client.
1479
2562
  */
@@ -1501,7 +2584,7 @@ declare global {
1501
2584
  destroy(): void;
1502
2585
 
1503
2586
  /**
1504
- * Hands this dog to another player. Every client re-possesses the body onto the new master's soul, and authority over its pose moves with it.
2587
+ * Hands this dog to another player. Every client re-possesses the body onto the new master's soul, and authority over its pose moves with it. Throws when `player` is not a connected player.
1505
2588
  * @param player The dog's new master, or null to leave it masterless.
1506
2589
  */
1507
2590
  giveTo(player: Player | null): void;
@@ -2399,7 +3482,7 @@ declare global {
2399
3482
  readonly condition: number;
2400
3483
 
2401
3484
  /**
2402
- * Whether the stack has settled where it will stay. A stack a script spawned is resting from the start; one a player threw down is false until that player's own physics stops it and publishes the final pose, and its position moves until then.
3485
+ * Whether the stack has settled where it will stay. A stack a script spawned is resting from the start; one a player dropped is false while the nearest client simulates its fall, and its position moves until then. A resting stack's pose is the server's and does not move again.
2403
3486
  */
2404
3487
  readonly resting: boolean;
2405
3488
 
@@ -2459,6 +3542,71 @@ declare global {
2459
3542
 
2460
3543
  interface GroundItem extends Entity {}
2461
3544
 
3545
+ /**
3546
+ * A plant a player picked and what it is about to give them.
3547
+ */
3548
+ interface GatheringProposal {
3549
+ /**
3550
+ * Item class GUID of the herb.
3551
+ */
3552
+ item: string;
3553
+
3554
+ /**
3555
+ * How many, as the game computes it from the player's survival level and the plants harvested together.
3556
+ */
3557
+ amount: number;
3558
+
3559
+ /**
3560
+ * The game's pickable area id for the plant.
3561
+ */
3562
+ kind: number;
3563
+
3564
+ /**
3565
+ * Where the plant grows, as the player's game reported it.
3566
+ */
3567
+ position: number[];
3568
+
3569
+ /**
3570
+ * The player's virtual world.
3571
+ */
3572
+ virtualWorld: number;
3573
+ }
3574
+
3575
+ /**
3576
+ * A plant a player picked, and what they were given.
3577
+ */
3578
+ interface GatheringHarvestedEvent {
3579
+ /**
3580
+ * Item class GUID of the herb.
3581
+ */
3582
+ item: string;
3583
+
3584
+ /**
3585
+ * How many.
3586
+ */
3587
+ amount: number;
3588
+
3589
+ /**
3590
+ * The game's pickable area id for the plant.
3591
+ */
3592
+ kind: number;
3593
+
3594
+ /**
3595
+ * Where the plant grows.
3596
+ */
3597
+ position: number[];
3598
+
3599
+ /**
3600
+ * The player's virtual world.
3601
+ */
3602
+ virtualWorld: number;
3603
+
3604
+ /**
3605
+ * The inventory rows that received the herb.
3606
+ */
3607
+ items: InventoryUnit[];
3608
+ }
3609
+
2462
3610
  /** */
2463
3611
  interface NearestDoor {
2464
3612
  /**
@@ -2754,10 +3902,15 @@ declare global {
2754
3902
  readonly name: string;
2755
3903
 
2756
3904
  /**
2757
- * How many stacks the server is holding. Contents are not replicated -- they are pulled when a player opens the container and pushed back when they close it -- so this is the only view of what is in one. A container linked to another in the level opens that one's contents, and reads them here too.
3905
+ * How many rows the server is holding. A container linked to another in the level opens that one's contents, and reads them here too.
2758
3906
  */
2759
3907
  readonly itemCount: number;
2760
3908
 
3909
+ /**
3910
+ * Whether a player has it open. Every client animates the lid by it.
3911
+ */
3912
+ readonly isOpen: boolean;
3913
+
2761
3914
  /**
2762
3915
  * The network ID of the player who has its contents open, or 0. While it is held, every other player's open is refused before their transfer screen appears.
2763
3916
  */
@@ -2805,7 +3958,28 @@ declare global {
2805
3958
  destroy(): void;
2806
3959
 
2807
3960
  /**
2808
- * Spawns and replicates an empty container. Empty by design: an item class is a 16-byte engine GUID only the game's own parser turns from text, and the server has no game to ask. Fill one by having a player put things in it.
3961
+ * Reads what the container holds. A linked child reads its master's.
3962
+ * @returns A copy of its rows, or null once the container is gone.
3963
+ */
3964
+ getInventory(): { revision: number; items: InventoryRow[] } | null;
3965
+
3966
+ /**
3967
+ * Puts items in the container, as `Inventory.add` gives them to a player.
3968
+ */
3969
+ addItem(request: { item: string; amount: number; metadata?: Record<string, unknown>; revision?: number }): InventoryResult;
3970
+
3971
+ /**
3972
+ * Takes exact units out of named rows, every one of them or none.
3973
+ */
3974
+ removeItem(request: { units: InventoryUnit[]; revision?: number }): InventoryResult;
3975
+
3976
+ /**
3977
+ * Replaces everything in the container, which is how saved contents come back. At most 128 rows. An empty list empties it.
3978
+ */
3979
+ setInventory(request: { items: { id?: string; item: string; amount: number; metadata?: Record<string, unknown> }[]; revision?: number }): InventoryResult;
3980
+
3981
+ /**
3982
+ * Spawns and replicates an empty container. Fill it with `addItem` or `setInventory`, or let players put things in it.
2809
3983
  * @param position Optional world-space spawn position; omitted components default to zero.
2810
3984
  * @param rotation Optional initial orientation: a Quaternion, or a Vector3 of Euler angles in degrees.
2811
3985
  * @param virtualWorld Optional virtual world the container belongs to; omitted puts it in the global one.
@@ -3248,6 +4422,94 @@ declare global {
3248
4422
  claim(classNames: string[]): string[];
3249
4423
  };
3250
4424
 
4425
+ /**
4426
+ * The game's skills, stats and perks, and the rules this server puts on how players move along them.
4427
+ */
4428
+ const Progression: {
4429
+ /**
4430
+ * Whether players' own games may earn XP. See `setNativeXp`.
4431
+ */
4432
+ readonly nativeXp: boolean;
4433
+
4434
+ /**
4435
+ * The perks this server blocks.
4436
+ */
4437
+ readonly blockedPerks: string[];
4438
+
4439
+ /**
4440
+ * Every skill and stat a player levels: the fifteen skills the character sheet shows, then strength, agility, vitality, speech and prestige.
4441
+ * @returns The tracks, in that order.
4442
+ */
4443
+ tracks(): TrackInfo[];
4444
+
4445
+ /**
4446
+ * Looks a perk up.
4447
+ * @param query A perk's name, as the game's perk tables spell it, or its GUID.
4448
+ * @returns What the tables say about it, or null for a name they do not carry.
4449
+ */
4450
+ findPerk(query: string): PerkInfo | null;
4451
+
4452
+ /**
4453
+ * Lists the game's perks: 945 of them, most of them hidden system perks. `Progression.perks({ visibleOnly: true })` is the perk screen.
4454
+ * @param filter `track` keeps the perks one tree pays for -- a track name, or `main`; `visibleOnly` keeps the perks the perk screen shows.
4455
+ * @returns The perks, sorted by name.
4456
+ */
4457
+ perks(filter?: { track?: string; visibleOnly?: boolean }): PerkInfo[];
4458
+
4459
+ /**
4460
+ * The total XP a track costs from level 0 to `level`, on the game's own curve: each level costs `base + diff * level`, with base and diff from the game's RPG tables.
4461
+ * @param track A track name.
4462
+ * @param level The level to reach.
4463
+ * @returns The XP. Throws for a track name the tables do not carry.
4464
+ */
4465
+ xpForLevel(track: string, level: number): number;
4466
+
4467
+ /**
4468
+ * Switches off XP from play. Every gain the game produces is dropped on the player's own client, and only `player.addXp` and `player.setLevel` move a track -- for servers where progression comes from jobs, trainers or quests a resource runs.
4469
+ * @param enabled False to stop players' own games from earning XP at all.
4470
+ * @returns Nothing.
4471
+ */
4472
+ setNativeXp(enabled: boolean): void;
4473
+
4474
+ /**
4475
+ * Scales the XP players earn by playing. Applied before the player's own perk multipliers, which still work as they do in single player. `player.addXp` is not scaled.
4476
+ * @param track A track name, or `*` for every track.
4477
+ * @param rate What a gain is multiplied by before it is granted: 1 is the game's own pace, 0.5 half, 0 none at all.
4478
+ * @returns Nothing.
4479
+ */
4480
+ setXpRate(track: string, rate: number): void;
4481
+
4482
+ /**
4483
+ * Limits how fast a track can be ground. The budget holds a minute's worth and refills steadily, so a burst after a quiet spell goes through and a loop -- two players sparring for sword XP, a lock picked over and over -- runs dry. `player.addXp` is not limited.
4484
+ * @param track A track name, or `*` for every track.
4485
+ * @param xpPerMinute How much XP a player may earn on the track per minute, before multipliers. 0 is unlimited.
4486
+ * @returns Nothing.
4487
+ */
4488
+ setXpBudget(track: string, xpPerMinute: number): void;
4489
+
4490
+ /**
4491
+ * Stops a track at a level. Gains close to it are granted exactly what is left, so no multiplier carries the track past it. `player.setLevel` and `player.addXp` can still go beyond: the cap rules over what is earned.
4492
+ * @param track A track name, or `*` for every track.
4493
+ * @param level The highest level XP from play may reach, at most the game's own 30.
4494
+ * @returns Nothing.
4495
+ */
4496
+ setLevelCap(track: string, level: number): void;
4497
+
4498
+ /**
4499
+ * Makes perks unobtainable: the perk screen's learn is refused, the game's own grants are turned down on every client, and a report carrying one is rejected. `player.addPerk` still works.
4500
+ * @param perks Perk names or GUIDs.
4501
+ * @returns Nothing. Throws for an unknown perk.
4502
+ */
4503
+ blockPerks(perks: string[]): void;
4504
+
4505
+ /**
4506
+ * Lifts `blockPerks`.
4507
+ * @param perks Perk names or GUIDs.
4508
+ * @returns Nothing. Throws for an unknown perk.
4509
+ */
4510
+ unblockPerks(perks: string[]): void;
4511
+ };
4512
+
3251
4513
  /**
3252
4514
  * The game's own character-component catalog: every face, hairstyle, beard and skin a player's body can be given.
3253
4515
  *
@@ -4536,6 +5798,59 @@ declare global {
4536
5798
  isPlayerTalking(player: Entity): boolean;
4537
5799
  };
4538
5800
 
5801
+ /**
5802
+ * A player asking to join, handed to `playerConnecting`. Every identifier is reported by the player's own client and is not verified by the server.
5803
+ */
5804
+ interface PendingConnection {
5805
+ /**
5806
+ * The name the player asked to join under.
5807
+ */
5808
+ readonly nickname: string;
5809
+
5810
+ /**
5811
+ * Steam identifier the client reported, or an empty string when it had none.
5812
+ */
5813
+ readonly steamId: string;
5814
+
5815
+ /**
5816
+ * Discord identifier the client reported, or an empty string when it had none.
5817
+ */
5818
+ readonly discordId: string;
5819
+
5820
+ /**
5821
+ * Framework hardware identifier the client reported, or an empty string when it had none.
5822
+ */
5823
+ readonly hardwareId: string;
5824
+
5825
+ /**
5826
+ * The string the client was launched with, as the `ticket` of its launch link, or an empty string. The framework passes it through untouched; checking it -- against a one-time join ticket your own launcher or website issued, typically -- is the script's job.
5827
+ */
5828
+ readonly ticket: string;
5829
+
5830
+ /**
5831
+ * The remote address the connection comes from, without its port.
5832
+ */
5833
+ readonly ip: string;
5834
+
5835
+ /**
5836
+ * Turns the player away before they receive anything. Takes effect on the next server tick, whatever other handlers are still doing. Does nothing once the connection is decided or the player has left.
5837
+ * @param reason Shown to the player as written, up to 512 bytes. Omitted, they read that the server refused the connection.
5838
+ */
5839
+ reject(reason?: string): void;
5840
+
5841
+ /**
5842
+ * Shows the waiting player a line of status and restarts the admission timeout, so a queue that keeps updating its players is never timed out. Does nothing once the connection is decided or the player has left.
5843
+ * @param message One line for the player's connecting screen, up to 256 bytes: 'Checking the whitelist', 'You are 4th in the queue'.
5844
+ */
5845
+ update(message: string): void;
5846
+
5847
+ /**
5848
+ * Checks whether this connection is still waiting on a decision.
5849
+ * @returns False once it was let in or turned away, or the player gave up and left; a queue drops such entries.
5850
+ */
5851
+ isPending(): boolean;
5852
+ }
5853
+
4539
5854
  /**
4540
5855
  * Base handle for a live replicated network entity.
4541
5856
  */