@dreadwood-types/types 0.1.0

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.
Files changed (70) hide show
  1. package/README.md +43 -0
  2. package/dist/appearance.d.ts +80 -0
  3. package/dist/appearance.d.ts.map +1 -0
  4. package/dist/appearance.js +319 -0
  5. package/dist/appearance.js.map +1 -0
  6. package/dist/bank.d.ts +15 -0
  7. package/dist/bank.d.ts.map +1 -0
  8. package/dist/bank.js +45 -0
  9. package/dist/bank.js.map +1 -0
  10. package/dist/clientConfig.d.ts +103 -0
  11. package/dist/clientConfig.d.ts.map +1 -0
  12. package/dist/clientConfig.js +209 -0
  13. package/dist/clientConfig.js.map +1 -0
  14. package/dist/constants.d.ts +205 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/constants.js +713 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/cooking.d.ts +26 -0
  19. package/dist/cooking.d.ts.map +1 -0
  20. package/dist/cooking.js +41 -0
  21. package/dist/cooking.js.map +1 -0
  22. package/dist/equipment.d.ts +47 -0
  23. package/dist/equipment.d.ts.map +1 -0
  24. package/dist/equipment.js +186 -0
  25. package/dist/equipment.js.map +1 -0
  26. package/dist/goblinCave.d.ts +112 -0
  27. package/dist/goblinCave.d.ts.map +1 -0
  28. package/dist/goblinCave.js +69 -0
  29. package/dist/goblinCave.js.map +1 -0
  30. package/dist/groundItems.d.ts +17 -0
  31. package/dist/groundItems.d.ts.map +1 -0
  32. package/dist/groundItems.js +104 -0
  33. package/dist/groundItems.js.map +1 -0
  34. package/dist/index.d.ts +16 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +16 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/landmarks.d.ts +366 -0
  39. package/dist/landmarks.d.ts.map +1 -0
  40. package/dist/landmarks.js +584 -0
  41. package/dist/landmarks.js.map +1 -0
  42. package/dist/messages.d.ts +723 -0
  43. package/dist/messages.d.ts.map +1 -0
  44. package/dist/messages.js +38 -0
  45. package/dist/messages.js.map +1 -0
  46. package/dist/nameFilter.d.ts +8 -0
  47. package/dist/nameFilter.d.ts.map +1 -0
  48. package/dist/nameFilter.js +94 -0
  49. package/dist/nameFilter.js.map +1 -0
  50. package/dist/quests.d.ts +63 -0
  51. package/dist/quests.d.ts.map +1 -0
  52. package/dist/quests.js +233 -0
  53. package/dist/quests.js.map +1 -0
  54. package/dist/torches.d.ts +7 -0
  55. package/dist/torches.d.ts.map +1 -0
  56. package/dist/torches.js +11 -0
  57. package/dist/torches.js.map +1 -0
  58. package/dist/woodwork.d.ts +206 -0
  59. package/dist/woodwork.d.ts.map +1 -0
  60. package/dist/woodwork.js +365 -0
  61. package/dist/woodwork.js.map +1 -0
  62. package/dist/xp.d.ts +74 -0
  63. package/dist/xp.d.ts.map +1 -0
  64. package/dist/xp.js +126 -0
  65. package/dist/xp.js.map +1 -0
  66. package/dist/zones.d.ts +30 -0
  67. package/dist/zones.d.ts.map +1 -0
  68. package/dist/zones.js +143 -0
  69. package/dist/zones.js.map +1 -0
  70. package/package.json +36 -0
