@kradle/challenges 0.0.1 → 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.
- package/.github/workflows/create-release-pr.yml +76 -0
- package/.github/workflows/pr-checks.yml +30 -0
- package/.github/workflows/publish.yml +70 -0
- package/.github/workflows/tech-debt-analyzer.yaml +14 -0
- package/dist/actions.d.ts +26 -20
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +71 -82
- package/dist/actions.js.map +1 -1
- package/dist/challenge.d.ts.map +1 -1
- package/dist/challenge.js +12 -12
- package/dist/challenge.js.map +1 -1
- package/dist/commands.d.ts +9 -2
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +42 -8
- package/dist/commands.js.map +1 -1
- package/dist/constants.d.ts +3 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -7
- package/dist/constants.js.map +1 -1
- package/dist/types.d.ts +2 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/actions.ts +81 -92
- package/src/challenge.ts +12 -13
- package/src/commands.ts +43 -9
- package/src/constants.ts +7 -6
- package/src/types.ts +2 -3
package/src/actions.ts
CHANGED
|
@@ -24,10 +24,11 @@ import {
|
|
|
24
24
|
teleport,
|
|
25
25
|
tellraw,
|
|
26
26
|
time as timeCmd,
|
|
27
|
+
data,
|
|
27
28
|
} from "sandstone";
|
|
28
29
|
import type { ATTRIBUTES, BLOCKS, ENTITY_TYPES, ITEMS } from "sandstone/arguments/generated";
|
|
29
30
|
import { Commands } from "./commands";
|
|
30
|
-
import { ALL, DISPLAY_TAG } from "./constants";
|
|
31
|
+
import { ALL, DISPLAY_TAG, END_STATE_KEY, KRADLE_STORAGE } from "./constants";
|
|
31
32
|
import type { LiteralStringUnion } from "./utils";
|
|
32
33
|
|
|
33
34
|
/// Targets that can be used in Actions
|
|
@@ -53,17 +54,13 @@ export function mapTarget(target: string | SelectorClass): SelectorClass<any, an
|
|
|
53
54
|
return Selector("@a", { tag: target }); // Assuming the target is a team name
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
export type Action = () => unknown;
|
|
57
|
-
|
|
58
57
|
export const Actions = {
|
|
59
58
|
/**
|
|
60
59
|
* Send a chat message to everyone.
|
|
61
60
|
* @param {JSONTextComponent} message - The message to send.
|
|
62
61
|
*/
|
|
63
62
|
announce: ({ message }: { message: JSONTextComponent }) => {
|
|
64
|
-
|
|
65
|
-
tellraw("@a", ["\n", { text: DISPLAY_TAG, color: "aqua" }, " | ", message, "\n"]);
|
|
66
|
-
};
|
|
63
|
+
tellraw("@a", ["\n", { text: DISPLAY_TAG, color: "aqua" }, " | ", message, "\n"]);
|
|
67
64
|
},
|
|
68
65
|
|
|
69
66
|
/**
|
|
@@ -71,7 +68,7 @@ export const Actions = {
|
|
|
71
68
|
* @param {TargetNames} target - The target to clear the inventory of.
|
|
72
69
|
*/
|
|
73
70
|
clear: ({ target }: { target: TargetNames }) => {
|
|
74
|
-
|
|
71
|
+
clear(mapTarget(target))
|
|
75
72
|
},
|
|
76
73
|
|
|
77
74
|
/**
|
|
@@ -80,7 +77,7 @@ export const Actions = {
|
|
|
80
77
|
* @param {() => void} callback - The function to execute.
|
|
81
78
|
*/
|
|
82
79
|
custom: (callback: () => void) => {
|
|
83
|
-
|
|
80
|
+
callback();
|
|
84
81
|
},
|
|
85
82
|
|
|
86
83
|
/**
|
|
@@ -115,64 +112,62 @@ export const Actions = {
|
|
|
115
112
|
absolute: boolean;
|
|
116
113
|
mode: "fill" | "line" | "pyramid";
|
|
117
114
|
}) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
115
|
+
// fill the region with the block
|
|
116
|
+
if (mode === "fill") {
|
|
117
|
+
const coordinates1 = absolute ? abs(x1, y1, z1) : rel(x1, y1, z1);
|
|
118
|
+
const coordinates2 = absolute ? abs(x2, y2, z2) : rel(x2, y2, z2);
|
|
119
|
+
|
|
120
|
+
fill(coordinates1, coordinates2, block);
|
|
121
|
+
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// draw a line from the first coordinate to the second coordinate
|
|
126
|
+
if (mode === "line") {
|
|
127
|
+
const dx = x2 - x1;
|
|
128
|
+
const dy = y2 - y1;
|
|
129
|
+
const dz = z2 - z1;
|
|
130
|
+
|
|
131
|
+
const length = Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
|
|
132
|
+
const stepX = dx / length || 0;
|
|
133
|
+
const stepY = dy / length || 0;
|
|
134
|
+
const stepZ = dz / length || 0;
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i <= length; i++) {
|
|
137
|
+
const x = Math.round(x1 + stepX * i);
|
|
138
|
+
const y = Math.round(y1 + stepY * i);
|
|
139
|
+
const z = Math.round(z1 + stepZ * i);
|
|
140
|
+
setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
|
|
127
141
|
}
|
|
128
142
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const dx = x2 - x1;
|
|
132
|
-
const dy = y2 - y1;
|
|
133
|
-
const dz = z2 - z1;
|
|
134
|
-
|
|
135
|
-
const length = Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
|
|
136
|
-
const stepX = dx / length || 0;
|
|
137
|
-
const stepY = dy / length || 0;
|
|
138
|
-
const stepZ = dz / length || 0;
|
|
139
|
-
|
|
140
|
-
for (let i = 0; i <= length; i++) {
|
|
141
|
-
const x = Math.round(x1 + stepX * i);
|
|
142
|
-
const y = Math.round(y1 + stepY * i);
|
|
143
|
-
const z = Math.round(z1 + stepZ * i);
|
|
144
|
-
setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
|
|
145
|
-
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
if (mode === "pyramid") {
|
|
147
|
+
const height = Math.abs(y2);
|
|
148
|
+
const direction = Math.sign(y2); // +1 for up, -1 for down
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
const
|
|
150
|
+
for (let i = 0; i < height; i++) {
|
|
151
|
+
const y = y1 + i * direction;
|
|
152
|
+
const layerRadius = (height - 1 - i) * 2;
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
const minX = x1 - layerRadius;
|
|
155
|
+
const maxX = x1 + layerRadius;
|
|
156
|
+
const minZ = z1 - layerRadius;
|
|
157
|
+
const maxZ = z1 + layerRadius;
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const maxZ = z1 + layerRadius;
|
|
162
|
-
|
|
163
|
-
for (let x = minX; x <= maxX; x++) {
|
|
164
|
-
for (let z = minZ; z <= maxZ; z++) {
|
|
165
|
-
setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
|
|
166
|
-
}
|
|
159
|
+
for (let x = minX; x <= maxX; x++) {
|
|
160
|
+
for (let z = minZ; z <= maxZ; z++) {
|
|
161
|
+
setblock(absolute ? abs(x, y, z) : rel(x, y, z), block);
|
|
167
162
|
}
|
|
168
163
|
}
|
|
169
|
-
|
|
170
|
-
return;
|
|
171
164
|
}
|
|
172
165
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// if mode is not fill or line, throw an error
|
|
170
|
+
throw new Error(`Invalid fill mode: ${mode}`);
|
|
176
171
|
},
|
|
177
172
|
|
|
178
173
|
/**
|
|
@@ -182,7 +177,7 @@ export const Actions = {
|
|
|
182
177
|
* @param {number} count - The number of items to give.
|
|
183
178
|
*/
|
|
184
179
|
give: ({ item, target, count = 1 }: { item: ITEMS; target: TargetNames; count?: number }) => {
|
|
185
|
-
|
|
180
|
+
give(mapTarget(target), item, count);
|
|
186
181
|
},
|
|
187
182
|
|
|
188
183
|
/**
|
|
@@ -192,7 +187,7 @@ export const Actions = {
|
|
|
192
187
|
*/
|
|
193
188
|
giveLoot: ({ items, target }: { items: [{ name: ITEMS; count: number; weight: number }]; target: TargetNames }) => {
|
|
194
189
|
// sort incoming items and create a hash for table re-use
|
|
195
|
-
const lootItemsSorted = items.sort((a, b) => a.name.localeCompare(b.name));
|
|
190
|
+
const lootItemsSorted = [...items].sort((a, b) => a.name.localeCompare(b.name));
|
|
196
191
|
const lootItemsJson = JSON.stringify(lootItemsSorted);
|
|
197
192
|
const lootItemsHash = crypto.createHash("sha256").update(lootItemsJson).digest("hex");
|
|
198
193
|
const lootTableName = `loot_${lootItemsHash}`.slice(0, 16);
|
|
@@ -222,7 +217,7 @@ export const Actions = {
|
|
|
222
217
|
};
|
|
223
218
|
|
|
224
219
|
// on conflict, ignore because we can re-use duplicate loot tables
|
|
225
|
-
|
|
220
|
+
LootTable(lootTableName, lootTable, { onConflict: "ignore" }).give(mapTarget(target));
|
|
226
221
|
},
|
|
227
222
|
|
|
228
223
|
/**
|
|
@@ -231,7 +226,7 @@ export const Actions = {
|
|
|
231
226
|
* @param {boolean | number} value - The value to set the gamerule to.
|
|
232
227
|
*/
|
|
233
228
|
gamerule: ({ rule, value }: { rule: GAMERULES; value: boolean | number }) => {
|
|
234
|
-
|
|
229
|
+
gamerule(rule, value);
|
|
235
230
|
},
|
|
236
231
|
|
|
237
232
|
/**
|
|
@@ -239,7 +234,7 @@ export const Actions = {
|
|
|
239
234
|
* @param {SelectorArgument} selector - The entities to kill.
|
|
240
235
|
*/
|
|
241
236
|
kill: ({ selector }: { selector: TargetNames }) => {
|
|
242
|
-
|
|
237
|
+
kill(mapTarget(selector));
|
|
243
238
|
},
|
|
244
239
|
|
|
245
240
|
/**
|
|
@@ -249,9 +244,7 @@ export const Actions = {
|
|
|
249
244
|
* @param {TargetNames} target - The target to set the attribute for.
|
|
250
245
|
*/
|
|
251
246
|
setAttribute: ({ attribute_, value, target }: { attribute_: ATTRIBUTES; value: number; target: TargetNames }) => {
|
|
252
|
-
|
|
253
|
-
execute.as(mapTarget(target)).run.attribute("@s", attribute_).baseSet(value);
|
|
254
|
-
};
|
|
247
|
+
execute.as(mapTarget(target)).run.attribute("@s", attribute_).baseSet(value);
|
|
255
248
|
},
|
|
256
249
|
|
|
257
250
|
/**
|
|
@@ -259,7 +252,7 @@ export const Actions = {
|
|
|
259
252
|
* @param {'day' | 'night'} time_ - The time to set.
|
|
260
253
|
*/
|
|
261
254
|
setTime: ({ time }: { time: "day" | "night" }) => {
|
|
262
|
-
|
|
255
|
+
timeCmd.set(time);
|
|
263
256
|
},
|
|
264
257
|
|
|
265
258
|
/**
|
|
@@ -273,22 +266,26 @@ export const Actions = {
|
|
|
273
266
|
z: number;
|
|
274
267
|
absolute: boolean;
|
|
275
268
|
}) => {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
269
|
+
const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
|
|
270
|
+
for (let i = 0; i < params.count; i++) {
|
|
271
|
+
summon(params.entity, coordinates);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Set the end state of the challenge.
|
|
277
|
+
* @param {string} end_state - The end state to set.
|
|
278
|
+
*/
|
|
279
|
+
setEndState: ({ endState }: { endState: string }) => {
|
|
280
|
+
data.modify.storage(KRADLE_STORAGE, END_STATE_KEY).set.value(endState);
|
|
282
281
|
},
|
|
283
282
|
|
|
284
283
|
/**
|
|
285
284
|
* Set a block at a specific location.
|
|
286
285
|
*/
|
|
287
286
|
setBlock: (params: { block: BLOCKS; x: number; y: number; z: number; absolute: boolean }) => {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
setblock(coordinates, params.block);
|
|
291
|
-
};
|
|
287
|
+
const coordinates = params.absolute ? abs(params.x, params.y, params.z) : rel(params.x, params.y, params.z);
|
|
288
|
+
setblock(coordinates, params.block);
|
|
292
289
|
},
|
|
293
290
|
|
|
294
291
|
// teleport
|
|
@@ -316,7 +313,7 @@ export const Actions = {
|
|
|
316
313
|
absolute: boolean;
|
|
317
314
|
}) => {
|
|
318
315
|
const coordinates = absolute ? abs(x, y, z) : rel(x, y, z);
|
|
319
|
-
|
|
316
|
+
teleport(mapTarget(target), coordinates);
|
|
320
317
|
},
|
|
321
318
|
|
|
322
319
|
/**
|
|
@@ -325,7 +322,7 @@ export const Actions = {
|
|
|
325
322
|
* @param {TargetNames} target - The target to send the message to.
|
|
326
323
|
*/
|
|
327
324
|
tellraw: ({ message, target }: { message: string[]; target: TargetNames }) => {
|
|
328
|
-
|
|
325
|
+
tellraw(mapTarget(target), message);
|
|
329
326
|
},
|
|
330
327
|
|
|
331
328
|
// Score operations
|
|
@@ -334,9 +331,7 @@ export const Actions = {
|
|
|
334
331
|
* @param variable - The score variable to increment.
|
|
335
332
|
*/
|
|
336
333
|
increment: ({ variable }: { variable: Score }) => {
|
|
337
|
-
|
|
338
|
-
variable.add(1);
|
|
339
|
-
};
|
|
334
|
+
variable.add(1);
|
|
340
335
|
},
|
|
341
336
|
|
|
342
337
|
/**
|
|
@@ -344,9 +339,7 @@ export const Actions = {
|
|
|
344
339
|
* @param variable - The score variable to decrement.
|
|
345
340
|
*/
|
|
346
341
|
decrement: ({ variable }: { variable: Score }) => {
|
|
347
|
-
|
|
348
|
-
variable.remove(1);
|
|
349
|
-
};
|
|
342
|
+
variable.remove(1);
|
|
350
343
|
},
|
|
351
344
|
|
|
352
345
|
/**
|
|
@@ -355,9 +348,7 @@ export const Actions = {
|
|
|
355
348
|
* @param value - The value to set the score variable to, which can be a number or another score variable.
|
|
356
349
|
*/
|
|
357
350
|
set: ({ variable, value }: { variable: Score; value: number | Score }) => {
|
|
358
|
-
|
|
359
|
-
variable.set(value);
|
|
360
|
-
};
|
|
351
|
+
variable.set(value);
|
|
361
352
|
},
|
|
362
353
|
|
|
363
354
|
/**
|
|
@@ -368,7 +359,7 @@ export const Actions = {
|
|
|
368
359
|
*/
|
|
369
360
|
// WARNING: the logs must have precisely this structure to be read by the watcher. DO NOT CHANGE THE STRUCTURE.
|
|
370
361
|
log_variable: ({ message, variable, store }: { message: string; variable: Score; store: boolean }) => {
|
|
371
|
-
|
|
362
|
+
Commands.logVariable(message, variable, store);
|
|
372
363
|
},
|
|
373
364
|
|
|
374
365
|
/**
|
|
@@ -380,9 +371,7 @@ export const Actions = {
|
|
|
380
371
|
* @param {boolean} absolute - Whether the coordinates are absolute or relative.
|
|
381
372
|
*/
|
|
382
373
|
summonItem: ({ item, x, y, z, absolute }: { item: ITEMS; x: number; y: number; z: number; absolute: boolean }) => {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
raw(`summon item ${abs}${x} ${abs}${y} ${abs}${z} {Item:{id:"${item}",Count:1b}}`);
|
|
386
|
-
};
|
|
374
|
+
const abs = absolute ? "" : "~";
|
|
375
|
+
raw(`summon item ${abs}${x} ${abs}${y} ${abs}${z} {Item:{id:"${item}",Count:1b}}`);
|
|
387
376
|
},
|
|
388
|
-
} satisfies Record<string, (...args: any[]) =>
|
|
377
|
+
} satisfies Record<string, (...args: any[]) => void | undefined>;
|
package/src/challenge.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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?.
|
|
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?.
|
|
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?.
|
|
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?.
|
|
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,13 +528,12 @@ 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
|
});
|
|
535
535
|
}
|
|
536
|
-
|
|
537
|
-
Commands.declareWinners();
|
|
536
|
+
Commands.gameOver();
|
|
538
537
|
});
|
|
539
538
|
|
|
540
539
|
savePack("datapack", {
|
package/src/commands.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _, type JSONTextComponent, type Score, Selector, type SelectorClass, tellraw } from "sandstone";
|
|
2
|
-
import { WATCHER, WINNER_TAG } from "./constants";
|
|
2
|
+
import { END_STATE_KEY, KRADLE_STORAGE, WATCHER, WINNER_TAG } from "./constants";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Converts a Sandstone Selector to a JSON Text Component that will be displayed like a JSON array in the chat.
|
|
@@ -43,6 +43,27 @@ function selectorToJSONString(selector: SelectorClass<any, any>): JSONTextCompon
|
|
|
43
43
|
return ['"', { selector: selector.toString(), separator: "," } as any, '"'];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Converts a storage to a JSON string that will be displayed like a JSON string in the chat.
|
|
48
|
+
* @param storage The storage holding the value to convert.
|
|
49
|
+
* @param storageKey The key of the value to convert in the storage.
|
|
50
|
+
* @returns A JSON string that will be displayed like a JSON string in the chat.
|
|
51
|
+
*
|
|
52
|
+
*
|
|
53
|
+
* If the value is found in the storage, it will be sent as a JSON string.
|
|
54
|
+
* Ex: { "end_state": "win" }
|
|
55
|
+
*
|
|
56
|
+
* If the value is not found in the storage, an empty string will be sent.
|
|
57
|
+
* Ex: { "end_state": "" }
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
function storageToJSONString(storage: string, storageKey: string): JSONTextComponent[] {
|
|
61
|
+
return ['"', {
|
|
62
|
+
storage: storage,
|
|
63
|
+
nbt: storageKey,
|
|
64
|
+
}, '"'];
|
|
65
|
+
}
|
|
66
|
+
|
|
46
67
|
/**
|
|
47
68
|
* Commands for interacting with Kradle's Watcher.
|
|
48
69
|
*/
|
|
@@ -83,7 +104,11 @@ export const Commands = {
|
|
|
83
104
|
return value.toString();
|
|
84
105
|
}
|
|
85
106
|
if (typeof value === "string") {
|
|
86
|
-
|
|
107
|
+
try {
|
|
108
|
+
JSON.parse(value);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
throw new Error(`When using Commands.raw with string values, they must represent a valid JSON object. Invalid JSON string: ${value}`);
|
|
111
|
+
}
|
|
87
112
|
}
|
|
88
113
|
return value;
|
|
89
114
|
}
|
|
@@ -99,26 +124,35 @@ export const Commands = {
|
|
|
99
124
|
},
|
|
100
125
|
|
|
101
126
|
/**
|
|
102
|
-
*
|
|
127
|
+
* Game over command - sends a command to Kradle's Watcher to end the challenge.
|
|
128
|
+
* This will also announce the winners and the end state.
|
|
103
129
|
*
|
|
104
130
|
* The `winners` argument of the payload will be a JSON list of player names.
|
|
105
131
|
* Ex: { "winners": ["player1", "player2"] }
|
|
106
132
|
*
|
|
107
133
|
* If no winners are selected, an empty array will be sent.
|
|
108
134
|
* Ex: { "winners": [] }
|
|
135
|
+
*
|
|
136
|
+
* The `end_state` argument of the payload will be a JSON string that represents the end state of the challenge.
|
|
137
|
+
* Ex: { "end_state": "win" }
|
|
138
|
+
*
|
|
139
|
+
* If no end state is selected, an empty string will be sent.
|
|
140
|
+
* Ex: { "end_state": "" }
|
|
109
141
|
*/
|
|
110
|
-
|
|
142
|
+
gameOver: () => {
|
|
111
143
|
const selector = Selector("@a", { tag: WINNER_TAG });
|
|
112
144
|
|
|
113
145
|
// If no winners are selected, we send them as a JSON array.
|
|
114
146
|
_.if(selector, () => {
|
|
115
|
-
Commands.raw("
|
|
147
|
+
Commands.raw("game_over", {
|
|
116
148
|
winners: selectorToJSONArray(selector),
|
|
149
|
+
end_state: storageToJSONString(KRADLE_STORAGE, END_STATE_KEY),
|
|
117
150
|
});
|
|
118
151
|
}).else(() => {
|
|
119
152
|
// Else, we send an empty array.
|
|
120
|
-
Commands.raw("
|
|
121
|
-
winners:
|
|
153
|
+
Commands.raw("game_over", {
|
|
154
|
+
winners: JSON.stringify([]),
|
|
155
|
+
end_state: storageToJSONString(KRADLE_STORAGE, END_STATE_KEY),
|
|
122
156
|
});
|
|
123
157
|
});
|
|
124
158
|
},
|
|
@@ -128,13 +162,13 @@ export const Commands = {
|
|
|
128
162
|
const variableName = variable.target.toString();
|
|
129
163
|
|
|
130
164
|
return Commands.raw("log_variable", {
|
|
131
|
-
message,
|
|
165
|
+
message: JSON.stringify(message),
|
|
132
166
|
store,
|
|
133
167
|
variable: JSON.stringify({
|
|
134
168
|
objective: objectiveName,
|
|
135
169
|
selector: variableName,
|
|
136
170
|
}),
|
|
137
|
-
value: variable,
|
|
171
|
+
value: JSON.stringify(variable),
|
|
138
172
|
targets: selectorToJSONString(Selector(variableName as any)),
|
|
139
173
|
});
|
|
140
174
|
},
|
package/src/constants.ts
CHANGED
|
@@ -16,6 +16,9 @@ export const KRADLE_PARTICIPANT_TAG = "kradle_participant";
|
|
|
16
16
|
export const WINNER_TAG = "kradle_winner";
|
|
17
17
|
export const DISPLAY_TAG = "***KRADLE***";
|
|
18
18
|
|
|
19
|
+
export const KRADLE_STORAGE = "kradle_storage";
|
|
20
|
+
export const END_STATE_KEY = "end_state";
|
|
21
|
+
|
|
19
22
|
export const MAX_DURATION = 5 * 60 * 20; // 5 minutes in ticks
|
|
20
23
|
|
|
21
24
|
/// The selector that targets all participants in the game.
|
|
@@ -98,7 +101,7 @@ export const BUILTIN_VARIABLES = {
|
|
|
98
101
|
_.if(value.greaterThan(0), () => {
|
|
99
102
|
Actions.announce({
|
|
100
103
|
message: [Selector("@s"), " has died!"],
|
|
101
|
-
})
|
|
104
|
+
});
|
|
102
105
|
value.set(0); // Reset the death count after announcing
|
|
103
106
|
});
|
|
104
107
|
},
|
|
@@ -112,10 +115,8 @@ export const BUILTIN_SCORE_EVENTS = (variables: Record<BUILTIN_VARIABLE_NAMES, S
|
|
|
112
115
|
{
|
|
113
116
|
mode: "repeatable",
|
|
114
117
|
score: variables.main_score,
|
|
115
|
-
actions:
|
|
116
|
-
()
|
|
117
|
-
|
|
118
|
-
},
|
|
119
|
-
],
|
|
118
|
+
actions: () => {
|
|
119
|
+
VISIBLE_OBJECTIVE("@s").set(variables.main_score);
|
|
120
|
+
},
|
|
120
121
|
},
|
|
121
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,
|
|
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:
|
|
108
|
+
actions: () => void;
|
|
110
109
|
};
|
|
111
110
|
|
|
112
111
|
export type _InputScoreCustomEventType = {
|