@crowdedkingdoms/crowdyjs 8.2.0 → 8.3.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 (102) hide show
  1. package/README.md +21 -3
  2. package/dist/crowdy-client.d.ts.map +1 -1
  3. package/dist/crowdy-client.js +5 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/kit/blueprints/combat.d.ts +75 -0
  8. package/dist/kit/blueprints/combat.d.ts.map +1 -0
  9. package/dist/kit/blueprints/combat.js +351 -0
  10. package/dist/kit/blueprints/core.d.ts +222 -0
  11. package/dist/kit/blueprints/core.d.ts.map +1 -0
  12. package/dist/kit/blueprints/core.js +185 -0
  13. package/dist/kit/blueprints/decks.d.ts +50 -0
  14. package/dist/kit/blueprints/decks.d.ts.map +1 -0
  15. package/dist/kit/blueprints/decks.js +163 -0
  16. package/dist/kit/blueprints/economy.d.ts +88 -0
  17. package/dist/kit/blueprints/economy.d.ts.map +1 -0
  18. package/dist/kit/blueprints/economy.js +533 -0
  19. package/dist/kit/blueprints/guild.d.ts +51 -0
  20. package/dist/kit/blueprints/guild.d.ts.map +1 -0
  21. package/dist/kit/blueprints/guild.js +50 -0
  22. package/dist/kit/blueprints/index.d.ts +21 -0
  23. package/dist/kit/blueprints/index.d.ts.map +1 -0
  24. package/dist/kit/blueprints/index.js +20 -0
  25. package/dist/kit/blueprints/inventory.d.ts +38 -0
  26. package/dist/kit/blueprints/inventory.d.ts.map +1 -0
  27. package/dist/kit/blueprints/inventory.js +157 -0
  28. package/dist/kit/blueprints/leaderboards.d.ts +49 -0
  29. package/dist/kit/blueprints/leaderboards.d.ts.map +1 -0
  30. package/dist/kit/blueprints/leaderboards.js +126 -0
  31. package/dist/kit/blueprints/locks.d.ts +82 -0
  32. package/dist/kit/blueprints/locks.d.ts.map +1 -0
  33. package/dist/kit/blueprints/locks.js +155 -0
  34. package/dist/kit/blueprints/loot.d.ts +84 -0
  35. package/dist/kit/blueprints/loot.d.ts.map +1 -0
  36. package/dist/kit/blueprints/loot.js +228 -0
  37. package/dist/kit/blueprints/matches.d.ts +59 -0
  38. package/dist/kit/blueprints/matches.d.ts.map +1 -0
  39. package/dist/kit/blueprints/matches.js +246 -0
  40. package/dist/kit/blueprints/npcs.d.ts +71 -0
  41. package/dist/kit/blueprints/npcs.d.ts.map +1 -0
  42. package/dist/kit/blueprints/npcs.js +122 -0
  43. package/dist/kit/blueprints/plots.d.ts +54 -0
  44. package/dist/kit/blueprints/plots.d.ts.map +1 -0
  45. package/dist/kit/blueprints/plots.js +146 -0
  46. package/dist/kit/blueprints/progression.d.ts +68 -0
  47. package/dist/kit/blueprints/progression.d.ts.map +1 -0
  48. package/dist/kit/blueprints/progression.js +324 -0
  49. package/dist/kit/blueprints/quests.d.ts +65 -0
  50. package/dist/kit/blueprints/quests.d.ts.map +1 -0
  51. package/dist/kit/blueprints/quests.js +284 -0
  52. package/dist/kit/blueprints/worldsim.d.ts +84 -0
  53. package/dist/kit/blueprints/worldsim.d.ts.map +1 -0
  54. package/dist/kit/blueprints/worldsim.js +461 -0
  55. package/dist/kit/combat.d.ts +103 -0
  56. package/dist/kit/combat.d.ts.map +1 -0
  57. package/dist/kit/combat.js +151 -0
  58. package/dist/kit/decks.d.ts +123 -0
  59. package/dist/kit/decks.d.ts.map +1 -0
  60. package/dist/kit/decks.js +138 -0
  61. package/dist/kit/economy.d.ts +244 -0
  62. package/dist/kit/economy.d.ts.map +1 -0
  63. package/dist/kit/economy.js +365 -0
  64. package/dist/kit/features.d.ts +60 -0
  65. package/dist/kit/features.d.ts.map +1 -0
  66. package/dist/kit/features.js +65 -0
  67. package/dist/kit/index.d.ts +13 -2
  68. package/dist/kit/index.d.ts.map +1 -1
  69. package/dist/kit/index.js +12 -1
  70. package/dist/kit/inventory.d.ts +5 -0
  71. package/dist/kit/inventory.d.ts.map +1 -1
  72. package/dist/kit/inventory.js +14 -1
  73. package/dist/kit/kit.d.ts +58 -2
  74. package/dist/kit/kit.d.ts.map +1 -1
  75. package/dist/kit/kit.js +24 -2
  76. package/dist/kit/leaderboards.d.ts +66 -0
  77. package/dist/kit/leaderboards.d.ts.map +1 -0
  78. package/dist/kit/leaderboards.js +94 -0
  79. package/dist/kit/loot.d.ts +106 -0
  80. package/dist/kit/loot.d.ts.map +1 -0
  81. package/dist/kit/loot.js +120 -0
  82. package/dist/kit/matches.d.ts +140 -0
  83. package/dist/kit/matches.d.ts.map +1 -0
  84. package/dist/kit/matches.js +253 -0
  85. package/dist/kit/objects.js +1 -1
  86. package/dist/kit/plots.js +1 -1
  87. package/dist/kit/progression.d.ts +181 -0
  88. package/dist/kit/progression.d.ts.map +1 -0
  89. package/dist/kit/progression.js +265 -0
  90. package/dist/kit/quests.d.ts +110 -0
  91. package/dist/kit/quests.d.ts.map +1 -0
  92. package/dist/kit/quests.js +158 -0
  93. package/dist/kit/social.d.ts +267 -0
  94. package/dist/kit/social.d.ts.map +1 -0
  95. package/dist/kit/social.js +230 -0
  96. package/dist/kit/worldsim.d.ts +225 -0
  97. package/dist/kit/worldsim.d.ts.map +1 -0
  98. package/dist/kit/worldsim.js +231 -0
  99. package/package.json +1 -1
  100. package/dist/kit/blueprints.d.ts +0 -370
  101. package/dist/kit/blueprints.d.ts.map +0 -1
  102. package/dist/kit/blueprints.js +0 -643
