@kradle/challenges 0.0.2 → 0.2.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.
package/src/actions.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  tellraw,
26
26
  time as timeCmd,
27
27
  data,
28
+ Variable,
28
29
  } from "sandstone";
29
30
  import type { ATTRIBUTES, BLOCKS, ENTITY_TYPES, ITEMS } from "sandstone/arguments/generated";
30
31
  import { Commands } from "./commands";
@@ -54,17 +55,13 @@ export function mapTarget(target: string | SelectorClass): SelectorClass<any, an
54
55
  return Selector("@a", { tag: target }); // Assuming the target is a team name
55
56
  }
56
57
 
57
- export type Action = () => unknown;
58
-
59
58
  export const Actions = {
60
59
  /**
61
60
  * Send a chat message to everyone.
62
61
  * @param {JSONTextComponent} message - The message to send.
63
62
  */
64
63
  announce: ({ message }: { message: JSONTextComponent }) => {
65
- return () => {
66
- tellraw("@a", ["\n", { text: DISPLAY_TAG, color: "aqua" }, " | ", message, "\n"]);
67
- };
64
+ tellraw("@a", ["\n", { text: DISPLAY_TAG, color: "aqua" }, " | ", message, "\n"]);
68
65
  },
69
66
 
70
67
  /**
@@ -72,7 +69,7 @@ export const Actions = {
72
69
  * @param {TargetNames} target - The target to clear the inventory of.
73
70
  */
74
71
  clear: ({ target }: { target: TargetNames }) => {
75
- return () => clear(mapTarget(target));
72
+ clear(mapTarget(target))
76
73
  },
77
74
 
78
75
  /**
@@ -81,7 +78,7 @@ export const Actions = {
81
78
  * @param {() => void} callback - The function to execute.
82
79
  */
83
80
  custom: (callback: () => void) => {
84
- return () => callback();
81
+ callback();
85
82
  },
86
83
 
87
84
  /**
@@ -116,64 +113,62 @@ export const Actions = {
116
113
  absolute: boolean;
117
114
  mode: "fill" | "line" | "pyramid";
118
115
  }) => {
119
- return () => {
120
- // fill the region with the block
121
- if (mode === "fill") {
122
- const coordinates1 = absolute ? abs(x1, y1, z1) : rel(x1, y1, z1);
123
- const coordinates2 = absolute ? abs(x2, y2, z2) : rel(x2, y2, z2);
124
-
125
- fill(coordinates1, coordinates2, block);
126
-
127
- return;
116
+ // fill the region with the block
117
+ if (mode === "fill") {
118
+ const coordinates1 = absolute ? abs(x1, y1, z1) : rel(x1, y1, z1);
119
+ const coordinates2 = absolute ? abs(x2, y2, z2) : rel(x2, y2, z2);
120
+
121
+ fill(coordinates1, coordinates2, block);
122
+
123
+ return;
124
+ }
125
+
126
+ // draw a line from the first coordinate to the second coordinate
127
+ if (mode === "line") {
128
+ const dx = x2 - x1;
129
+ const dy = y2 - y1;
130
+ const dz = z2 - z1;
131
+
132
+ const length = Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
133
+ const stepX = dx / length || 0;
134
+ const stepY = dy / length || 0;
135
+ const stepZ = dz / length || 0;
136
+
137
+ for (let i = 0; i <= length; i++) {
138
+ const x = Math.round(x1 + stepX * i);
139
+ const y = Math.round(y1 + stepY * i);
140
+ const z = Math.round(z1 + stepZ * i);
141
+ setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
128
142
  }
129
143
 
130
- // draw a line from the first coordinate to the second coordinate
131
- if (mode === "line") {
132
- const dx = x2 - x1;
133
- const dy = y2 - y1;
134
- const dz = z2 - z1;
135
-
136
- const length = Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
137
- const stepX = dx / length || 0;
138
- const stepY = dy / length || 0;
139
- const stepZ = dz / length || 0;
140
-
141
- for (let i = 0; i <= length; i++) {
142
- const x = Math.round(x1 + stepX * i);
143
- const y = Math.round(y1 + stepY * i);
144
- const z = Math.round(z1 + stepZ * i);
145
- setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
146
- }
147
-
148
- return;
149
- }
144
+ return;
145
+ }
150
146
 
151
- if (mode === "pyramid") {
152
- const height = Math.abs(y2);
153
- const direction = Math.sign(y2); // +1 for up, -1 for down
147
+ if (mode === "pyramid") {
148
+ const height = Math.abs(y2);
149
+ const direction = Math.sign(y2); // +1 for up, -1 for down
154
150
 
155
- for (let i = 0; i < height; i++) {
156
- const y = y1 + i * direction;
157
- const layerRadius = (height - 1 - i) * 2;
151
+ for (let i = 0; i < height; i++) {
152
+ const y = y1 + i * direction;
153
+ const layerRadius = (height - 1 - i) * 2;
158
154
 
159
- const minX = x1 - layerRadius;
160
- const maxX = x1 + layerRadius;
161
- const minZ = z1 - layerRadius;
162
- const maxZ = z1 + layerRadius;
155
+ const minX = x1 - layerRadius;
156
+ const maxX = x1 + layerRadius;
157
+ const minZ = z1 - layerRadius;
158
+ const maxZ = z1 + layerRadius;
163
159
 
164
- for (let x = minX; x <= maxX; x++) {
165
- for (let z = minZ; z <= maxZ; z++) {
166
- setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
167
- }
160
+ for (let x = minX; x <= maxX; x++) {
161
+ for (let z = minZ; z <= maxZ; z++) {
162
+ setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
168
163
  }
169
164
  }
170
-
171
- return;
172
165
  }
173
166
 
174
- // if mode is not fill or line, throw an error
175
- throw new Error(`Invalid fill mode: ${mode}`);
176
- };
167
+ return;
168
+ }
169
+
170
+ // if mode is not fill or line, throw an error
171
+ throw new Error(`Invalid fill mode: ${mode}`);
177
172
  },
178
173
 
179
174
  /**
@@ -183,7 +178,7 @@ export const Actions = {
183
178
  * @param {number} count - The number of items to give.
184
179
  */
185
180
  give: ({ item, target, count = 1 }: { item: ITEMS; target: TargetNames; count?: number }) => {
186
- return () => give(mapTarget(target), item, count);
181
+ give(mapTarget(target), item, count);
187
182
  },
188
183
 
189
184
  /**
@@ -193,7 +188,7 @@ export const Actions = {
193
188
  */
194
189
  giveLoot: ({ items, target }: { items: [{ name: ITEMS; count: number; weight: number }]; target: TargetNames }) => {
195
190
  // sort incoming items and create a hash for table re-use
196
- const lootItemsSorted = items.sort((a, b) => a.name.localeCompare(b.name));
191
+ const lootItemsSorted = [...items].sort((a, b) => a.name.localeCompare(b.name));
197
192
  const lootItemsJson = JSON.stringify(lootItemsSorted);
198
193
  const lootItemsHash = crypto.createHash("sha256").update(lootItemsJson).digest("hex");
199
194
  const lootTableName = `loot_${lootItemsHash}`.slice(0, 16);
@@ -223,7 +218,7 @@ export const Actions = {
223
218
  };
224
219
 
225
220
  // on conflict, ignore because we can re-use duplicate loot tables
226
- return () => LootTable(lootTableName, lootTable, { onConflict: "ignore" }).give(mapTarget(target));
221
+ LootTable(lootTableName, lootTable, { onConflict: "ignore" }).give(mapTarget(target));
227
222
  },
228
223
 
229
224
  /**
@@ -232,7 +227,7 @@ export const Actions = {
232
227
  * @param {boolean | number} value - The value to set the gamerule to.
233
228
  */
234
229
  gamerule: ({ rule, value }: { rule: GAMERULES; value: boolean | number }) => {
235
- return () => gamerule(rule, value);
230
+ gamerule(rule, value);
236
231
  },
237
232
 
238
233
  /**
@@ -240,7 +235,7 @@ export const Actions = {
240
235
  * @param {SelectorArgument} selector - The entities to kill.
241
236
  */
242
237
  kill: ({ selector }: { selector: TargetNames }) => {
243
- return () => kill(mapTarget(selector));
238
+ kill(mapTarget(selector));
244
239
  },
245
240
 
246
241
  /**
@@ -250,9 +245,7 @@ export const Actions = {
250
245
  * @param {TargetNames} target - The target to set the attribute for.
251
246
  */
252
247
  setAttribute: ({ attribute_, value, target }: { attribute_: ATTRIBUTES; value: number; target: TargetNames }) => {
253
- return () => {
254
- execute.as(mapTarget(target)).run.attribute("@s", attribute_).baseSet(value);
255
- };
248
+ execute.as(mapTarget(target)).run.attribute("@s", attribute_).baseSet(value);
256
249
  },
257
250
 
258
251
  /**
@@ -260,7 +253,7 @@ export const Actions = {
260
253
  * @param {'day' | 'night'} time_ - The time to set.
261
254
  */
262
255
  setTime: ({ time }: { time: "day" | "night" }) => {
263
- return () => timeCmd.set(time);
256
+ timeCmd.set(time);
264
257
  },
265
258
 
266
259
  /**
@@ -274,12 +267,10 @@ export const Actions = {
274
267
  z: number;
275
268
  absolute: boolean;
276
269
  }) => {
277
- return () => {
278
- const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
279
- for (let i = 0; i < params.count; i++) {
280
- summon(params.entity, coordinates);
281
- }
282
- };
270
+ const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
271
+ for (let i = 0; i < params.count; i++) {
272
+ summon(params.entity, coordinates);
273
+ }
283
274
  },
284
275
 
285
276
  /**
@@ -287,19 +278,15 @@ export const Actions = {
287
278
  * @param {string} end_state - The end state to set.
288
279
  */
289
280
  setEndState: ({ endState }: { endState: string }) => {
290
- return () => {
291
- data.modify.storage(KRADLE_STORAGE, END_STATE_KEY).set.value(endState);
292
- };
281
+ data.modify.storage(KRADLE_STORAGE, END_STATE_KEY).set.value(endState);
293
282
  },
294
283
 
295
284
  /**
296
285
  * Set a block at a specific location.
297
286
  */
298
287
  setBlock: (params: { block: BLOCKS; x: number; y: number; z: number; absolute: boolean }) => {
299
- return () => {
300
- const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
301
- setblock(coordinates, params.block);
302
- };
288
+ const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
289
+ setblock(coordinates, params.block);
303
290
  },
304
291
 
305
292
  // teleport
@@ -327,7 +314,7 @@ export const Actions = {
327
314
  absolute: boolean;
328
315
  }) => {
329
316
  const coordinates = absolute ? abs(x, y, z) : rel(x, y, z);
330
- return () => teleport(mapTarget(target), coordinates);
317
+ teleport(mapTarget(target), coordinates);
331
318
  },
