@kingdomsconnected/types 1.5.1 → 1.5.3

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
  */
@@ -146,7 +168,7 @@ declare global {
146
168
  dialogueClosed: [session: number, player: Player, reason: number];
147
169
 
148
170
  /**
149
- * Dispatched once a deal has settled: everything in it has already moved. `balance` is what the player came out with in money units -- positive when the vendor paid them. What the player sold does not join the vendor's stock; add it with `setStock` here if this vendor resells.
171
+ * Dispatched once a deal has settled: everything in it has already moved, in one commit on the player's inventory whose playerInventoryChanged reason is `trade`. `balance` is what the player came out with in money units -- positive when the vendor paid them. What the player sold does not join the vendor's stock; add it with `setStock` here if this vendor resells.
150
172
  */
151
173
  vendorTrade: [vendor: number, player: Player, bought: VendorTradeLine[], sold: VendorTradeLine[], balance: number];
152
174
 
@@ -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
  */
@@ -202,6 +249,31 @@ declare global {
202
249
  */
203
250
  propDestroy: [prop: Prop];
204
251
 
252
+ /**
253
+ * Dispatched immediately after a cart is created and replicated, whether by `Cart.spawn`, the `/cart` command, or anything else.
254
+ */
255
+ cartSpawn: [cart: Cart];
256
+
257
+ /**
258
+ * Dispatched while a cart is being despawned, after everyone in it has been let out. The handle still resolves, so its blueprint and its pose can be read one last time.
259
+ */
260
+ cartDestroy: [cart: Cart];
261
+
262
+ /**
263
+ * Dispatched before a player is put in a seat -- by their own use of the cart's prompt, or `putPlayer`. Return `false` from a handler and the seat is refused: nothing changes, and the player's game never climbs in. Handlers run synchronously.
264
+ */
265
+ cartEntering: [cart: Cart, player: Player, seat: string];
266
+
267
+ /**
268
+ * Dispatched after a player is given a seat. `seat` is `driver` or `back`; a driver's client runs the cart from here on.
269
+ */
270
+ cartEnter: [cart: Cart, player: Player | null, seat: string];
271
+
272
+ /**
273
+ * Dispatched after a player leaves a seat: their own climb down, `removePlayer`, a disconnect, or the cart being destroyed.
274
+ */
275
+ cartExit: [cart: Cart, player: Player | null, seat: string];
276
+
205
277
  /**
206
278
  * Dispatched immediately after a replicated particle effect is placed, whether by `Vfx.spawn`, a command, or anything else.
207
279
  */
@@ -298,11 +370,46 @@ declare global {
298
370
  groundItemPickup: [groundItem: GroundItem, player: Player | null];
299
371
 
300
372
  /**
301
- * 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.
373
+ * 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.
374
+ */
375
+ gatheringHarvest: [player: Player, proposal: GatheringProposal];
376
+
377
+ /**
378
+ * 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.
379
+ */
380
+ gatheringHarvested: [player: Player, event: GatheringHarvestedEvent];
381
+
382
+ /**
383
+ * Dispatched when a player's client reports working a door, before the server applies it. `action` is `open`, `close`, `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
384
  *
303
385
  * Return false to refuse it: the door is put back on every client, the player's included, and nobody else sees it happen. Every handler runs whatever an earlier one returned, and an async handler cannot refuse. The server has already refused what the game's own rules forbid -- a player out of reach, a door the server locked, opening a locked door, picking a door with no keyhole -- so this only sees what the game would allow.
304
386
  */
305
- doorInteract: [player: Player, door: Door, action: "open" | "close" | "lock" | "unlock" | "lockpick", keySide: boolean];
387
+ doorInteract: [player: Player, door: Door, action: "open" | "close" | "unlock" | "lockpick", keySide: boolean];
388
+
389
+ /**
390
+ * 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()`.
391
+ */
392
+ stashSpawn: [stash: Stash];
393
+
394
+ /**
395
+ * A player opened a container and sees what it holds.
396
+ */
397
+ stashOpen: [stash: Stash, player: Player];
398
+
399
+ /**
400
+ * 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.
401
+ */
402
+ stashClose: [stash: Stash, player: Player, reason: "closed" | "lostAccess" | "timeout" | "disconnected" | "destroyed"];
403
+
404
+ /**
405
+ * 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.
406
+ */
407
+ stashInventoryChanged: [stash: Stash, player: Player | null, change: InventoryChange];
408
+
409
+ /**
410
+ * A container is about to go. Raised after its close and its contents' removal, while it can still be read.
411
+ */
412
+ stashDestroy: [stash: Stash];
306
413
 
307
414
  /**
308
415
  * 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.
@@ -346,6 +453,41 @@ declare global {
346
453
  */
347
454
  playerBuffBlocked: [player: Player, buff: string];
348
455
 
456
+ /**
457
+ * 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.
458
+ */
459
+ playerXpGaining: [player: Player, track: string, xp: number, source: string];
460
+
461
+ /**
462
+ * Dispatched when XP landed on a player's character, from their game or from this server, after every multiplier.
463
+ */
464
+ playerXpGained: [player: Player, track: string, xp: number];
465
+
466
+ /**
467
+ * Dispatched when one of a player's tracks reaches a new level. `perkPoints` is what that track's tree now has unspent.
468
+ */
469
+ playerLevelUp: [player: Player, track: string, level: number, perkPoints: number];
470
+
471
+ /**
472
+ * 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`.
473
+ */
474
+ playerPerkLearning: [player: Player, perk: string];
475
+
476
+ /**
477
+ * 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.
478
+ */
479
+ playerPerkAdded: [player: Player, perk: string, source: "learned" | "server" | "native"];
480
+
481
+ /**
482
+ * Dispatched when a perk left a player's character: taken or respecced by this server, or removed by the game.
483
+ */
484
+ playerPerkRemoved: [player: Player, perk: string, source: "server" | "native"];
485
+
486
+ /**
487
+ * 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.
488
+ */
489
+ playerProgressionRejected: [player: Player, reason: string];
490
+
349
491
  /**
350
492
  * Dispatched after a resource entry point has run and immediately before the resource becomes running.
351
493
  */
@@ -360,6 +502,16 @@ declare global {
360
502
  * 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
503
  */
362
504
  entityStateChange: [entity: Entity, key: string, value: any, previous: any];
505
+
506
+ /**
507
+ * 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.
508
+ */
509
+ consoleCommand: [command: string, args: string[]];
510
+
511
+ /**
512
+ * 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.
513
+ */
514
+ playerConnecting: [connection: PendingConnection];
363
515
  }
364
516
 
365
517
  /** Names of native events available in this scripting environment. */
@@ -494,6 +646,231 @@ declare global {
494
646
  unarmed: number;
495
647
  }
496
648
 
649
+ /**
650
+ * One skill or stat a player levels, as the game's own tables describe it.
651
+ */
652
+ interface TrackInfo {
653
+ /**
654
+ * The name every progression verb takes, as the game's tables spell it: `weapon_sword`, `thievery`, `strength`.
655
+ */
656
+ name: string;
657
+
658
+ /**
659
+ * Whether it is a skill or one of the stats the skills sit on.
660
+ */
661
+ kind: "skill" | "stat";
662
+
663
+ /**
664
+ * The highest level the game lets it reach.
665
+ */
666
+ cap: number;
667
+
668
+ /**
669
+ * True for fencing alone: it is never earned, the game derives it from the five weapon skills, so XP handed to it is refused.
670
+ */
671
+ induced: boolean;
672
+ }
673
+
674
+ /**
675
+ * One perk, as the game's own perk tables describe it.
676
+ */
677
+ interface PerkInfo {
678
+ /**
679
+ * The perk's `perk_name`, unique across the tables, and the spelling every perk verb takes alongside its GUID.
680
+ */
681
+ name: string;
682
+
683
+ /**
684
+ * The perk's GUID.
685
+ */
686
+ id: string;
687
+
688
+ /**
689
+ * The localisation key the perk screen shows, or empty for a perk it never shows.
690
+ */
691
+ uiName: string;
692
+
693
+ /**
694
+ * 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.
695
+ */
696
+ track: string | null;
697
+
698
+ /**
699
+ * The level that track has to reach before the perk can be learnt. 0 for none.
700
+ */
701
+ level: number;
702
+
703
+ /**
704
+ * The perk that has to be owned first, or null.
705
+ */
706
+ parent: string | null;
707
+
708
+ /**
709
+ * `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.
710
+ */
711
+ visibility: "system" | "hidden" | "visible" | "obsolete";
712
+
713
+ /**
714
+ * 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.
715
+ */
716
+ kinds: string[];
717
+
718
+ /**
719
+ * Whether the game grants it on its own once its requirements are met, rather than on the perk screen.
720
+ */
721
+ autolearnable: boolean;
722
+ }
723
+
724
+ /**
725
+ * Where a player stands on one track.
726
+ */
727
+ interface TrackProgress {
728
+ /**
729
+ * The level reached.
730
+ */
731
+ level: number;
732
+
733
+ /**
734
+ * XP earned towards the next level, in the game's own units.
735
+ */
736
+ xp: number;
737
+
738
+ /**
739
+ * XP the next level costs in total, from the start of this one. `xp / xpToNext` is the bar the character sheet draws.
740
+ */
741
+ xpToNext: number;
742
+
743
+ /**
744
+ * Unspent perk points in this track's tree.
745
+ */
746
+ perkPoints: number;
747
+ }
748
+
749
+ /**
750
+ * A player's level on every track, keyed by track name.
751
+ */
752
+ interface TrackLevels {
753
+ /**
754
+ * The level reached.
755
+ */
756
+ stealth: number;
757
+
758
+ /**
759
+ * The level reached.
760
+ */
761
+ horse_riding: number;
762
+
763
+ /**
764
+ * The level reached.
765
+ */
766
+ fencing: number;
767
+
768
+ /**
769
+ * The level reached.
770
+ */
771
+ thievery: number;
772
+
773
+ /**
774
+ * The level reached.
775
+ */
776
+ alchemy: number;
777
+
778
+ /**
779
+ * The level reached.
780
+ */
781
+ craftsmanship: number;
782
+
783
+ /**
784
+ * The level reached.
785
+ */
786
+ drinking: number;
787
+
788
+ /**
789
+ * The level reached.
790
+ */
791
+ survival: number;
792
+
793
+ /**
794
+ * The level reached.
795
+ */
796
+ weapon_sword: number;
797
+
798
+ /**
799
+ * The level reached.
800
+ */
801
+ heavy_weapons: number;
802
+
803
+ /**
804
+ * The level reached.
805
+ */
806
+ marksmanship: number;
807
+
808
+ /**
809
+ * The level reached.
810
+ */
811
+ weapon_large: number;
812
+
813
+ /**
814
+ * The level reached.
815
+ */
816
+ weapon_unarmed: number;
817
+
818
+ /**
819
+ * The level reached.
820
+ */
821
+ scholarship: number;
822
+
823
+ /**
824
+ * The level reached.
825
+ */
826
+ houndmaster: number;
827
+
828
+ /**
829
+ * The level reached.
830
+ */
831
+ strength: number;
832
+
833
+ /**
834
+ * The level reached.
835
+ */
836
+ agility: number;
837
+
838
+ /**
839
+ * The level reached.
840
+ */
841
+ vitality: number;
842
+
843
+ /**
844
+ * The level reached.
845
+ */
846
+ speech: number;
847
+
848
+ /**
849
+ * The level reached.
850
+ */
851
+ prestige: number;
852
+ }
853
+
854
+ /**
855
+ * 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.
856
+ */
857
+ interface ProgressionSnapshot {
858
+ /**
859
+ * Level and XP into the next level, per track name.
860
+ */
861
+ tracks: Record<string, { level: number; xp: number }>;
862
+
863
+ /**
864
+ * Every perk owned, by name.
865
+ */
866
+ perks: string[];
867
+
868
+ /**
869
+ * Unspent points per tree: track names, and `main`.
870
+ */
871
+ perkPoints: Record<string, number>;
872
+ }
873
+
497
874
  /**
498
875
  * The pace rule a server puts on one player. Both halves default to off, and a call to `setMovementMode` states both of them.
499
876
  */
@@ -761,6 +1138,26 @@ declare global {
761
1138
  */
762
1139
  readonly equipment: string[];
763
1140
 
1141
+ /**
1142
+ * The player's main level, the one the game derives from the stats, as their client last reported it. 0 until the first report.
1143
+ */
1144
+ readonly level: number;
1145
+
1146
+ /**
1147
+ * The level of every skill and stat, keyed by track name, as this server last accepted it. All zero until the first report.
1148
+ */
1149
+ readonly levels: TrackLevels;
1150
+
1151
+ /**
1152
+ * Every perk the player owns, by name.
1153
+ */
1154
+ readonly perks: string[];
1155
+
1156
+ /**
1157
+ * 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.
1158
+ */
1159
+ readonly progression: ProgressionSnapshot | null;
1160
+
764
1161
  /**
765
1162
  * Whether this player is in a saddle.
766
1163
  */
@@ -809,18 +1206,83 @@ declare global {
809
1206
  toString(): string;
810
1207
 
811
1208
  /**
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.
1209
+ * Where this player stands on one track: level, XP towards the next one, and unspent perk points.
1210
+ * @param track A track name, from `Progression.tracks()`.
1211
+ * @returns The progress, or null before their client's first report. Throws for a track name the tables do not carry.
814
1212
  */
815
- revive(): boolean;
1213
+ getTrack(track: string): TrackProgress | null;
816
1214
 
817
1215
  /**
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.
1216
+ * Whether this player owns a perk.
1217
+ * @param perk A perk's name or GUID.
1218
+ * @returns True when their last report carried it.
1219
+ */
1220
+ hasPerk(perk: string): boolean;
1221
+
1222
+ /**
1223
+ * 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.
1224
+ * @param track A track name. Not `fencing`: the game derives it from the weapon skills.
1225
+ * @param xp XP, in the game's own units.
1226
+ * @returns True when the order went out. Throws for an unknown track or an xp that is not positive.
1227
+ */
1228
+ addXp(track: string, xp: number): boolean;
1229
+
1230
+ /**
1231
+ * 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.
1232
+ * @param track A track name. Not `fencing`.
1233
+ * @param level The level to raise it to, at most the game's cap of 30.
1234
+ * @returns True when the order went out; false for a level past the cap.
1235
+ */
1236
+ setLevel(track: string, level: number): boolean;
1237
+
1238
+ /**
1239
+ * 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.
1240
+ * @param perk A perk's name or GUID.
1241
+ * @returns True when the order went out. Throws for an unknown perk.
1242
+ */
1243
+ addPerk(perk: string): boolean;
1244
+
1245
+ /**
1246
+ * Takes a perk away. The point it cost is not refunded; `respecPerks` is the way to hand points back.
1247
+ * @param perk A perk's name or GUID.
1248
+ * @returns True when the order went out. Throws for an unknown perk.
1249
+ */
1250
+ removePerk(perk: string): boolean;
1251
+
1252
+ /**
1253
+ * Gives this player unspent perk points in one tree, on top of what their levels earned.
1254
+ * @param track The tree to add to: a track name, or `main` for the main-level bank.
1255
+ * @param count How many, from 1 to 65535.
1256
+ * @returns True when the order went out.
1257
+ */
1258
+ addPerkPoints(track: string, count: number): boolean;
1259
+
1260
+ /**
1261
+ * 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.
1262
+ * @returns True when the order went out.
1263
+ */
1264
+ respecPerks(): boolean;
1265
+
1266
+ /**
1267
+ * 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.
1268
+ * @param snapshot What `player.progression` returned, as the resource stored it.
1269
+ * @returns True when every order went out.
1270
+ */
1271
+ restoreProgression(snapshot: ProgressionSnapshot): boolean;
1272
+
1273
+ /**
1274
+ * Requests revival of this player after playerDied.
1275
+ * @returns True when sent; false when disconnected, no death was reported, or revival was already requested.
1276
+ */
1277
+ revive(): boolean;
1278
+
1279
+ /**
1280
+ * 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.
1281
+ *
1282
+ * 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.
1283
+ *
1284
+ * 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.
1285
+ * @param position Where the body goes; a Vector3 or any object carrying x, y and z.
824
1286
  * @param rotation Which way they face: a Quaternion, or a Vector3 of Euler degrees.
825
1287
  * @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.
826
1288
  */
@@ -906,25 +1368,34 @@ declare global {
906
1368
  setMovementMode(mode: Partial<MovementMode>): boolean;
907
1369
 
908
1370
  /**
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.
1371
+ * 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
1372
  * @param item Item class GUID, or the exact name the game's own item tables use.
911
1373
  * @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.
1374
+ * @returns True when the items were added; false for an unknown item, an amount outside 1..10000, or a player with no inventory.
913
1375
  */
914
1376
  giveItem(item: string, amount?: number): boolean;
915
1377
 
916
1378
  /**
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.
1379
+ * 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
1380
  * @param item Item class GUID, or the exact name the game's own item tables use. The same spelling `giveItem` takes.
923
1381
  * @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).
1382
+ * @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
1383
  */
926
1384
  takeItem(item: string, amount?: number): Promise<{ removed: number; requested: number; ok: boolean; reason: string }>;
927
1385
 
1386
+ /**
1387
+ * 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.
1388
+ * @param options `keepEquipped` keeps the units their body wears or holds.
1389
+ * @returns The container, or null when there was nothing to drop or the player has no inventory.
1390
+ */
1391
+ dropInventory(options?: { keepEquipped?: boolean }): Stash | null;
1392
+
1393
+ /**
1394
+ * Reads this player's inventory; the same as `Inventory.get(player)`.
1395
+ * @returns A copy of it, or null for a player who is not connected.
1396
+ */
1397
+ getInventory(): InventoryState | null;
1398
+
928
1399
  /**
929
1400
  * 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
1401
  *
@@ -999,6 +1470,172 @@ declare global {
999
1470
 
1000
1471
  interface Player extends BasePlayer {}
1001
1472
 
1473
+ /**
1474
+ * A count of units from one row.
1475
+ */
1476
+ interface InventoryUnit {
1477
+ /**
1478
+ * The row.
1479
+ */
1480
+ id: string;
1481
+
1482
+ /**
1483
+ * How many of its units.
1484
+ */
1485
+ amount: number;
1486
+ }
1487
+
1488
+ /**
1489
+ * 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.
1490
+ */
1491
+ interface InventoryRow {
1492
+ /**
1493
+ * 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`.
1494
+ */
1495
+ id: string;
1496
+
1497
+ /**
1498
+ * Item class GUID.
1499
+ */
1500
+ item: string;
1501
+
1502
+ /**
1503
+ * The item's name in the game's own tables; not localized text.
1504
+ */
1505
+ name: string;
1506
+
1507
+ /**
1508
+ * Units in the row.
1509
+ */
1510
+ amount: number;
1511
+
1512
+ /**
1513
+ * Quality, from 1 up to the class's maximum. Same as `metadata.quality`.
1514
+ */
1515
+ quality: number;
1516
+
1517
+ /**
1518
+ * Absolute item health. Same as `metadata.health`.
1519
+ */
1520
+ health: number;
1521
+
1522
+ /**
1523
+ * Health as a fraction of what this quality allows, 0 to 1. Same as `metadata.condition`.
1524
+ */
1525
+ condition: number;
1526
+
1527
+ /**
1528
+ * 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.
1529
+ */
1530
+ equipped: number;
1531
+
1532
+ /**
1533
+ * 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.
1534
+ */
1535
+ metadata: Record<string, unknown>;
1536
+ }
1537
+
1538
+ /**
1539
+ * One player's inventory as the server holds it.
1540
+ */
1541
+ interface InventoryState {
1542
+ /**
1543
+ * The player's game shows this revision. False for a moment after every change, and until `playerInventoryReady`.
1544
+ */
1545
+ ready: boolean;
1546
+
1547
+ /**
1548
+ * Advances by one with every change. Pass it as a request's `revision` to refuse the request if anything changed in between.
1549
+ */
1550
+ revision: number;
1551
+
1552
+ /**
1553
+ * Every row.
1554
+ */
1555
+ items: InventoryRow[];
1556
+ }
1557
+
1558
+ /**
1559
+ * What one operation did to one player's inventory.
1560
+ */
1561
+ interface InventoryChange {
1562
+ /**
1563
+ * The revision the operation produced.
1564
+ */
1565
+ revision: number;
1566
+
1567
+ /**
1568
+ * `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`, `trade` for a vendor deal, `drop` for `player.dropInventory`, or the ground, stash and gathering reasons.
1569
+ */
1570
+ reason: string;
1571
+
1572
+ /**
1573
+ * Only the rows that changed. `before: null` is a new row and `after: null` an emptied one.
1574
+ */
1575
+ items: { id: string; before: InventoryRow | null; after: InventoryRow | null }[];
1576
+ }
1577
+
1578
+ /**
1579
+ * What an inventory operation did.
1580
+ */
1581
+ interface InventoryResult {
1582
+ /**
1583
+ * It happened. Nothing changes when it did not.
1584
+ */
1585
+ ok: boolean;
1586
+
1587
+ /**
1588
+ * 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`).
1589
+ */
1590
+ code: string;
1591
+
1592
+ /**
1593
+ * The revision after the operation; for a transfer, the source's. 0 when refused.
1594
+ */
1595
+ revision: number;
1596
+
1597
+ /**
1598
+ * 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`.
1599
+ */
1600
+ items: InventoryUnit[];
1601
+ }
1602
+
1603
+ /**
1604
+ * 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.
1605
+ */
1606
+ const Inventory: {
1607
+ /**
1608
+ * Reads a player's inventory.
1609
+ * @returns A copy of it, or null for a player who is not connected.
1610
+ */
1611
+ get(player: Player): InventoryState | null;
1612
+
1613
+ /**
1614
+ * 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.
1615
+ */
1616
+ add(player: Player, request: { item: string; amount: number; metadata?: Record<string, unknown>; revision?: number }): InventoryResult;
1617
+
1618
+ /**
1619
+ * Takes exact units from named rows, every one of them or none.
1620
+ */
1621
+ remove(player: Player, request: { units: InventoryUnit[]; revision?: number }): InventoryResult;
1622
+
1623
+ /**
1624
+ * 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.
1625
+ */
1626
+ setProperties(player: Player, request: { id: string; metadata: Record<string, unknown>; revision?: number }): InventoryResult;
1627
+
1628
+ /**
1629
+ * 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.
1630
+ */
1631
+ set(player: Player, request: { items: { id?: string; item: string; amount: number; metadata?: Record<string, unknown>; equipped?: number }[]; revision?: number }): InventoryResult;
1632
+
1633
+ /**
1634
+ * 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.
1635
+ */
1636
+ transfer(source: Player, target: Player, request: { units: InventoryUnit[]; sourceRevision?: number; targetRevision?: number }): InventoryResult;
1637
+ };
1638
+
1002
1639
  /**
1003
1640
  * Replicated KCD2 horse handle.
1004
1641
  */
@@ -1049,6 +1686,21 @@ declare global {
1049
1686
  */
1050
1687
  readonly mounted: boolean;
1051
1688
 
1689
+ /**
1690
+ * Network ID of the player this horse belongs to, or 0 when it is nobody's. Not necessarily its rider.
1691
+ */
1692
+ readonly ownerId: number;
1693
+
1694
+ /**
1695
+ * The player this horse belongs to, or null when it is nobody's. Set with `giveTo`.
1696
+ */
1697
+ readonly owner: Player | null;
1698
+
1699
+ /**
1700
+ * 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.
1701
+ */
1702
+ destroyWithOwner: boolean;
1703
+
1052
1704
  /**
1053
1705
  * 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
1706
  */
@@ -1085,6 +1737,12 @@ declare global {
1085
1737
  */
1086
1738
  destroy(): void;
1087
1739
 
1740
+ /**
1741
+ * 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.
1742
+ * @param player The horse's new owner, or null to leave it ownerless.
1743
+ */
1744
+ giveTo(player: Player | null): void;
1745
+
1088
1746
  /**
1089
1747
  * Rears the horse on every client so it throws its rider off. The game's own animation, not a pose.
1090
1748
  * @returns True when the request went out; false when nobody is riding it.
@@ -1356,7 +2014,7 @@ declare global {
1356
2014
  create(options?: VendorOptions): number;
1357
2015
 
1358
2016
  /**
1359
- * Closes every session at the vendor and forgets it. A deal already settling still completes.
2017
+ * Closes every session at the vendor and forgets it. A deal settles the moment its basket arrives, so none is ever left half done.
1360
2018
  * @param vendor The vendor to remove.
1361
2019
  * @returns False when there was no such vendor.
1362
2020
  */
@@ -1368,81 +2026,526 @@ declare global {
1368
2026
  * @param rows Everything it sells, at most 128 rows and each item class once. Replaces the old list.
1369
2027
  * @returns False when there is no such vendor.
1370
2028
  */
1371
- setStock(vendor: number, rows: VendorStockRow[]): boolean;
2029
+ setStock(vendor: number, rows: VendorStockRow[]): boolean;
2030
+
2031
+ /**
2032
+ * 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.
2033
+ * @param vendor The vendor to change.
2034
+ * @param rows Everything it buys, at most 128 rows and each item class once. Replaces the old list.
2035
+ * @returns False when there is no such vendor.
2036
+ */
2037
+ setBuyPrices(vendor: number, rows: VendorBuyRow[]): boolean;
2038
+
2039
+ /**
2040
+ * Sets what a vendor can pay out. Deals keep it current: what players pay goes in, what they are paid comes out.
2041
+ * @param vendor The vendor to change.
2042
+ * @param purse Money units it holds, or null for a purse that never runs out.
2043
+ * @returns False when there is no such vendor.
2044
+ */
2045
+ setPurse(vendor: number, purse: number | null): boolean;
2046
+
2047
+ /**
2048
+ * What a vendor holds.
2049
+ * @param vendor The vendor to ask about.
2050
+ * @returns Money units, or null for a purse that never runs out or a vendor that does not exist.
2051
+ */
2052
+ getPurse(vendor: number): number | null;
2053
+
2054
+ /**
2055
+ * 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.
2056
+ * @param vendor The vendor to trade with.
2057
+ * @param player NetworkID of the player to show it to.
2058
+ * @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.
2059
+ * @returns The session id, or 0 when the vendor or the player is gone.
2060
+ */
2061
+ open(vendor: number, player: number, npc?: number): number;
2062
+
2063
+ /**
2064
+ * Takes the trade screen off that player.
2065
+ * @param session The session to end.
2066
+ * @returns False when the session had already ended.
2067
+ */
2068
+ close(session: number): boolean;
2069
+
2070
+ /**
2071
+ * The trading session a player is in.
2072
+ * @param player NetworkID of the player to ask about.
2073
+ * @returns The session id, or 0 when they are not trading.
2074
+ */
2075
+ sessionOf(player: number): number;
2076
+
2077
+ /**
2078
+ * The vendor a session trades with.
2079
+ * @param session The session to ask about.
2080
+ * @returns The vendor id, or 0 when the session has ended.
2081
+ */
2082
+ vendorOf(session: number): number;
2083
+ };
2084
+
2085
+ /**
2086
+ * One item class that left a victim's pockets for a thief's.
2087
+ */
2088
+ interface PickpocketLine {
2089
+ /**
2090
+ * The item class GUID.
2091
+ */
2092
+ item: string;
2093
+
2094
+ /**
2095
+ * The game's own name for the item class.
2096
+ */
2097
+ name: string;
2098
+
2099
+ /**
2100
+ * How many moved.
2101
+ */
2102
+ amount: number;
2103
+ }
2104
+
2105
+ /**
2106
+ * A table a player is about to open. Frozen: a handler can refuse it, not change it.
2107
+ */
2108
+ interface CraftStartProposal {
2109
+ /**
2110
+ * Station id, as `Crafting.stations` names it.
2111
+ */
2112
+ station: string;
2113
+
2114
+ /**
2115
+ * The player's virtual world; each world has its own tables.
2116
+ */
2117
+ virtualWorld: number;
2118
+
2119
+ /**
2120
+ * The batch this one follows at a table the player kept, or empty for a fresh entry.
2121
+ */
2122
+ continuationOf: string;
2123
+ }
2124
+
2125
+ /**
2126
+ * A batch that is now brewing: the table's opening animation finished, or the next batch started at a table the player kept.
2127
+ */
2128
+ interface CraftStartedEvent {
2129
+ /**
2130
+ * The batch's session id.
2131
+ */
2132
+ session: string;
2133
+
2134
+ /**
2135
+ * Station id.
2136
+ */
2137
+ station: string;
2138
+
2139
+ /**
2140
+ * The table's virtual world.
2141
+ */
2142
+ virtualWorld: number;
2143
+
2144
+ /**
2145
+ * The previous batch at this table, or empty for the first.
2146
+ */
2147
+ continuationOf: string;
2148
+ }
2149
+
2150
+ /**
2151
+ * What a finished batch is about to grant, computed by the server. Frozen: a handler can refuse it, not change it.
2152
+ */
2153
+ interface CraftCompletionProposal {
2154
+ /**
2155
+ * The batch's session id.
2156
+ */
2157
+ session: string;
2158
+
2159
+ /**
2160
+ * Station id.
2161
+ */
2162
+ station: string;
2163
+
2164
+ /**
2165
+ * `failed` brews the game's failed potion.
2166
+ */
2167
+ outcome: 'success' | 'failed';
2168
+
2169
+ /**
2170
+ * The recipe the brew matched, or empty when it matched none.
2171
+ */
2172
+ recipe: string;
2173
+
2174
+ /**
2175
+ * The product's native rank.
2176
+ */
2177
+ grade: number;
2178
+
2179
+ /**
2180
+ * Item class GUID of what would be granted, or empty when the yield came out at zero.
2181
+ */
2182
+ product: string;
2183
+
2184
+ /**
2185
+ * How many.
2186
+ */
2187
+ amount: number;
2188
+
2189
+ /**
2190
+ * Brewing quality, 0 to 1, after perks and the table-entry bonus.
2191
+ */
2192
+ quality: number;
2193
+
2194
+ /**
2195
+ * Base alchemy XP; the player's own multipliers apply on top.
2196
+ */
2197
+ xp: number;
2198
+ }
2199
+
2200
+ /**
2201
+ * A batch whose result was granted: the output is in the inventory and the XP was ordered.
2202
+ */
2203
+ interface CraftCompletedEvent {
2204
+ /**
2205
+ * The batch's session id.
2206
+ */
2207
+ session: string;
2208
+
2209
+ /**
2210
+ * Station id.
2211
+ */
2212
+ station: string;
2213
+
2214
+ /**
2215
+ * The table's virtual world.
2216
+ */
2217
+ virtualWorld: number;
2218
+
2219
+ /**
2220
+ * `failed` granted the game's failed potion.
2221
+ */
2222
+ outcome: 'success' | 'failed';
2223
+
2224
+ /**
2225
+ * The recipe matched, or empty.
2226
+ */
2227
+ recipe: string;
2228
+
2229
+ /**
2230
+ * The product's native rank.
2231
+ */
2232
+ grade: number;
2233
+
2234
+ /**
2235
+ * Brewing quality, 0 to 1.
2236
+ */
2237
+ quality: number;
2238
+
2239
+ /**
2240
+ * Base alchemy XP ordered.
2241
+ */
2242
+ xp: number;
2243
+
2244
+ /**
2245
+ * The inventory rows that received the output. Do not grant it again.
2246
+ */
2247
+ outputs: InventoryUnit[];
2248
+
2249
+ /**
2250
+ * The player's recipe knowledge after this batch, as `Crafting.knowledge` returns it.
2251
+ */
2252
+ knowledge: Record<string, number>;
2253
+ }
2254
+
2255
+ /**
2256
+ * A batch that is over, for any reason. A table kept for the next batch is not closed by this.
2257
+ */
2258
+ interface CraftEndedEvent {
2259
+ /**
2260
+ * The batch's session id.
2261
+ */
2262
+ session: string;
2263
+
2264
+ /**
2265
+ * Station id.
2266
+ */
2267
+ station: string;
2268
+
2269
+ /**
2270
+ * The table's virtual world.
2271
+ */
2272
+ virtualWorld: number;
2273
+
2274
+ /**
2275
+ * How it ended.
2276
+ */
2277
+ outcome: 'success' | 'failed' | 'cancelled';
2278
+
2279
+ /**
2280
+ * 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.
2281
+ */
2282
+ reason: string;
2283
+
2284
+ /**
2285
+ * The inventory rows ingredients went back to. Wholly unmilled bowl, mortar and herb groups come back; everything else put on the table was spent.
2286
+ */
2287
+ refunded: InventoryUnit[];
2288
+ }
2289
+
2290
+ /**
2291
+ * Units required by a shipped recipe.
2292
+ */
2293
+ interface CraftMaterialRequirement {
2294
+ /**
2295
+ * Item class GUID.
2296
+ */
2297
+ item: string;
2298
+
2299
+ /**
2300
+ * Native item name, useful with Player.giveItem.
2301
+ */
2302
+ name: string;
2303
+
2304
+ /**
2305
+ * Units required for one attempt.
2306
+ */
2307
+ amount: number;
2308
+ }
2309
+
2310
+ /**
2311
+ * One possible product row. These are alternatives, not a reward list.
2312
+ */
2313
+ interface CraftProductInfo {
2314
+ /**
2315
+ * Product class GUID.
2316
+ */
2317
+ item: string;
2318
+
2319
+ /**
2320
+ * Alchemy product rank or smithing minimum quality percent.
2321
+ */
2322
+ threshold: number;
2323
+
2324
+ /**
2325
+ * Alchemy base maximum yield before modifiers; one for smithing.
2326
+ */
2327
+ maxYield: number;
2328
+ }
2329
+
2330
+ /**
2331
+ * Shipped recipe data allowed by server DLC policy. Presence is not proof of player knowledge, skill, quest eligibility or materials.
2332
+ */
2333
+ interface CraftRecipeInfo {
2334
+ /**
2335
+ * Tagged native recipe identity.
2336
+ */
2337
+ key: { kind: 'alchemy'; id: number } | { kind: 'smithing'; id: string };
2338
+
2339
+ /**
2340
+ * Localization key from the native table.
2341
+ */
2342
+ name: string;
2343
+
2344
+ /**
2345
+ * Native DLC id; zero for untagged content.
2346
+ */
2347
+ dlcId: number;
2348
+
2349
+ /**
2350
+ * Minimum craftsmanship skill, or zero for alchemy.
2351
+ */
2352
+ minSkill: number;
2353
+
2354
+ /**
2355
+ * Smithing recipe unlock perk GUID, empty for alchemy.
2356
+ */
2357
+ perk: string;
2358
+
2359
+ /**
2360
+ * Alchemy base liquid, empty for smithing. Supplied by the station.
2361
+ */
2362
+ base: string;
2363
+
2364
+ /**
2365
+ * Required ingredient quantities.
2366
+ */
2367
+ ingredients: CraftMaterialRequirement[];
2368
+
2369
+ /**
2370
+ * Possible products by native rank or threshold.
2371
+ */
2372
+ products: CraftProductInfo[];
2373
+ }
2374
+
2375
+ /**
2376
+ * 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.
2377
+ */
2378
+ interface CraftStationInfo {
2379
+ /**
2380
+ * Level and stable placement GUID.
2381
+ */
2382
+ id: string;
2383
+
2384
+ /**
2385
+ * The station's recipe family.
2386
+ */
2387
+ kind: 'alchemy' | 'smithing';
2388
+
2389
+ /**
2390
+ * Level directory name.
2391
+ */
2392
+ level: string;
2393
+
2394
+ /**
2395
+ * Authored editor layer, for identifying the location.
2396
+ */
2397
+ layer: string;
2398
+
2399
+ /**
2400
+ * World position of the station.
2401
+ */
2402
+ position: { x: number; y: number; z: number };
2403
+
2404
+ /**
2405
+ * Horizontal facing direction.
2406
+ */
2407
+ forward: { x: number; y: number };
2408
+ }
2409
+
2410
+ /**
2411
+ * Who holds an alchemy table. A player keeps it between batches until they leave it.
2412
+ */
2413
+ interface CraftStationOccupant {
2414
+ /**
2415
+ * The player's id.
2416
+ */
2417
+ playerId: number;
2418
+
2419
+ /**
2420
+ * The first batch of this visit; the same across every batch of it.
2421
+ */
2422
+ entryId: string;
2423
+
2424
+ /**
2425
+ * The batch now running, or the last one to finish.
2426
+ */
2427
+ sessionId: string;
2428
+
2429
+ /**
2430
+ * `entering` until the opening animation finishes; `finishing` while a finished batch waits to settle.
2431
+ */
2432
+ phase: 'entering' | 'brewing' | 'finishing' | 'betweenBatches';
2433
+
2434
+ /**
2435
+ * Milliseconds until the table is taken back. Each batch has 30 minutes.
2436
+ */
2437
+ expiresInMs: number;
2438
+ }
2439
+
2440
+ /**
2441
+ * One table in one virtual world. A free table may still be unusable in the game, for instance behind a quest layer.
2442
+ */
2443
+ interface CraftStationOccupancy {
2444
+ /**
2445
+ * Station id.
2446
+ */
2447
+ station: string;
2448
+
2449
+ /**
2450
+ * The virtual world asked about.
2451
+ */
2452
+ virtualWorld: number;
2453
+
2454
+ /**
2455
+ * Someone holds it, brewing or between batches.
2456
+ */
2457
+ occupied: boolean;
2458
+
2459
+ /**
2460
+ * Who, or null when free.
2461
+ */
2462
+ occupant: CraftStationOccupant | null;
2463
+ }
2464
+
2465
+ /**
2466
+ * A player's alchemy session, or the table they kept between batches. A copy: changing it changes nothing.
2467
+ */
2468
+ interface CraftSessionInfo {
2469
+ /**
2470
+ * The batch's session id.
2471
+ */
2472
+ id: string;
2473
+
2474
+ /**
2475
+ * Station id.
2476
+ */
2477
+ station: string;
2478
+
2479
+ /**
2480
+ * The table's virtual world.
2481
+ */
2482
+ virtualWorld: number;
2483
+
2484
+ /**
2485
+ * Where the batch is.
2486
+ */
2487
+ phase: 'entering' | 'brewing' | 'finishing' | 'betweenBatches';
2488
+
2489
+ /**
2490
+ * Native actions accepted so far.
2491
+ */
2492
+ sequence: number;
1372
2493
 
1373
2494
  /**
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.
2495
+ * What is on the table: item class, the inventory row it came from (empty for a base liquid), and the native table position.
1378
2496
  */
1379
- setBuyPrices(vendor: number, rows: VendorBuyRow[]): boolean;
2497
+ resources: { id: number; item: string; itemId: string; position: number; base: boolean; milled: boolean; distilled: boolean }[];
1380
2498
 
1381
2499
  /**
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.
2500
+ * Milliseconds until the session times out.
1386
2501
  */
1387
- setPurse(vendor: number, purse: number | null): boolean;
2502
+ expiresInMs: number;
2503
+ }
1388
2504
 
2505
+ /**
2506
+ * Crafting catalogs, alchemy table occupancy, sessions and recipe knowledge. Held in memory for each connection; nothing is saved.
2507
+ */
2508
+ const Crafting: {
1389
2509
  /**
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.
2510
+ * True for alchemy, false for smithing, which is not synchronized yet. Omitted kind checks alchemy.
1393
2511
  */
1394
- getPurse(vendor: number): number | null;
2512
+ isAvailable(kind?: 'alchemy' | 'smithing'): boolean;
1395
2513
 
1396
2514
  /**
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.
2515
+ * Placed stations in this server's level. Does not load deferred layers or bypass quests.
1402
2516
  */
1403
- open(vendor: number, player: number, npc?: number): number;
2517
+ stations(kind?: 'alchemy' | 'smithing'): readonly CraftStationInfo[];
1404
2518
 
1405
2519
  /**
1406
- * Takes the trade screen off that player.
1407
- * @param session The session to end.
1408
- * @returns False when the session had already ended.
2520
+ * 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.
1409
2521
  */
1410
- close(session: number): boolean;
2522
+ recipes(player: Player, kind?: 'alchemy' | 'smithing'): readonly CraftRecipeInfo[];
1411
2523
 
1412
2524
  /**
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.
2525
+ * The player's alchemy session or the table they kept between batches, or null.
1416
2526
  */
1417
- sessionOf(player: number): number;
2527
+ session(player: Player): CraftSessionInfo | null;
1418
2528
 
1419
2529
  /**
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.
2530
+ * Who holds a table. World defaults to 0. Null for an unknown or non-alchemy station.
1423
2531
  */
1424
- vendorOf(session: number): number;
1425
- };
2532
+ occupancy(stationId: string, virtualWorld?: number): CraftStationOccupancy | null;
1426
2533
 
1427
- /**
1428
- * One item class that left a victim's pockets for a thief's.
1429
- */
1430
- interface PickpocketLine {
1431
2534
  /**
1432
- * The item class GUID.
2535
+ * 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.
1433
2536
  */
1434
- item: string;
2537
+ cancel(player: Player): boolean;
1435
2538
 
1436
2539
  /**
1437
- * The game's own name for the item class.
2540
+ * 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`.
1438
2541
  */
1439
- name: string;
2542
+ knowledge(player: Player): Record<string, number>;
1440
2543
 
1441
2544
  /**
1442
- * How many moved.
2545
+ * 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.
1443
2546
  */
1444
- amount: number;
1445
- }
2547
+ setKnowledge(player: Player, recipeId: string | number, mask: number): boolean;
2548
+ };
1446
2549
 
1447
2550
  /**
1448
2551
  * Replicated KCD2 dog companion handle.
@@ -1474,6 +2577,11 @@ declare global {
1474
2577
  */
1475
2578
  readonly owner: Player | null;
1476
2579
 
2580
+ /**
2581
+ * 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.
2582
+ */
2583
+ destroyWithOwner: boolean;
2584
+
1477
2585
  /**
1478
2586
  * 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
2587
  */
@@ -1501,7 +2609,7 @@ declare global {
1501
2609
  destroy(): void;
1502
2610
 
1503
2611
  /**
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.
2612
+ * 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
2613
  * @param player The dog's new master, or null to leave it masterless.
1506
2614
  */
1507
2615
  giveTo(player: Player | null): void;
@@ -1614,6 +2722,124 @@ declare global {
1614
2722
 
1615
2723
  interface Prop extends Entity {}
1616
2724
 
2725
+ /**
2726
+ * Replicated cart or wagon handle.
2727
+ */
2728
+ class Cart {
2729
+ /**
2730
+ * Creates a script wrapper for an existing cart with this ID; use Cart.spawn() to spawn one.
2731
+ * @param id Network entity identifier.
2732
+ */
2733
+ constructor(id: number);
2734
+
2735
+ /**
2736
+ * The game prefab this cart was built from, e.g. `wagon_b_covered`. `Cart.blueprints()` lists them all.
2737
+ */
2738
+ readonly blueprint: string;
2739
+
2740
+ /**
2741
+ * How many horses the cart is harnessed for: 2 for a wagon, 1 for the two-wheeled cart, 0 for `wagon_b_covered_empty`, whose chassis has nowhere to hitch one and so can be sat in but never pulled.
2742
+ */
2743
+ readonly horseCount: number;
2744
+
2745
+ /**
2746
+ * The player at the reins, or null when nobody drives it.
2747
+ */
2748
+ readonly driver: Player | null;
2749
+
2750
+ /**
2751
+ * How the driver last asked the cart to go: `stand`, `walk`, `trot` or `reverse`.
2752
+ */
2753
+ readonly pace: string;
2754
+
2755
+ /**
2756
+ * Formats this cart handle for logging and debugging.
2757
+ * @returns The cart ID, its blueprint, its driver and its pace.
2758
+ */
2759
+ toString(): string;
2760
+
2761
+ /**
2762
+ * Despawns this cart on every client. Everyone in it is let out first, each with a `cartExit`, then `cartDestroy` is raised.
2763
+ */
2764
+ destroy(): void;
2765
+
2766
+ /**
2767
+ * Puts a player in a seat. They are taken out of any cart they were in, their own game walks them to the seat and climbs in, and `cartEnter` follows; the driver's client runs the cart from then on. `cartEntering` handlers are asked first.
2768
+ * @param player The player to seat.
2769
+ * @param seat `driver` (the bench, holding the reins) or `back` (the right rail): the two seats the game animates a player in.
2770
+ * @returns Whether the player was seated: false for a taken seat, a player that is not connected, or a handler's refusal.
2771
+ */
2772
+ putPlayer(player: Player, seat: string): boolean;
2773
+
2774
+ /**
2775
+ * Lets a player out of this cart: their own game climbs down, and `cartExit` is raised.
2776
+ * @param player The player to let out.
2777
+ * @returns False when the player is not in this cart.
2778
+ */
2779
+ removePlayer(player: Player): boolean;
2780
+
2781
+ /**
2782
+ * Who sits in a seat.
2783
+ * @param seat `driver` or `back`.
2784
+ * @returns The player in it, or null when it is empty.
2785
+ */
2786
+ getOccupant(seat: string): Player | null;
2787
+
2788
+ /**
2789
+ * Where a player sits in this cart.
2790
+ * @param player The player to look for.
2791
+ * @returns `driver` or `back`, or null when they are not in it.
2792
+ */
2793
+ seatOf(player: Player): string | null;
2794
+
2795
+ /**
2796
+ * Moves the cart outright, with everyone in it: every client rebuilds it on a new short road at the new pose, and a driver carries on from there.
2797
+ * @param position Where the cart's front axle stands.
2798
+ * @param rotation Which way it faces; omitted keeps its heading.
2799
+ * @returns False for a pose that is not finite.
2800
+ */
2801
+ teleport(position: Vector3, rotation?: Vector3 | Quaternion): boolean;
2802
+
2803
+ /**
2804
+ * Spawns and replicates a cart or wagon from the game's own prefabs, with its horses already in the shafts. It stands on a short straight road until somebody takes the reins.
2805
+ * @param blueprint Which of the game's cart prefabs to build; omitted builds `wagon_b_covered`. `Cart.blueprints()` lists them.
2806
+ * @param position Where the cart's front axle stands; omitted components default to zero.
2807
+ * @param rotation Which way it faces: a Quaternion, or a Vector3 of Euler angles in degrees.
2808
+ * @param virtualWorld Optional virtual world the cart belongs to; omitted puts it in the global one.
2809
+ * @returns The newly spawned cart handle.
2810
+ */
2811
+ static spawn(blueprint?: string, position?: Vector3 | Partial<Vector3>, rotation?: Vector3 | Quaternion, virtualWorld?: number): Cart;
2812
+
2813
+ /**
2814
+ * Lists the carts the server has.
2815
+ * @param virtualWorld Optional virtual world to list; omitted lists every one.
2816
+ * @returns One handle per live cart, in no particular order.
2817
+ */
2818
+ static all(virtualWorld?: number): Cart[];
2819
+
2820
+ /**
2821
+ * Looks a cart up by its network entity ID.
2822
+ * @param id Network entity identifier.
2823
+ * @returns The cart's handle, or null when no live cart has that ID.
2824
+ */
2825
+ static getById(id: number): Cart | null;
2826
+
2827
+ /**
2828
+ * Despawns carts, emitting cartDestroy for each one.
2829
+ * @param virtualWorld Optional virtual world to clear; omitted clears every one of them.
2830
+ * @returns How many carts were removed.
2831
+ */
2832
+ static destroyAll(virtualWorld?: number): number;
2833
+
2834
+ /**
2835
+ * Names every cart prefab `Cart.spawn` can build.
2836
+ * @returns The blueprint names, in catalog order.
2837
+ */
2838
+ static blueprints(): string[];
2839
+ }
2840
+
2841
+ interface Cart extends Entity {}
2842
+
1617
2843
  /**
1618
2844
  * Replicated particle effect handle.
1619
2845
  */
@@ -2305,30 +3531,44 @@ declare global {
2305
3531
  * @param objective The line, as text or as an object carrying its state.
2306
3532
  * @param announce Whether to raise the quest-updated toast; defaults to true.
2307
3533
  */
2308
- setObjective(index: number, objective: string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean }, announce?: boolean): void;
3534
+ setObjective(index: number, objective: string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean; position?: Vector3 }, announce?: boolean): void;
2309
3535
 
2310
3536
  /**
2311
3537
  * Replaces the quest's objective list.
2312
3538
  * @param objectives The whole list, at most eight entries; anything past that is dropped.
2313
3539
  * @param announce Whether to raise the quest-updated toast; defaults to true.
2314
3540
  */
2315
- setObjectives(objectives: (string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean })[], announce?: boolean): void;
3541
+ setObjectives(objectives: (string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean; position?: Vector3 })[], announce?: boolean): void;
2316
3542
 
2317
3543
  /**
2318
3544
  * Reads the quest's objectives back.
2319
- * @returns One entry per objective, in journal order.
3545
+ * @returns One entry per objective, in journal order. `position` is present only on an objective that has one.
3546
+ */
3547
+ objectives(): { text: string; progress: 'active' | 'done' | 'failed' | 'none'; optional: boolean; position?: Vector3 }[];
3548
+
3549
+ /**
3550
+ * Makes the game follow this quest, exactly as the journal's track button does: it is listed in the HUD tracker, and every active objective that has a `position` is drawn as the game's own quest marker on the map and the compass. It is an instruction, not a lock -- the player can untrack it from the journal -- and the outcome arrives as `questTrackingChanged` like any other change. A quest given a moment ago can be tracked at once; the client waits for it to arrive.
3551
+ * @param player Network id of the player who should follow the quest. Omitted, everyone who has the quest follows it: its one owner, or every player in its world.
3552
+ * @returns How many clients were told. Zero when the player does not have this quest.
3553
+ */
3554
+ track(player?: number): number;
3555
+
3556
+ /**
3557
+ * Makes the game stop following this quest, which takes its markers off the map and the compass. The outcome arrives as `questTrackingChanged`.
3558
+ * @param player Network id of the player who should stop following the quest. Omitted, everyone who has the quest stops.
3559
+ * @returns How many clients were told.
2320
3560
  */
2321
- objectives(): { text: string; progress: 'active' | 'done' | 'failed' | 'none'; optional: boolean }[];
3561
+ untrack(player?: number): number;
2322
3562
 
2323
3563
  /**
2324
3564
  * Writes a quest into the game's own journal. It is a replicated entity, so a player who joins late, reloads or walks away still finds it in their log -- which is what a quest needs and what a one-shot notification cannot do. What the player sees is the game's quest UI: its journal row, its diary page, its objective tracker and its quest-updated toast, all reading a quest node the client builds with the game's own constructor.
2325
3565
  * @param key What the quest is filed under: up to 64 letters, digits, underscores or dashes, unique within its virtual world.
2326
3566
  * @param title The line the journal row shows.
2327
- * @param options `description` is the diary page, `type` the journal section, `objectives` the lines under it, `player` the network id of the one player it belongs to, and `announce` whether to raise the toast.
3567
+ * @param options `description` is the diary page, `type` the journal section, `objectives` the lines under it -- each with an optional world `position` the game marks on the map and compass while the quest is followed -- `player` the network id of the one player it belongs to, `announce` whether to raise the toast, and `track` whether its recipients start following it.
2328
3568
  * @param virtualWorld Optional virtual world the quest belongs to; omitted puts it in the global one.
2329
3569
  * @returns The newly written quest handle.
2330
3570
  */
2331
- static give(key: string, title: string, options?: { description?: string; type?: 'main' | 'side' | 'activity' | 'event' | 'micro' | 'racing'; objectives?: (string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean })[]; player?: number; announce?: boolean }, virtualWorld?: number): Quest;
3571
+ static give(key: string, title: string, options?: { description?: string; type?: 'main' | 'side' | 'activity' | 'event' | 'micro' | 'racing'; objectives?: (string | { text: string; progress?: 'active' | 'done' | 'failed'; optional?: boolean; position?: Vector3 })[]; player?: number; announce?: boolean; track?: boolean }, virtualWorld?: number): Quest;
2332
3572
 
2333
3573
  /**
2334
3574
  * Lists every replicated quest the server currently has.
@@ -2399,7 +3639,7 @@ declare global {
2399
3639
  readonly condition: number;
2400
3640
 
2401
3641
  /**
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.
3642
+ * 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
3643
  */
2404
3644
  readonly resting: boolean;
2405
3645
 
@@ -2459,6 +3699,71 @@ declare global {
2459
3699
 
2460
3700
  interface GroundItem extends Entity {}
2461
3701
 
3702
+ /**
3703
+ * A plant a player picked and what it is about to give them.
3704
+ */
3705
+ interface GatheringProposal {
3706
+ /**
3707
+ * Item class GUID of the herb.
3708
+ */
3709
+ item: string;
3710
+
3711
+ /**
3712
+ * How many, as the game computes it from the player's survival level and the plants harvested together.
3713
+ */
3714
+ amount: number;
3715
+
3716
+ /**
3717
+ * The game's pickable area id for the plant.
3718
+ */
3719
+ kind: number;
3720
+
3721
+ /**
3722
+ * Where the plant grows, as the player's game reported it.
3723
+ */
3724
+ position: number[];
3725
+
3726
+ /**
3727
+ * The player's virtual world.
3728
+ */
3729
+ virtualWorld: number;
3730
+ }
3731
+
3732
+ /**
3733
+ * A plant a player picked, and what they were given.
3734
+ */
3735
+ interface GatheringHarvestedEvent {
3736
+ /**
3737
+ * Item class GUID of the herb.
3738
+ */
3739
+ item: string;
3740
+
3741
+ /**
3742
+ * How many.
3743
+ */
3744
+ amount: number;
3745
+
3746
+ /**
3747
+ * The game's pickable area id for the plant.
3748
+ */
3749
+ kind: number;
3750
+
3751
+ /**
3752
+ * Where the plant grows.
3753
+ */
3754
+ position: number[];
3755
+
3756
+ /**
3757
+ * The player's virtual world.
3758
+ */
3759
+ virtualWorld: number;
3760
+
3761
+ /**
3762
+ * The inventory rows that received the herb.
3763
+ */
3764
+ items: InventoryUnit[];
3765
+ }
3766
+
2462
3767
  /** */
2463
3768
  interface NearestDoor {
2464
3769
  /**
@@ -2754,10 +4059,15 @@ declare global {
2754
4059
  readonly name: string;
2755
4060
 
2756
4061
  /**
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.
4062
+ * 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
4063
  */
2759
4064
  readonly itemCount: number;
2760
4065
 
4066
+ /**
4067
+ * Whether a player has it open. Every client animates the lid by it.
4068
+ */
4069
+ readonly isOpen: boolean;
4070
+
2761
4071
  /**
2762
4072
  * 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
4073
  */
@@ -2805,7 +4115,28 @@ declare global {
2805
4115
  destroy(): void;
2806
4116
 
2807
4117
  /**
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.
4118
+ * Reads what the container holds. A linked child reads its master's.
4119
+ * @returns A copy of its rows, or null once the container is gone.
4120
+ */
4121
+ getInventory(): { revision: number; items: InventoryRow[] } | null;
4122
+
4123
+ /**
4124
+ * Puts items in the container, as `Inventory.add` gives them to a player.
4125
+ */
4126
+ addItem(request: { item: string; amount: number; metadata?: Record<string, unknown>; revision?: number }): InventoryResult;
4127
+
4128
+ /**
4129
+ * Takes exact units out of named rows, every one of them or none.
4130
+ */
4131
+ removeItem(request: { units: InventoryUnit[]; revision?: number }): InventoryResult;
4132
+
4133
+ /**
4134
+ * Replaces everything in the container, which is how saved contents come back. At most 128 rows. An empty list empties it.
4135
+ */
4136
+ setInventory(request: { items: { id?: string; item: string; amount: number; metadata?: Record<string, unknown> }[]; revision?: number }): InventoryResult;
4137
+
4138
+ /**
4139
+ * Spawns and replicates an empty container. Fill it with `addItem` or `setInventory`, or let players put things in it.
2809
4140
  * @param position Optional world-space spawn position; omitted components default to zero.
2810
4141
  * @param rotation Optional initial orientation: a Quaternion, or a Vector3 of Euler angles in degrees.
2811
4142
  * @param virtualWorld Optional virtual world the container belongs to; omitted puts it in the global one.
@@ -3248,6 +4579,94 @@ declare global {
3248
4579
  claim(classNames: string[]): string[];
3249
4580
  };
3250
4581
 
4582
+ /**
4583
+ * The game's skills, stats and perks, and the rules this server puts on how players move along them.
4584
+ */
4585
+ const Progression: {
4586
+ /**
4587
+ * Whether players' own games may earn XP. See `setNativeXp`.
4588
+ */
4589
+ readonly nativeXp: boolean;
4590
+
4591
+ /**
4592
+ * The perks this server blocks.
4593
+ */
4594
+ readonly blockedPerks: string[];
4595
+
4596
+ /**
4597
+ * Every skill and stat a player levels: the fifteen skills the character sheet shows, then strength, agility, vitality, speech and prestige.
4598
+ * @returns The tracks, in that order.
4599
+ */
4600
+ tracks(): TrackInfo[];
4601
+
4602
+ /**
4603
+ * Looks a perk up.
4604
+ * @param query A perk's name, as the game's perk tables spell it, or its GUID.
4605
+ * @returns What the tables say about it, or null for a name they do not carry.
4606
+ */
4607
+ findPerk(query: string): PerkInfo | null;
4608
+
4609
+ /**
4610
+ * Lists the game's perks: 945 of them, most of them hidden system perks. `Progression.perks({ visibleOnly: true })` is the perk screen.
4611
+ * @param filter `track` keeps the perks one tree pays for -- a track name, or `main`; `visibleOnly` keeps the perks the perk screen shows.
4612
+ * @returns The perks, sorted by name.
4613
+ */
4614
+ perks(filter?: { track?: string; visibleOnly?: boolean }): PerkInfo[];
4615
+
4616
+ /**
4617
+ * 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.
4618
+ * @param track A track name.
4619
+ * @param level The level to reach.
4620
+ * @returns The XP. Throws for a track name the tables do not carry.
4621
+ */
4622
+ xpForLevel(track: string, level: number): number;
4623
+
4624
+ /**
4625
+ * 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.
4626
+ * @param enabled False to stop players' own games from earning XP at all.
4627
+ * @returns Nothing.
4628
+ */
4629
+ setNativeXp(enabled: boolean): void;
4630
+
4631
+ /**
4632
+ * 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.
4633
+ * @param track A track name, or `*` for every track.
4634
+ * @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.
4635
+ * @returns Nothing.
4636
+ */
4637
+ setXpRate(track: string, rate: number): void;
4638
+
4639
+ /**
4640
+ * 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.
4641
+ * @param track A track name, or `*` for every track.
4642
+ * @param xpPerMinute How much XP a player may earn on the track per minute, before multipliers. 0 is unlimited.
4643
+ * @returns Nothing.
4644
+ */
4645
+ setXpBudget(track: string, xpPerMinute: number): void;
4646
+
4647
+ /**
4648
+ * 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.
4649
+ * @param track A track name, or `*` for every track.
4650
+ * @param level The highest level XP from play may reach, at most the game's own 30.
4651
+ * @returns Nothing.
4652
+ */
4653
+ setLevelCap(track: string, level: number): void;
4654
+
4655
+ /**
4656
+ * 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.
4657
+ * @param perks Perk names or GUIDs.
4658
+ * @returns Nothing. Throws for an unknown perk.
4659
+ */
4660
+ blockPerks(perks: string[]): void;
4661
+
4662
+ /**
4663
+ * Lifts `blockPerks`.
4664
+ * @param perks Perk names or GUIDs.
4665
+ * @returns Nothing. Throws for an unknown perk.
4666
+ */
4667
+ unblockPerks(perks: string[]): void;
4668
+ };
4669
+
3251
4670
  /**
3252
4671
  * The game's own character-component catalog: every face, hairstyle, beard and skin a player's body can be given.
3253
4672
  *
@@ -4536,6 +5955,59 @@ declare global {
4536
5955
  isPlayerTalking(player: Entity): boolean;
4537
5956
  };
4538
5957
 
5958
+ /**
5959
+ * 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.
5960
+ */
5961
+ interface PendingConnection {
5962
+ /**
5963
+ * The name the player asked to join under.
5964
+ */
5965
+ readonly nickname: string;
5966
+
5967
+ /**
5968
+ * Steam identifier the client reported, or an empty string when it had none.
5969
+ */
5970
+ readonly steamId: string;
5971
+
5972
+ /**
5973
+ * Discord identifier the client reported, or an empty string when it had none.
5974
+ */
5975
+ readonly discordId: string;
5976
+
5977
+ /**
5978
+ * Framework hardware identifier the client reported, or an empty string when it had none.
5979
+ */
5980
+ readonly hardwareId: string;
5981
+
5982
+ /**
5983
+ * 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.
5984
+ */
5985
+ readonly ticket: string;
5986
+
5987
+ /**
5988
+ * The remote address the connection comes from, without its port.
5989
+ */
5990
+ readonly ip: string;
5991
+
5992
+ /**
5993
+ * 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.
5994
+ * @param reason Shown to the player as written, up to 512 bytes. Omitted, they read that the server refused the connection.
5995
+ */
5996
+ reject(reason?: string): void;
5997
+
5998
+ /**
5999
+ * 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.
6000
+ * @param message One line for the player's connecting screen, up to 256 bytes: 'Checking the whitelist', 'You are 4th in the queue'.
6001
+ */
6002
+ update(message: string): void;
6003
+
6004
+ /**
6005
+ * Checks whether this connection is still waiting on a decision.
6006
+ * @returns False once it was let in or turned away, or the player gave up and left; a queue drops such entries.
6007
+ */
6008
+ isPending(): boolean;
6009
+ }
6010
+
4539
6011
  /**
4540
6012
  * Base handle for a live replicated network entity.
4541
6013
  */