@@ -0,0 +1,461 @@
1
+ import { kitPolicyJson, ownerEqualsCaller, ownerMirrorProperty, toSnakeCase, } from './core.js';
2
+ /** Compute the type/function names a worldsim blueprint (and its runtime helper) uses. */
3
+ export function worldsimNames(typePrefix = '') {
4
+ const fnPrefix = typePrefix ? `${toSnakeCase(typePrefix)}_` : '';
5
+ const autoPrefix = fnPrefix.replace(/_/g, '-');
6
+ return {
7
+ worldStateType: `${typePrefix}WorldState`,
8
+ nodeType: `${typePrefix}ResourceNode`,
9
+ cropType: `${typePrefix}Crop`,
10
+ spawnerType: `${typePrefix}WaveSpawner`,
11
+ advanceTimeFn: `${fnPrefix}advance_time`,
12
+ setWeatherFn: `${fnPrefix}set_weather`,
13
+ regenNodeFn: `${fnPrefix}regen_node`,
14
+ gatherNodeFn: `${fnPrefix}gather_node`,
15
+ growCropFn: `${fnPrefix}grow_crop`,
16
+ harvestFn: `${fnPrefix}harvest`,
17
+ spawnWaveFn: `${fnPrefix}spawn_wave`,
18
+ clockAutomation: `${autoPrefix}world-clock`,
19
+ regenAutomation: `${autoPrefix}node-regen`,
20
+ growthAutomation: `${autoPrefix}crop-growth`,
21
+ waveAutomation: `${autoPrefix}wave-spawner`,
22
+ };
23
+ }
24
+ /**
25
+ * Blueprint for **world simulation**: day/night + weather (`WorldState`
26
+ * singleton), regenerating `ResourceNode`s, growing `Crop`s / production
27
+ * jobs, and `WaveSpawner` counters — all driven by interval automations that
28
+ * run with **no client online** (the automations simulation tier: seconds,
29
+ * never per-frame).
30
+ *
31
+ * The world clock emits a **spatial notification** at the world anchor chunk
32
+ * each tick, so nearby clients update the sky push-style instead of polling;
33
+ * everything else is pull-on-demand (or wire your own notify-to-pull pings).
34
+ * Wave spawners only advance counters — actual entity spawning belongs on
35
+ * the replication plane under host authority (the BWF hybrid).
36
+ *
37
+ * Runtime counterpart: `client.kit(appId).worldsim`.
38
+ */
39
+ export function worldsimBlueprint(options = {}) {
40
+ const { typePrefix = '', ownerIdKind: kind = 'int' } = options;
41
+ const names = worldsimNames(typePrefix);
42
+ const automationOnly = kitPolicyJson({ type: 'is_automation' });
43
+ const containerTypes = [];
44
+ const propertyDefinitions = [];
45
+ const functions = [];
46
+ const automations = [];
47
+ // --- Day/night + weather ---------------------------------------------------
48
+ if (options.time !== false) {
49
+ const time = options.time === undefined ? {} : options.time;
50
+ const hoursPerDay = time.hoursPerDay ?? 24;
51
+ const weather = time.weather ?? true;
52
+ const lastHour = hoursPerDay - 1;
53
+ containerTypes.push({
54
+ typeName: names.worldStateType,
55
+ displayName: names.worldStateType,
56
+ instantiableBy: 'admin',
57
+ description: 'Singleton world clock/weather state (create one via kit.worldsim.ensureWorld).',
58
+ });
59
+ propertyDefinitions.push({
60
+ containerTypeName: names.worldStateType,
61
+ key: 'time_of_day',
62
+ valueType: 'int',
63
+ defaultValueJson: '0',
64
+ description: `In-game hour, 0..${lastHour}, advanced by the world-clock automation.`,
65
+ }, {
66
+ containerTypeName: names.worldStateType,
67
+ key: 'day',
68
+ valueType: 'int',
69
+ defaultValueJson: '0',
70
+ description: 'In-game day counter (bumps when the clock wraps).',
71
+ }, {
72
+ containerTypeName: names.worldStateType,
73
+ key: 'weather',
74
+ valueType: 'string',
75
+ defaultValueJson: '"clear"',
76
+ description: "Current weather: 'clear' | 'rain' | 'storm'.",
77
+ }, {
78
+ containerTypeName: names.worldStateType,
79
+ key: 'cx',
80
+ valueType: 'int',
81
+ defaultValueJson: '0',
82
+ description: 'Anchor chunk of the time-changed spatial notification.',
83
+ }, {
84
+ containerTypeName: names.worldStateType,
85
+ key: 'cy',
86
+ valueType: 'int',
87
+ defaultValueJson: '0',
88
+ description: 'Anchor chunk (y).',
89
+ }, {
90
+ containerTypeName: names.worldStateType,
91
+ key: 'cz',
92
+ valueType: 'int',
93
+ defaultValueJson: '0',
94
+ description: 'Anchor chunk (z).',
95
+ });
96
+ functions.push({
97
+ name: names.advanceTimeFn,
98
+ containerTypeName: names.worldStateType,
99
+ returnType: 'int',
100
+ mutations: [
101
+ {
102
+ target: 'self',
103
+ property: 'day',
104
+ expression: `if(self.time_of_day >= ${lastHour}, self.day + 1, self.day)`,
105
+ },
106
+ {
107
+ target: 'self',
108
+ property: 'time_of_day',
109
+ expression: `(self.time_of_day + 1) % ${hoursPerDay}`,
110
+ },
111
+ ...(weather
112
+ ? [
113
+ {
114
+ target: 'self',
115
+ property: 'weather',
116
+ expression: 'if(rand() < 0.7, "clear", if(rand() < 0.5, "rain", "storm"))',
117
+ },
118
+ ]
119
+ : []),
120
+ ],
121
+ returnExpression: 'self.time_of_day',
122
+ invokePolicyJson: automationOnly,
123
+ autonomousInvocable: true,
124
+ notifications: [
125
+ {
126
+ kind: 'spatial',
127
+ args: [
128
+ { name: 'chunk_x', expression: 'self.cx' },
129
+ { name: 'chunk_y', expression: 'self.cy' },
130
+ { name: 'chunk_z', expression: 'self.cz' },
131
+ { name: 'event_type', expression: '1' },
132
+ { name: 'state', expression: 'to_string(self.time_of_day)' },
133
+ { name: 'distance', expression: String(time.notifyDistance ?? 8) },
134
+ ],
135
+ },
136
+ ],
137
+ description: 'World-clock tick (automation-only): advances the hour/day, re-rolls weather, and pushes a spatial time-changed ping so nearby clients skip polling.',
138
+ });
139
+ if (weather) {
140
+ functions.push({
141
+ name: names.setWeatherFn,
142
+ containerTypeName: names.worldStateType,
143
+ returnType: 'string',
144
+ parameters: [
145
+ {
146
+ name: 'weather',
147
+ valueType: 'string',
148
+ required: true,
149
+ description: "The weather to force (e.g. 'storm').",
150
+ },
151
+ ],
152
+ mutations: [
153
+ { target: 'self', property: 'weather', expression: '$weather' },
154
+ ],
155
+ returnExpression: 'self.weather',
156
+ // not(allow) denies everyone — app admins bypass invoke policies,
157
+ // making this an admin-only lever.
158
+ invokePolicyJson: kitPolicyJson({ type: 'not', rule: { type: 'allow' } }),
159
+ description: 'Force the weather (app admins only — everyone else is denied).',
160
+ });
161
+ }
162
+ automations.push({
163
+ name: names.clockAutomation,
164
+ functionName: names.advanceTimeFn,
165
+ targetMode: 'type',
166
+ targetTypeName: names.worldStateType,
167
+ triggerType: 'schedule',
168
+ scheduleKind: 'interval',
169
+ intervalMs: time.intervalMs ?? 60000,
170
+ maxTargets: 1,
171
+ description: 'Advances the world clock (and weather) every tick.',
172
+ });
173
+ }
174
+ // --- Resource nodes ----------------------------------------------------------
175
+ if (options.nodes !== false) {
176
+ const nodes = options.nodes === undefined ? {} : options.nodes;
177
+ containerTypes.push({
178
+ typeName: names.nodeType,
179
+ displayName: names.nodeType,
180
+ instantiableBy: 'admin',
181
+ description: 'A shared harvestable resource node that regenerates server-side.',
182
+ });
183
+ propertyDefinitions.push({
184
+ containerTypeName: names.nodeType,
185
+ key: 'node_id',
186
+ valueType: 'string',
187
+ defaultValueJson: '""',
188
+ description: 'Stable node identifier.',
189
+ }, {
190
+ containerTypeName: names.nodeType,
191
+ key: 'resource_item_id',
192
+ valueType: 'string',
193
+ defaultValueJson: '""',
194
+ description: 'The item gathering yields (matched against the stack).',
195
+ }, {
196
+ containerTypeName: names.nodeType,
197
+ key: 'amount',
198
+ valueType: 'int',
199
+ defaultValueJson: '0',
200
+ description: 'Units currently available.',
201
+ }, {
202
+ containerTypeName: names.nodeType,
203
+ key: 'max_amount',
204
+ valueType: 'int',
205
+ defaultValueJson: '100',
206
+ description: 'Regeneration ceiling.',
207
+ }, {
208
+ containerTypeName: names.nodeType,
209
+ key: 'regen_rate',
210
+ valueType: 'int',
211
+ defaultValueJson: '1',
212
+ description: 'Units regenerated per tick.',
213
+ }, {
214
+ containerTypeName: names.nodeType,
215
+ key: 'x',
216
+ valueType: 'float',
217
+ defaultValueJson: '0',
218
+ description: 'World position (informational).',
219
+ }, {
220
+ containerTypeName: names.nodeType,
221
+ key: 'y',
222
+ valueType: 'float',
223
+ defaultValueJson: '0',
224
+ description: 'World position.',
225
+ }, {
226
+ containerTypeName: names.nodeType,
227
+ key: 'z',
228
+ valueType: 'float',
229
+ defaultValueJson: '0',
230
+ description: 'World position.',
231
+ });
232
+ functions.push({
233
+ name: names.regenNodeFn,
234
+ containerTypeName: names.nodeType,
235
+ returnType: 'int',
236
+ mutations: [
237
+ {
238
+ target: 'self',
239
+ property: 'amount',
240
+ expression: 'min(self.max_amount, self.amount + self.regen_rate)',
241
+ },
242
+ ],
243
+ returnExpression: 'self.amount',
244
+ invokePolicyJson: automationOnly,
245
+ autonomousInvocable: true,
246
+ description: 'Server-driven node regeneration tick (automation-only).',
247
+ }, {
248
+ name: names.gatherNodeFn,
249
+ containerTypeName: names.nodeType,
250
+ returnType: 'int',
251
+ parameters: [
252
+ {
253
+ name: 'amount',
254
+ valueType: 'int',
255
+ required: true,
256
+ description: 'Units to gather (must not exceed the node amount).',
257
+ },
258
+ {
259
+ name: 'to_stack_id',
260
+ valueType: 'container_ref',
261
+ required: true,
262
+ description: 'A caller-owned stack of the node resource that receives the units.',
263
+ },
264
+ ],
265
+ mutations: [
266
+ { target: 'self', property: 'amount', expression: 'self.amount - $amount' },
267
+ {
268
+ target: 'ref($to_stack_id)',
269
+ property: 'quantity',
270
+ expression: 'ref($to_stack_id).quantity + $amount',
271
+ },
272
+ ],
273
+ returnExpression: 'self.amount',
274
+ invokePolicyJson: kitPolicyJson({
275
+ type: 'condition',
276
+ expression: [
277
+ '$amount > 0',
278
+ 'self.amount >= $amount',
279
+ 'ref($to_stack_id).item_id == self.resource_item_id',
280
+ ownerEqualsCaller('ref($to_stack_id).owner_user_id', kind),
281
+ ].join(' && '),
282
+ }),
283
+ description: 'Gather from a shared node into your stack: the node decrement and the grant commit atomically (no over-gathering races).',
284
+ });
285
+ automations.push({
286
+ name: names.regenAutomation,
287
+ functionName: names.regenNodeFn,
288
+ targetMode: 'type',
289
+ targetTypeName: names.nodeType,
290
+ triggerType: 'schedule',
291
+ scheduleKind: 'interval',
292
+ intervalMs: nodes.intervalMs ?? 60000,
293
+ maxTargets: 64,
294
+ selectorJson: JSON.stringify({
295
+ selfWhere: [{ key: 'amount', op: '<', value: 'self.max_amount' }],
296
+ }),
297
+ description: 'Regenerates depleted resource nodes.',
298
+ });
299
+ }
300
+ // --- Crops / production jobs -------------------------------------------------
301
+ if (options.crops !== false) {
302
+ const crops = options.crops === undefined ? {} : options.crops;
303
+ containerTypes.push({
304
+ typeName: names.cropType,
305
+ displayName: names.cropType,
306
+ instantiableBy: 'member',
307
+ description: 'A planted crop / production job that matures server-side.',
308
+ });
309
+ propertyDefinitions.push(ownerMirrorProperty(names.cropType, kind), {
310
+ containerTypeName: names.cropType,
311
+ key: 'stage',
312
+ valueType: 'int',
313
+ defaultValueJson: '0',
314
+ description: 'Growth stage, advanced by the crop-growth automation.',
315
+ }, {
316
+ containerTypeName: names.cropType,
317
+ key: 'max_stage',
318
+ valueType: 'int',
319
+ defaultValueJson: '3',
320
+ description: 'Stage at which the crop is harvestable.',
321
+ }, {
322
+ containerTypeName: names.cropType,
323
+ key: 'output_item_id',
324
+ valueType: 'string',
325
+ defaultValueJson: '""',
326
+ description: 'The item harvesting yields.',
327
+ }, {
328
+ containerTypeName: names.cropType,
329
+ key: 'output_qty',
330
+ valueType: 'int',
331
+ defaultValueJson: '1',
332
+ description: 'Units yielded per harvest.',
333
+ });
334
+ functions.push({
335
+ name: names.growCropFn,
336
+ containerTypeName: names.cropType,
337
+ returnType: 'int',
338
+ mutations: [
339
+ {
340
+ target: 'self',
341
+ property: 'stage',
342
+ expression: 'min(self.stage + 1, self.max_stage)',
343
+ },
344
+ ],
345
+ returnExpression: 'self.stage',
346
+ invokePolicyJson: automationOnly,
347
+ autonomousInvocable: true,
348
+ description: 'Server-driven growth tick (automation-only).',
349
+ }, {
350
+ name: names.harvestFn,
351
+ containerTypeName: names.cropType,
352
+ returnType: 'int',
353
+ parameters: [
354
+ {
355
+ name: 'to_stack_id',
356
+ valueType: 'container_ref',
357
+ required: true,
358
+ description: 'A caller-owned stack of the output item that receives the yield.',
359
+ },
360
+ ],
361
+ mutations: [
362
+ { target: 'self', property: 'stage', expression: '0' },
363
+ {
364
+ target: 'ref($to_stack_id)',
365
+ property: 'quantity',
366
+ expression: 'ref($to_stack_id).quantity + self.output_qty',
367
+ },
368
+ ],
369
+ returnExpression: 'self.output_qty',
370
+ invokePolicyJson: kitPolicyJson({
371
+ type: 'and',
372
+ rules: [
373
+ { type: 'owner_of_self' },
374
+ {
375
+ type: 'condition',
376
+ expression: [
377
+ 'self.stage >= self.max_stage',
378
+ 'ref($to_stack_id).item_id == self.output_item_id',
379
+ ownerEqualsCaller('ref($to_stack_id).owner_user_id', kind),
380
+ ].join(' && '),
381
+ },
382
+ ],
383
+ }),
384
+ description: 'Harvest a grown crop: the stage reset and the yield grant commit atomically; regrows via the automation.',
385
+ });
386
+ automations.push({
387
+ name: names.growthAutomation,
388
+ functionName: names.growCropFn,
389
+ targetMode: 'type',
390
+ targetTypeName: names.cropType,
391
+ triggerType: 'schedule',
392
+ scheduleKind: 'interval',
393
+ intervalMs: crops.intervalMs ?? 60000,
394
+ maxTargets: 128,
395
+ selectorJson: JSON.stringify({
396
+ selfWhere: [{ key: 'stage', op: '<', value: 'self.max_stage' }],
397
+ }),
398
+ description: 'Advances growing crops one stage per tick.',
399
+ });
400
+ }
401
+ // --- Wave spawners -------------------------------------------------------------
402
+ if (options.waves) {
403
+ containerTypes.push({
404
+ typeName: names.spawnerType,
405
+ displayName: names.spawnerType,
406
+ instantiableBy: 'admin',
407
+ description: 'A wave counter the server advances; entity spawning stays host-side on the replication plane.',
408
+ });
409
+ propertyDefinitions.push({
410
+ containerTypeName: names.spawnerType,
411
+ key: 'wave',
412
+ valueType: 'int',
413
+ defaultValueJson: '0',
414
+ description: 'Current wave number.',
415
+ }, {
416
+ containerTypeName: names.spawnerType,
417
+ key: 'next_wave_size',
418
+ valueType: 'int',
419
+ defaultValueJson: '5',
420
+ description: 'Entities the host should spawn for the next wave.',
421
+ });
422
+ functions.push({
423
+ name: names.spawnWaveFn,
424
+ containerTypeName: names.spawnerType,
425
+ returnType: 'int',
426
+ mutations: [
427
+ { target: 'self', property: 'wave', expression: 'self.wave + 1' },
428
+ {
429
+ target: 'self',
430
+ property: 'next_wave_size',
431
+ expression: `self.next_wave_size + ${options.waves.growth ?? 1}`,
432
+ },
433
+ ],
434
+ returnExpression: 'self.wave',
435
+ invokePolicyJson: automationOnly,
436
+ autonomousInvocable: true,
437
+ description: 'Server-driven wave advance (automation-only): bumps the counters the host reads to spawn entities.',
438
+ });
439
+ automations.push({
440
+ name: names.waveAutomation,
441
+ functionName: names.spawnWaveFn,
442
+ targetMode: 'type',
443
+ targetTypeName: names.spawnerType,
444
+ triggerType: 'schedule',
445
+ scheduleKind: 'interval',
446
+ intervalMs: options.waves.intervalMs ?? 60000,
447
+ maxTargets: 16,
448
+ description: 'Advances wave counters on schedule.',
449
+ });
450
+ }
451
+ if (!containerTypes.length) {
452
+ throw new Error('worldsimBlueprint has every feature disabled — nothing to build');
453
+ }
454
+ return {
455
+ name: names.worldStateType,
456
+ containerTypes,
457
+ propertyDefinitions,
458
+ functions,
459
+ automations,
460
+ };
461
+ }
@@ -0,0 +1,103 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
3
+ import { type KitInvokeResult } from './shared.js';
4
+ /** Options for {@link CombatKit}. Must match the deployed combat blueprint. */
5
+ export interface CombatKitOptions {
6
+ /** The `typePrefix` the combat blueprint was deployed with. */
7
+ typePrefix?: string;
8
+ }
9
+ /** A parsed view of one combatant. */
10
+ export interface KitCombatant {
11
+ containerId: string;
12
+ displayName: string;
13
+ ownerUserId: string | null;
14
+ combatKey: string;
15
+ hp: number;
16
+ maxHp: number;
17
+ attack: number;
18
+ defense: number;
19
+ alive: boolean;
20
+ }
21
+ /** A parsed view of one status effect. */
22
+ export interface KitStatusEffect {
23
+ containerId: string;
24
+ displayName: string;
25
+ ownerUserId: string | null;
26
+ effectId: string;
27
+ targetKey: string;
28
+ magnitude: number;
29
+ ticksLeft: number;
30
+ }
31
+ /**
32
+ * Runtime helpers for the {@link combatBlueprint} conventions: spawn
33
+ * combatants, attack (server-side damage formula + death flip), arm status
34
+ * effects the tick automation applies over time, respawn, and — with
35
+ * `hostSynced` — persist host-simulated hp. Denials resolve with
36
+ * `success: false`.
37
+ *
38
+ * Obtained via `client.kit(appId).combat`.
39
+ */
40
+ export declare class CombatKit {
41
+ private readonly appId;
42
+ private readonly gameModel;
43
+ private readonly names;
44
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: CombatKitOptions);
45
+ /**
46
+ * Spawn a combatant with a unique `combat_key` (the status-effect join
47
+ * key) and the `owner_user_id` mirror.
48
+ */
49
+ spawnCombatant(input: {
50
+ ownerUserId: Scalars['BigInt']['input'];
51
+ displayName: string;
52
+ hp?: number;
53
+ maxHp?: number;
54
+ attack?: number;
55
+ defense?: number;
56
+ combatKey?: string;
57
+ sessionId?: string;
58
+ properties?: SeedPropertyInput[];
59
+ }): Promise<{
60
+ __typename?: "GmContainer";
61
+ containerId: string;
62
+ appId: string;
63
+ sessionId: string | null;
64
+ typeName: string;
65
+ displayName: string;
66
+ description: string | null;
67
+ ownerUserId: string | null;
68
+ metadataJson: string;
69
+ }>;
70
+ /** Read one combatant's state. */
71
+ state(combatantId: string): Promise<KitCombatant>;
72
+ /**
73
+ * Attack a target with your combatant. The damage formula and the death
74
+ * flip run server-side. Resolves with the target's remaining hp.
75
+ */
76
+ attack(attackerId: string, targetId: string): Promise<KitInvokeResult<number>>;
77
+ /**
78
+ * Arm a status effect against a target's `combat_key`: creates the
79
+ * caller's StatusEffect container (when `effectContainerId` is omitted)
80
+ * and invokes the gated apply function; the interval automation then
81
+ * ticks it server-side.
82
+ */
83
+ applyEffect(input: {
84
+ targetKey: string;
85
+ effectId: string;
86
+ magnitude: number;
87
+ ticks: number;
88
+ effectContainerId?: string;
89
+ sessionId?: string;
90
+ }): Promise<KitInvokeResult<number>>;
91
+ /** List the active status effects targeting a combat_key. */
92
+ effects(targetKey?: string): Promise<KitStatusEffect[]>;
93
+ /** Respawn your downed combatant at full hp. */
94
+ respawn(combatantId: string): Promise<KitInvokeResult<number>>;
95
+ /** Revive a downed combatant (blueprint deployed with `reviveGroup`). */
96
+ revive(combatantId: string): Promise<KitInvokeResult<number>>;
97
+ /**
98
+ * Persist host-simulated hp (blueprint deployed with `hostSynced: true`;
99
+ * `is_host` enforced server-side). Resolves with the clamped hp.
100
+ */
101
+ syncCombatant(combatantId: string, hp: number): Promise<KitInvokeResult<number>>;
102
+ }
103
+ //# sourceMappingURL=combat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combat.d.ts","sourceRoot":"","sources":["../../src/kit/combat.ts"],"names":[],"mappings":"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"}