332
319
 
333
320
  /**
@@ -336,7 +323,7 @@ export const Actions = {
336
323
  * @param {TargetNames} target - The target to send the message to.
337
324
  */
338
325
  tellraw: ({ message, target }: { message: string[]; target: TargetNames }) => {
339
- return () => tellraw(mapTarget(target), message);
326
+ tellraw(mapTarget(target), message);
340
327
  },
341
328
 
342
329
  // Score operations
@@ -345,9 +332,7 @@ export const Actions = {
345
332
  * @param variable - The score variable to increment.
346
333
  */
347
334
  increment: ({ variable }: { variable: Score }) => {
348
- return () => {
349
- variable.add(1);
350
- };
335
+ variable.add(1);
351
336
  },
352
337
 
353
338
  /**
@@ -355,9 +340,7 @@ export const Actions = {
355
340
  * @param variable - The score variable to decrement.
356
341
  */
357
342
  decrement: ({ variable }: { variable: Score }) => {
358
- return () => {
359
- variable.remove(1);
360
- };
343
+ variable.remove(1);
361
344
  },
362
345
 
363
346
  /**
@@ -366,9 +349,7 @@ export const Actions = {
366
349
  * @param value - The value to set the score variable to, which can be a number or another score variable.
367
350
  */
368
351
  set: ({ variable, value }: { variable: Score; value: number | Score }) => {
369
- return () => {
370
- variable.set(value);
371
- };
352
+ variable.set(value);
372
353
  },
373
354
 
374
355
  /**
@@ -379,7 +360,7 @@ export const Actions = {
379
360
  */
380
361
  // WARNING: the logs must have precisely this structure to be read by the watcher. DO NOT CHANGE THE STRUCTURE.
381
362
  log_variable: ({ message, variable, store }: { message: string; variable: Score; store: boolean }) => {
382
- return () => Commands.logVariable(message, variable, store);
363
+ Commands.logVariable(message, variable, store);
383
364
  },
384
365
 
385
366
  /**
@@ -391,9 +372,20 @@ export const Actions = {
391
372
  * @param {boolean} absolute - Whether the coordinates are absolute or relative.
392
373
  */
393
374
  summonItem: ({ item, x, y, z, absolute }: { item: ITEMS; x: number; y: number; z: number; absolute: boolean }) => {
394
- return () => {
395
- const abs = absolute ? "" : "~";
396
- raw(`summon item ${abs}${x} ${abs}${y} ${abs}${z} {Item:{id:"${item}",Count:1b}}`);
397
- };
375
+ const abs = absolute ? "" : "~";
376
+ raw(`summon item ${abs}${x} ${abs}${y} ${abs}${z} {Item:{id:"${item}",Count:1b}}`);
377
+ },
378
+
379
+ /**
380
+ * Count the number of a specific item in a target's inventory.
381
+ * @param params - The parameters object.
382
+ * @param params.target - The target to count items for.
383
+ * @param params.item - The item to count.
384
+ * @returns The variable containing the item count.
385
+ */
386
+ countItems: ({ target, item }: { target: TargetNames; item: ITEMS }) => {
387
+ const variable = Variable();
388
+ execute.store.result.score(variable).run.clear(mapTarget(target), item, 0);
389
+ return variable;
398
390
  },
399
- } satisfies Record<string, (...args: any[]) => Action>;
391
+ } satisfies Record<string, (...args: any[]) => any>;
package/src/challenge.ts CHANGED
@@ -267,7 +267,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
267
267
  const advancementsAsScoreCustomEvents: _InputScoreCustomEventType[] = inputCustomEvents