@@ -0,0 +1,723 @@
1
+ import type { ChunkCoord, ChunkData, NpcKind, WorldEntity } from './constants.js';
2
+ import type { CharacterAppearance } from './appearance.js';
3
+ import type { ClientConfig, PartialClientConfig } from './clientConfig.js';
4
+ import type { QuestId, QuestReward, QuestsSnapshot } from './quests.js';
5
+ import type { EquipmentSlots } from './equipment.js';
6
+ import type { WorldZoneId } from './zones.js';
7
+ export type { WorldZoneId } from './zones.js';
8
+ export type Vec2 = {
9
+ x: number;
10
+ y: number;
11
+ };
12
+ export type CharacterStats = {
13
+ health: number;
14
+ healthMax: number;
15
+ combat: number;
16
+ strength: number;
17
+ /** Melee power skill; paired with Mastery for attack effectiveness. */
18
+ archery: number;
19
+ /** Shared weapon-use skill. Shown to players as Mastery. */
20
+ precision: number;
21
+ fishing: number;
22
+ cooking: number;
23
+ foraging: number;
24
+ woodwork: number;
25
+ explorer: number;
26
+ combatXp: number;
27
+ strengthXp: number;
28
+ archeryXp: number;
29
+ precisionXp: number;
30
+ fishingXp: number;
31
+ cookingXp: number;
32
+ foragingXp: number;
33
+ woodworkXp: number;
34
+ explorerXp: number;
35
+ };
36
+ /** The currently selected combat training style. */
37
+ export type CombatStance = 'strength' | 'archery' | 'mastery' | 'balanced';
38
+ export declare function defaultCombatStance(): CombatStance;
39
+ export declare function normalizeCombatStance(raw: unknown): CombatStance;
40
+ export declare function defaultCharacterStats(): CharacterStats;
41
+ export type PlayerPublic = {
42
+ id: string;
43
+ name: string;
44
+ color: string;
45
+ x: number;
46
+ y: number;
47
+ appearance: CharacterAppearance;
48
+ health: number;
49
+ healthMax: number;
50
+ level: number;
51
+ fishing?: boolean;
52
+ /**
53
+ * Which tackle the fishing pose should show. Pond fishing is a scoop net;
54
+ * lake fishing (perch/tench) is the small rod, which previously also drew a
55
+ * net — so casting for perch looked like scooping frogs.
56
+ */
57
+ fishingGear?: 'net' | 'rod';
58
+ /**
59
+ * World point this player should visually face, e.g. the water they are
60
+ * casting at. Same field pair NpcPublic already uses to aim Old Tom at the
61
+ * pond; without it an angler faces wherever they happened to stop walking.
62
+ */
63
+ faceX?: number;
64
+ faceY?: number;
65
+ woodwork?: boolean;
66
+ woodcutTarget?: string;
67
+ /** Repeating woodcraft at a work bench (knife-on-wood pose). */
68
+ carving?: boolean;
69
+ weapon?: string;
70
+ boots?: string;
71
+ gloves?: string;
72
+ helmet?: string;
73
+ top?: string;
74
+ bottom?: string;
75
+ offhand?: string;
76
+ path?: Vec2[];
77
+ /**
78
+ * Pet trailing this player, visible to everyone. Server-driven so other
79
+ * players see your beagle follow you; absent while dismissed to the bank.
80
+ */
81
+ companion?: CompanionPublic | null;
82
+ };
83
+ /** A player's pet, positioned by the server like a miniature NPC. */
84
+ export type CompanionPublic = {
85
+ kind: 'beagle';
86
+ name: string;
87
+ x: number;
88
+ y: number;
89
+ };
90
+ export type NpcPublic = {
91
+ id: string;
92
+ kind: NpcKind;
93
+ name?: string;
94
+ x: number;
95
+ y: number;
96
+ level: number;
97
+ health: number;
98
+ healthMax: number;
99
+ /** Optional visual scale for special encounter variants. */
100
+ scale?: number;
101
+ inCombat: boolean;
102
+ path?: Vec2[];
103
+ speed?: number;
104
+ /** Optional world-space point this NPC should visually face (e.g. Old Tom facing pond water). */
105
+ faceX?: number;
106
+ faceY?: number;
107
+ };
108
+ export type CombatEndReason = 'victory' | 'defeat' | 'fled' | 'target_gone';
109
+ export type CombatTargetKind = 'player' | 'npc';
110
+ export type LootItem = {
111
+ kind: string;
112
+ qty: number;
113
+ };
114
+ export type InventorySlot = {
115
+ kind: string;
116
+ qty: number;
117
+ /** Craft quality for weapons (woodwork level when carved). */
118
+ precision?: number;
119
+ };
120
+ export type ItemAction = 'eat' | 'drop' | 'equip' | 'unequip';
121
+ /**
122
+ * A shop listing a player can buy. Normally costed in gold via `price`, but a
123
+ * listing can instead be a barter (e.g. Wilson's rod-for-maggots trade) by
124
+ * setting `costKind`/`costQty` to an item cost — `price` is ignored then.
125
+ */
126
+ export type ShopBuyEntry = {
127
+ kind: string;
128
+ price: number;
129
+ qty: number;
130
+ costKind?: string;
131
+ costQty?: number;
132
+ };
133
+ export type ShopSellEntry = {
134
+ kind: string;
135
+ price: number;
136
+ };
137
+ export type JoinRejectedReason = 'name_taken' | 'invalid_name';
138
+ /**
139
+ * `reward` is for "you just gained something" moments — landing a fish, and
140
+ * anything else worth a beat of celebration. Distinct from `quiet` (which is a
141
+ * plain grey chat line and was where catches used to land, so they slid past
142
+ * unnoticed) and from the default gold notice, which is used for routine
143
+ * information.
144
+ */
145
+ export type NoticeStyle = 'warning' | 'quiet' | 'combat' | 'reward' | 'area' | 'quest';
146
+ export type LevelUpSkill = 'combat' | 'strength' | 'archery' | 'precision' | 'fishing' | 'cooking' | 'foraging' | 'woodwork' | 'explorer';
147
+ export declare function skillDisplayName(skill: LevelUpSkill): string;
148
+ export type TradeOfferSlot = {
149
+ kind: string;
150
+ qty: number;
151
+ };
152
+ export type TradeSessionSnapshot = {
153
+ partnerId: string;
154
+ partnerName: string;
155
+ you: TradeOfferSlot[];
156
+ them: TradeOfferSlot[];
157
+ youLocked: boolean;
158
+ themLocked: boolean;
159
+ youAccepted: boolean;
160
+ themAccepted: boolean;
161
+ };
162
+ export type DuelStakeSnapshot = {
163
+ partnerId: string;
164
+ partnerName: string;
165
+ you: TradeOfferSlot[];
166
+ them: TradeOfferSlot[];
167
+ youLocked: boolean;
168
+ themLocked: boolean;
169
+ phase: 'staking' | 'fighting';
170
+ };
171
+ /** Client SFX keys for trade/duel events (filenames under assets/audio/). */
172
+ export type TradeDuelSfx = 'sending_trade_request' | 'trade_started' | 'item_put_up_for_trade' | 'trade_locked_in' | 'trade_completed' | 'duel_request_sent' | 'duel_accepted' | 'item_put_up_as_stake' | 'stake_screen_locked' | 'stake_starting' | 'stake_won' | 'stake_lost';
173
+ /** Client SFX keys for the Rat Tunnel dungeon (filenames under assets/audio/). */
174
+ export type DungeonSfx = 'enter_dungeon' | 'exit_dungeon' | 'gate_open' | 'gate_close' | 'door_open' | 'door_close' | 'rare_monster_alert_battle' | 'boss_victory' | 'area_effect_start' | 'area_effect_end';
175
+ /** Client SFX keys for building and crafting (filenames under assets/audio/). */
176
+ export type CraftSfx = 'workbench_build' | 'workbench_carve' | 'item_crafted' | 'torch_light';
177
+ /** All server-broadcastable one-shot SFX keys. */
178
+ export type ClientSfx = TradeDuelSfx | DungeonSfx | CraftSfx;
179
+ export type ClientMessage =
180
+ /**
181
+ * `sessionToken` + `characterId` are used by account-backed entry points
182
+ * (including TikTok). The server verifies both before loading the character;
183
+ * name-only joins remain for legacy/browser guests.
184
+ */
185
+ {
186
+ type: 'join';
187
+ name?: string;
188
+ appearance: CharacterAppearance;
189
+ sessionToken?: string;
190
+ characterId?: string;
191
+ } | {
192
+ type: 'move';
193
+ x: number;
194
+ y: number;
195
+ } | {
196
+ type: 'ping';
197
+ t: number;
198
+ } | {
199
+ type: 'chunk_request';
200
+ chunks: ChunkCoord[];
201
+ } | {
202
+ type: 'chat';
203
+ text: string;
204
+ } | {
205
+ type: 'pm';
206
+ to: string;
207
+ text: string;
208
+ } | {
209
+ type: 'friend_add';
210
+ name: string;
211
+ } | {
212
+ type: 'friend_remove';
213
+ name: string;
214
+ } | {
215
+ type: 'config';
216
+ config: PartialClientConfig;
217
+ } | {
218
+ type: 'pickup';
219
+ entityId: string;
220
+ } | {
221
+ type: 'attack';
222
+ targetId: string;
223
+ } | {
224
+ type: 'set_combat_stance';
225
+ stance: CombatStance;
226
+ }
227
+ /**
228
+ * `slot` is the bag index the player actually clicked. Stacks are capped per
229
+ * slot, so the same kind can occupy several slots; without this the server
230
+ * always consumed the first matching stack, which is not the one that was
231
+ * clicked. Optional so older clients keep working (they get the old
232
+ * first-match behaviour).
233
+ */
234
+ | {
235
+ type: 'item_action';
236
+ item: string;
237
+ action: ItemAction;
238
+ qty?: number;
239
+ slot?: number;
240
+ } | {
241
+ type: 'cook_start';
242
+ input: string;
243
+ qty: number;
244
+ } | {
245
+ type: 'woodcraft_open';
246
+ entityId: string;
247
+ } | {
248
+ type: 'woodcraft_make';
249
+ recipe: string;
250
+ qty: number;
251
+ } | {
252
+ type: 'cook_cancel';
253
+ } | {
254
+ type: 'shop_open';
255
+ npcId: string;
256
+ } | {
257
+ type: 'shop_sell';
258
+ item: string;
259
+ qty: number;
260
+ } | {
261
+ type: 'shop_buy';
262
+ item: string;
263
+ qty: number;
264
+ } | {
265
+ type: 'bank_open';
266
+ entityId: string;
267
+ } | {
268
+ type: 'bank_close';
269
+ } | {
270
+ type: 'bank_deposit';
271
+ tab: number;
272
+ kind: string;
273
+ qty: number;
274
+ } | {
275
+ type: 'bank_withdraw';
276
+ tab: number;
277
+ kind: string;
278
+ qty: number;
279
+ } | {
280
+ type: 'quest_offer';
281
+ npcId: string;
282
+ } | {
283
+ type: 'quest_accept';
284
+ quest: QuestId;
285
+ } | {
286
+ type: 'quest_decline';
287
+ quest: QuestId;
288
+ } | {
289
+ type: 'npc_action';
290
+ npcId: string;
291
+ action: string;
292
+ } | {
293
+ type: 'use_item';
294
+ item: string;
295
+ npcId: string;
296
+ } | {
297
+ type: 'use_item';
298
+ item: string;
299
+ entityId: string;
300
+ } | {
301
+ type: 'milk_cow';
302
+ npcId: string;
303
+ } | {
304
+ type: 'identify';
305
+ kind: string;
306
+ } | {
307
+ type: 'fish_start';
308
+ } | {
309
+ type: 'woodcut_start';
310
+ entityId: string;
311
+ } | {
312
+ type: 'trade_request';
313
+ name: string;
314
+ } | {
315
+ type: 'trade_respond';
316
+ accept: boolean;
317
+ } | {
318
+ type: 'trade_offer';
319
+ item: string;
320
+ qty: number;
321
+ } | {
322
+ type: 'trade_withdraw';
323
+ item: string;
324
+ qty: number;
325
+ } | {
326
+ type: 'trade_lock';
327
+ } | {
328
+ type: 'trade_accept';
329
+ } | {
330
+ type: 'trade_cancel';
331
+ } | {
332
+ type: 'duel_request';
333
+ name: string;
334
+ } | {
335
+ type: 'duel_respond';
336
+ accept: boolean;
337
+ } | {
338
+ type: 'duel_stake';
339
+ item: string;
340
+ qty: number;
341
+ } | {
342
+ type: 'duel_withdraw';
343
+ item: string;
344
+ qty: number;
345
+ } | {
346
+ type: 'duel_lock';
347
+ } | {
348
+ type: 'duel_cancel';
349
+ }
350
+ /**
351
+ * Claims the rescued beagle, or renames one already claimed — the same
352
+ * message either way, since "name your beagle" and "rename your beagle" are
353
+ * the same operation to the server.
354
+ */
355
+ | {
356
+ type: 'upgrade_member';
357
+ } | {
358
+ type: 'beagle_claim';
359
+ name: string;
360
+ } | {
361
+ type: 'beagle_summon';
362
+ } | {
363
+ type: 'beagle_dismiss';
364
+ } | {
365
+ type: 'beagle_bark';
366
+ }
367
+ /** Feeds the pet one cooked item, the same way the quest beagle is fed. */
368
+ | {
369
+ type: 'beagle_feed';
370
+ } | {
371
+ type: 'client_error';
372
+ report: ClientErrorReport;
373
+ };
374
+ /** Crash/error diagnostics pushed from client to server so they land in server logs
375
+ * instead of only a phone's on-device console (which on TikTok can miss early boot
376
+ * output — see crashDiagnostics.ts on the client). Best-effort, not persisted server-side. */
377
+ export type ClientErrorReport = {
378
+ reason: string;
379
+ message?: string;
380
+ stack?: string;
381
+ filename?: string;
382
+ lineno?: number;
383
+ colno?: number;
384
+ elapsedSec?: number;
385
+ breadcrumbs?: string[];
386
+ scene?: Record<string, unknown>;
387
+ webglEvents?: Array<{
388
+ t: number;
389
+ type: 'lost' | 'restored';
390
+ statusMessage?: string;
391
+ }>;
392
+ samples?: Array<Record<string, unknown>>;
393
+ recoveryRan?: boolean;
394
+ resumeAttempt?: number;
395
+ };
396
+ export type ServerMessage = {
397
+ type: 'welcome';
398
+ selfId: string;
399
+ originChunk: ChunkCoord;
400
+ chunks: ChunkData[];
401
+ players: PlayerPublic[];
402
+ npcs: NpcPublic[];
403
+ config: ClientConfig;
404
+ stats: CharacterStats;
405
+ friends: string[];
406
+ inventory: Array<InventorySlot | null>;
407
+ quests: QuestsSnapshot;
408
+ equipment: EquipmentSlots;
409
+ weaponPrecision?: number | null;
410
+ ammoQty?: number;
411
+ combatStance?: CombatStance;
412
+ fishingSpot: Vec2;
413
+ /** Fixed lake fishing spots (perch / tench). */
414
+ lakeFishingSpots?: Array<{
415
+ kind: 'perch' | 'tench';
416
+ x: number;
417
+ y: number;
418
+ }>;
419
+ /** Entity kinds this character has identified (server authority). */
420
+ identified: string[];
421
+ /** Membership unlocks the pet beagle (and whatever else members get). */
422
+ isMember?: boolean;
423
+ /** Null until the rescued beagle has been claimed and named. */
424
+ beagleName?: string | null;
425
+ /** True while the beagle is following; false while dismissed to the bank. */
426
+ beagleOut?: boolean;
427
+ /** Persistent fox-NPC kill count for Anne's Protect the Rabbits quest. */
428
+ anneFoxKills?: number;
429
+ /** Persistent Goblin Soldier kill count for the Battlefield Captain. */
430
+ captainGoblinKills?: number;
431
+ } | {
432
+ type: 'join_rejected';
433
+ reason: JoinRejectedReason;
434
+ message: string;
435
+ } | {
436
+ type: 'player_joined';
437
+ player: PlayerPublic;
438
+ } | {
439
+ type: 'player_left';
440
+ id: string;
441
+ } | {
442
+ type: 'players';
443
+ players: PlayerPublic[];
444
+ } | {
445
+ type: 'npcs';
446
+ npcs: NpcPublic[];
447
+ } | {
448
+ type: 'pong';
449
+ t: number;
450
+ } | {
451
+ type: 'chunk_data';
452
+ chunks: ChunkData[];
453
+ } | {
454
+ type: 'chunk_unload';
455
+ chunks: ChunkCoord[];
456
+ } | {
457
+ type: 'ground_item_add';
458
+ cx: number;
459
+ cz: number;
460
+ entity: WorldEntity;
461
+ } | {
462
+ type: 'ground_item_remove';
463
+ entityId: string;
464
+ }
465
+ /**
466
+ * One entity changed in place (a gate swinging, a prop restyled). Replaces
467
+ * just that model; resending the whole chunk makes the client tear down and
468
+ * respawn every prop around it, which reads as a visible flash.
469
+ */
470
+ | {
471
+ type: 'entity_update';
472
+ cx: number;
473
+ cz: number;
474
+ entity: WorldEntity;
475
+ } | {
476
+ type: 'chat';
477
+ id: string;
478
+ name: string;
479
+ text: string;
480
+ } | {
481
+ type: 'pm';
482
+ from: string;
483
+ to: string;
484
+ text: string;
485
+ } | {
486
+ type: 'friends';
487
+ names: string[];
488
+ }
489
+ /** Quest hints can also appear above their NPC; popupText keeps the overhead copy brief. */
490
+ | {
491
+ type: 'notice';
492
+ text: string;
493
+ style?: NoticeStyle;
494
+ npcId?: string;
495
+ popupText?: string;
496
+ }
497
+ /** A temporary world effect. Kept generic so future hazards and blessings share the UI. */
498
+ | {
499
+ type: 'area_effect';
500
+ id: string;
501
+ active: boolean;
502
+ title: string;
503
+ detail: string;
504
+ } | {
505
+ type: 'zone';
506
+ zone: WorldZoneId;
507
+ } | {
508
+ type: 'loot';
509
+ items: LootItem[];
510
+ } | {
511
+ type: 'item_gift';
512
+ kind: string;
513
+ } | {
514
+ type: 'inventory';
515
+ slots: Array<InventorySlot | null>;
516
+ } | {
517
+ type: 'player_say';
518
+ playerId: string;
519
+ name: string;
520
+ text: string;
521
+ } | {
522
+ type: 'ate';
523
+ kind: string;
524
+ } | {
525
+ type: 'cooked';
526
+ output: string;
527
+ done: number;
528
+ total: number;
529
+ } | {
530
+ type: 'crafted';
531
+ output: string;
532
+ done: number;
533
+ total: number;
534
+ } | {
535
+ type: 'dropped';
536
+ } | {
537
+ type: 'burrow_disturbed';
538
+ x: number;
539
+ y: number;
540
+ }
541
+ /** Server confirmed a kind identification (used when forage level gates the reveal). */
542
+ | {
543
+ type: 'identified';
544
+ kind: string;
545
+ } | {
546
+ type: 'shop_open';
547
+ npcId: string;
548
+ title: string;
549
+ buy: ShopBuyEntry[];
550
+ sell: ShopSellEntry[];
551
+ } | {
552
+ type: 'shop_close';
553
+ } | {
554
+ type: 'bank_state';
555
+ tabs: Array<Array<InventorySlot | null>>;
556
+ } | {
557
+ type: 'bank_close';
558
+ } | {
559
+ type: 'woodcraft_open';
560
+ /** Recipes with the player's current eligibility resolved server-side. */
561
+ recipes: Array<{
562
+ id: string;
563
+ output: string;
564
+ outputQty: number;
565
+ level: number;
566
+ xp: number;
567
+ materials: Array<{
568
+ kind: string;
569
+ qty: number;
570
+ have: number;
571
+ }>;
572
+ craftable: boolean;
573
+ }>;
574
+ hasKnife: boolean;
575
+ } | {
576
+ type: 'woodcraft_close';
577
+ } | {
578
+ type: 'quests';
579
+ quests: QuestsSnapshot;
580
+ anneFoxKills?: number;
581
+ captainGoblinKills?: number;
582
+ } | {
583
+ type: 'quest_offer';
584
+ quest: QuestId;
585
+ npcId: string;
586
+ title: string;
587
+ description: string;
588
+ rewards: QuestReward[];
589
+ } | {
590
+ type: 'equipment';
591
+ slots: EquipmentSlots;
592
+ weaponPrecision?: number | null;
593
+ ammoQty?: number;
594
+ } | {
595
+ type: 'combat_stance';
596
+ stance: CombatStance;
597
+ } | {
598
+ type: 'npc_celebrate';
599
+ npcId: string;
600
+ } | {
601
+ type: 'npc_food_bubble';
602
+ npcId: string;
603
+ } | {
604
+ type: 'npc_say';
605
+ npcId: string;
606
+ text: string;
607
+ style?: 'warning';
608
+ } | {
609
+ type: 'fishing_spot';
610
+ x: number;
611
+ y: number;
612
+ } | {
613
+ type: 'lake_fishing_spots';
614
+ spots: Array<{
615
+ kind: 'perch' | 'tench';
616
+ x: number;
617
+ y: number;
618
+ }>;
619
+ } | {
620
+ type: 'fish_dip';
621
+ } | {
622
+ type: 'tree_fell';
623
+ entityId: string;
624
+ }
625
+ /**
626
+ * Someone worked a dungeon gate. Broadcast to everyone, not just the player
627
+ * who did it: a gate you personally cannot open should still be seen and
628
+ * heard being used by someone who can, the same way the battlefield bridge
629
+ * is crossed in front of players who have not repaired it.
630
+ */
631
+ | {
632
+ type: 'gate_used';
633
+ entityId: string;
634
+ } | {
635
+ type: 'stats';
636
+ stats: CharacterStats;
637
+ } | {
638
+ type: 'discovery';
639
+ zone: string;
640
+ label: string;
641
+ xp: number;
642
+ } | {
643
+ type: 'level_up';
644
+ playerId: string;
645
+ skill: LevelUpSkill;
646
+ level: number;
647
+ } | {
648
+ type: 'npc_flyaway';
649
+ npcId: string;
650
+ } | {
651
+ type: 'combat_start';
652
+ playerId: string;
653
+ targetId: string;
654
+ targetKind: CombatTargetKind;
655
+ } | {
656
+ type: 'combat_hit';
657
+ attackerId: string;
658
+ targetId: string;
659
+ targetKind: CombatTargetKind;
660
+ damage: number;
661
+ health: number;
662
+ healthMax: number;
663
+ /** Ranged attack flavor — client renders a projectile instead of a melee punch. */
664
+ projectile?: 'blueberry' | 'arrow';
665
+ } | {
666
+ type: 'combat_end';
667
+ playerId: string;
668
+ targetId: string;
669
+ targetKind: CombatTargetKind;
670
+ reason: CombatEndReason;
671
+ } | {
672
+ type: 'respawn';
673
+ playerId: string;
674
+ x: number;
675
+ y: number;
676
+ reason: 'defeat';
677
+ } | {
678
+ type: 'sfx';
679
+ sound: ClientSfx;
680
+ } | {
681
+ type: 'trade_invite';
682
+ fromId: string;
683
+ fromName: string;
684
+ } | {
685
+ type: 'trade_open';
686
+ session: TradeSessionSnapshot;
687
+ } | {
688
+ type: 'trade_update';
689
+ session: TradeSessionSnapshot;
690
+ } | {
691
+ type: 'trade_close';
692
+ reason: 'completed' | 'cancelled' | 'busy' | 'range' | 'left';
693
+ } | {
694
+ type: 'duel_invite';
695
+ fromId: string;
696
+ fromName: string;
697
+ } | {
698
+ type: 'duel_open';
699
+ session: DuelStakeSnapshot;
700
+ } | {
701
+ type: 'duel_update';
702
+ session: DuelStakeSnapshot;
703
+ } | {
704
+ type: 'duel_close';
705
+ reason: 'completed' | 'cancelled' | 'busy' | 'range' | 'left';
706
+ outcome?: 'won' | 'lost' | 'cancelled';
707
+ } | {
708
+ type: 'membership';
709
+ isMember: boolean;
710
+ }
711
+ /** Pushed whenever the beagle is claimed, renamed, summoned or dismissed. */
712
+ | {
713
+ type: 'beagle_state';
714
+ name: string | null;
715
+ out: boolean;
716
+ }
717
+ /** Someone patted their beagle — shown over that owner's pet, not your own. */
718
+ | {
719
+ type: 'companion_speech';
720
+ ownerId: string;
721
+ text: string;
722
+ };
723
+ //# sourceMappingURL=messages.d.ts.map