268
268
  .filter(isAdvancementCustomEvent)
269
269
  .map((event, index) => {
270
- const trigger = (event.criteria?.[0].trigger ?? "").split("minecraft:").at(-1)!.replace(/[:/]/g, "_");
270
+ const trigger = (event.criteria?.[0].trigger ?? "").split("minecraft:").at(-1)?.replace(/[:/]/g, "_");
271
271
  const name = `adv_${trigger}__${index}`;
272
272
  const score = getOrCreateObjective(getUniqueObjectiveName(name), "dummy")("@s");
273
273
 
@@ -294,11 +294,11 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
294
294
  });
295
295
 
296
296
  return {
297
- actions: [
297
+ actions: () => {
298
298
  // First action is to reset the score to 0
299
- Actions.set({ variable: score, value: 0 }),
300
- ...event.actions,
301
- ],
299
+ Actions.set({ variable: score, value: 0 });
300
+ event.actions();
301
+ },
302
302
  mode: event.mode,
303
303
  score: score,
304
304
  };
@@ -348,7 +348,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
348
348
  // For global scores, we can directly use the condition
349
349
  comment(`Processing global custom score event ${debugName}`);
350
350
  _.if(condition, () => {
351
- actions.forEach((action) => action());
351
+ actions();
352
352
  counter.add(1);
353
353
  });
354
354
  } else {
@@ -356,7 +356,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
356
356
  comment(`Processing individual custom score event ${debugName}`);
357
357
  execute.as(ALL).run(getChildFunctionName(debugName), () => {
358
358
  _.if(condition, () => {
359
- actions.forEach((action) => action());
359
+ actions();
360
360
  counter.add(1);
361
361
  });
362
362
  });
@@ -406,7 +406,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
406
406
  }
407
407
 
408
408
  comment("3. Process the start_challenge events");
409
- this._events.start_challenge?.actions.forEach((action) => action());
409
+ this._events.start_challenge?.();
410
410
 
411
411
  comment("4. Schedule the init_participants function to run after 1s");
412
412
  init_participants.schedule("1s");
@@ -447,7 +447,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
447
447
  }
448
448
 
449
449
  comment("3. Process the init_participants events");
450
- this._events.init_participants?.actions.forEach((action) => action());
450
+ this._events.init_participants?.();
451
451
 
452
452
  comment("4. Set the game state to ON");
453
453
  this.full_variables.game_state.score.set(GAME_STATES.ON);
@@ -479,7 +479,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
479
479
  })();
480
480
 
481
481
  comment("2. Process the on_tick event");
482
- this._events.on_tick?.actions.forEach((action) => action());
482
+ this._events.on_tick?.();
483
483
 
484
484
  comment("3. Process custom events");
485
485
  MCFunction("process_custom_events", () => {
@@ -520,7 +520,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
520
520
  this.full_variables.game_state.score.set(GAME_STATES.OFF);
521
521
 
522
522
  comment("2. Process the end_challenge events");
523
- this._events.end_challenge?.actions.forEach((action) => action());
523
+ this._events.end_challenge?.();
524
524
 
525
525
  comment("3. Announce the winners");
526
526
  for (const [role, condition] of Object.entries(this._win_conditions || {})) {
@@ -528,7 +528,7 @@ export class ChallengeBase<const ROLES_NAMES extends string, const VARIABLE_NAME
528
528
  _.if(condition as ConditionType, () => {
529
529
  Actions.announce({
530
530
  message: [Selector("@s"), " has won the challenge!"],
531
- })();
531
+ });
532
532
  tag("@s").add(WINNER_TAG);
533
533
  });
534
534
  });
package/src/constants.ts CHANGED
@@ -101,7 +101,7 @@ export const BUILTIN_VARIABLES = {
101
101
  _.if(value.greaterThan(0), () => {
102
102
  Actions.announce({
103
103
  message: [Selector("@s"), " has died!"],
104
- })();
104
+ });
105
105
  value.set(0); // Reset the death count after announcing
106
106
  });
107
107
  },
@@ -115,10 +115,8 @@ export const BUILTIN_SCORE_EVENTS = (variables: Record<BUILTIN_VARIABLE_NAMES, S
115
115
  {
116
116
  mode: "repeatable",
117
117
  score: variables.main_score,
118
- actions: [
119
- () => {
120
- VISIBLE_OBJECTIVE("@s").set(variables.main_score);
121
- },
122
- ],
118
+ actions: () => {
119
+ VISIBLE_OBJECTIVE("@s").set(variables.main_score);
120
+ },
123
121
  },
124
122
  ] satisfies _InputCustomEventType[];
package/src/types.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { Score } from "sandstone";
2
2
  import type { OBJECTIVE_CRITERION } from "sandstone/arguments/generated";
3
3
  import type { AdvancementTriggers } from "sandstone/arguments/resources/AdvancementTriggers";
4
- import type { Action } from "./actions";
5
4
  import type { BUILTIN_VARIABLE_NAMES, POSSIBLE_SCENARIO_EVENTS } from "./constants";
6
5
 
7
6
  export { Actions } from "./actions";
@@ -77,7 +76,7 @@ export type _BaseConfig<ROLE_NAMES extends string, VARIABLE_NAMES extends string
77
76
  custom_variables: Record<VARIABLE_NAMES, _InputVariableType<VARIABLE_NAMES | BUILTIN_VARIABLE_NAMES>>;
78
77
  };
79
78
 
80
- export type _ScenarioEvents = Partial<Record<POSSIBLE_SCENARIO_EVENTS, { actions: Action[] }>>;
79
+ export type _ScenarioEvents = Partial<Record<POSSIBLE_SCENARIO_EVENTS, () => void>>;
81
80
 
82
81
  export type Roles<ROLES_NAMES extends string = string> = {
83
82
  [role in ROLES_NAMES]: role;
@@ -106,7 +105,7 @@ type _InputEventCommonProperties = {
106
105
  /** The mode of the event, either fire once or fire every time the score reaches the target */
107
106
  mode: "fire_once" | "repeatable";
108
107
  /** Actions to execute when the event is triggered */
109
- actions: Action[];
108
+ actions: () => void;
110
109
  };
111
110
 
112
111
  export type _InputScoreCustomEventType = {