@mythxengine/engine 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/LICENSE +21 -0
- package/dist/__tests__/advantage.test.d.ts +5 -0
- package/dist/__tests__/advantage.test.d.ts.map +1 -0
- package/dist/__tests__/advantage.test.js +126 -0
- package/dist/__tests__/advantage.test.js.map +1 -0
- package/dist/__tests__/dice.test.d.ts +2 -0
- package/dist/__tests__/dice.test.d.ts.map +1 -0
- package/dist/__tests__/dice.test.js +150 -0
- package/dist/__tests__/dice.test.js.map +1 -0
- package/dist/__tests__/resolution.test.d.ts +5 -0
- package/dist/__tests__/resolution.test.d.ts.map +1 -0
- package/dist/__tests__/resolution.test.js +362 -0
- package/dist/__tests__/resolution.test.js.map +1 -0
- package/dist/__tests__/rng.test.d.ts +2 -0
- package/dist/__tests__/rng.test.d.ts.map +1 -0
- package/dist/__tests__/rng.test.js +93 -0
- package/dist/__tests__/rng.test.js.map +1 -0
- package/dist/dice/advantage.d.ts +45 -0
- package/dist/dice/advantage.d.ts.map +1 -0
- package/dist/dice/advantage.js +118 -0
- package/dist/dice/advantage.js.map +1 -0
- package/dist/dice/index.d.ts +7 -0
- package/dist/dice/index.d.ts.map +1 -0
- package/dist/dice/index.js +7 -0
- package/dist/dice/index.js.map +1 -0
- package/dist/dice/parser.d.ts +21 -0
- package/dist/dice/parser.d.ts.map +1 -0
- package/dist/dice/parser.js +61 -0
- package/dist/dice/parser.js.map +1 -0
- package/dist/dice/roller.d.ts +23 -0
- package/dist/dice/roller.d.ts.map +1 -0
- package/dist/dice/roller.js +62 -0
- package/dist/dice/roller.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/resolution/combat.d.ts +39 -0
- package/dist/resolution/combat.d.ts.map +1 -0
- package/dist/resolution/combat.js +214 -0
- package/dist/resolution/combat.js.map +1 -0
- package/dist/resolution/damage.d.ts +27 -0
- package/dist/resolution/damage.d.ts.map +1 -0
- package/dist/resolution/damage.js +44 -0
- package/dist/resolution/damage.js.map +1 -0
- package/dist/resolution/index.d.ts +8 -0
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +8 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/initiative.d.ts +19 -0
- package/dist/resolution/initiative.d.ts.map +1 -0
- package/dist/resolution/initiative.js +55 -0
- package/dist/resolution/initiative.js.map +1 -0
- package/dist/resolution/test.d.ts +34 -0
- package/dist/resolution/test.d.ts.map +1 -0
- package/dist/resolution/test.js +143 -0
- package/dist/resolution/test.js.map +1 -0
- package/dist/rng/index.d.ts +6 -0
- package/dist/rng/index.d.ts.map +1 -0
- package/dist/rng/index.js +6 -0
- package/dist/rng/index.js.map +1 -0
- package/dist/rng/mulberry32.d.ts +13 -0
- package/dist/rng/mulberry32.d.ts.map +1 -0
- package/dist/rng/mulberry32.js +23 -0
- package/dist/rng/mulberry32.js.map +1 -0
- package/dist/rng/rng.d.ts +26 -0
- package/dist/rng/rng.d.ts.map +1 -0
- package/dist/rng/rng.js +51 -0
- package/dist/rng/rng.js.map +1 -0
- package/dist/rules/context.d.ts +86 -0
- package/dist/rules/context.d.ts.map +1 -0
- package/dist/rules/context.js +137 -0
- package/dist/rules/context.js.map +1 -0
- package/dist/rules/custom-test.d.ts +33 -0
- package/dist/rules/custom-test.d.ts.map +1 -0
- package/dist/rules/custom-test.js +164 -0
- package/dist/rules/custom-test.js.map +1 -0
- package/dist/rules/index.d.ts +6 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +6 -0
- package/dist/rules/index.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for test and combat resolution with advantage/disadvantage
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from "vitest";
|
|
5
|
+
import { resolveTest } from "../resolution/test.js";
|
|
6
|
+
import { resolveAttack } from "../resolution/combat.js";
|
|
7
|
+
import { createRNG } from "../rng/index.js";
|
|
8
|
+
// Test character factory
|
|
9
|
+
function createTestCharacter(overrides = {}) {
|
|
10
|
+
return {
|
|
11
|
+
id: "test-char",
|
|
12
|
+
name: "Test Character",
|
|
13
|
+
abilities: { STR: 2, AGI: 1, WIT: 0, CON: 1 },
|
|
14
|
+
hp: { current: 20, max: 20 },
|
|
15
|
+
skills: [
|
|
16
|
+
{ id: "combat", name: "Combat", ability: "STR", bonus: 2, description: "Fighting" },
|
|
17
|
+
{ id: "stealth", name: "Stealth", ability: "AGI", bonus: 3, description: "Sneaking" },
|
|
18
|
+
],
|
|
19
|
+
specialAbilities: [],
|
|
20
|
+
conditions: [],
|
|
21
|
+
flags: [],
|
|
22
|
+
background: "Test background",
|
|
23
|
+
personality: [],
|
|
24
|
+
psychology: { fears: [], goals: [], ambitions: [], bonds: [], flaws: [] },
|
|
25
|
+
archetypeId: "test",
|
|
26
|
+
equipment: { weapons: [], armor: null, gear: [] },
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Test enemy factory
|
|
31
|
+
function createTestEnemy(overrides = {}) {
|
|
32
|
+
return {
|
|
33
|
+
id: "test-enemy",
|
|
34
|
+
name: "Test Enemy",
|
|
35
|
+
description: "A test enemy",
|
|
36
|
+
abilities: { STR: 1, AGI: 0, WIT: -1, CON: 0 },
|
|
37
|
+
hp: { current: 15, max: 15 },
|
|
38
|
+
conditions: [],
|
|
39
|
+
attacks: [{ name: "Claw", damage: "d6", ability: "STR" }],
|
|
40
|
+
armor: 1,
|
|
41
|
+
threat: "standard",
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
describe("resolveTest with advantage", () => {
|
|
46
|
+
it("returns normal advantage state by default", () => {
|
|
47
|
+
const character = createTestCharacter();
|
|
48
|
+
const rng = createRNG(42);
|
|
49
|
+
const result = resolveTest({
|
|
50
|
+
character,
|
|
51
|
+
skill: "Stealth",
|
|
52
|
+
difficulty: 12,
|
|
53
|
+
rng,
|
|
54
|
+
});
|
|
55
|
+
expect(result.advantageState).toBe("normal");
|
|
56
|
+
expect(result.roll.advantage).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
it("applies explicit advantage sources", () => {
|
|
59
|
+
const character = createTestCharacter();
|
|
60
|
+
const rng = createRNG(42);
|
|
61
|
+
const result = resolveTest({
|
|
62
|
+
character,
|
|
63
|
+
skill: "Stealth",
|
|
64
|
+
difficulty: 12,
|
|
65
|
+
rng,
|
|
66
|
+
advantageSources: ["hiding in shadows"],
|
|
67
|
+
});
|
|
68
|
+
expect(result.advantageState).toBe("advantage");
|
|
69
|
+
expect(result.roll.advantage).toBeDefined();
|
|
70
|
+
expect(result.roll.advantage.type).toBe("advantage");
|
|
71
|
+
});
|
|
72
|
+
it("applies explicit disadvantage sources", () => {
|
|
73
|
+
const character = createTestCharacter();
|
|
74
|
+
const rng = createRNG(42);
|
|
75
|
+
const result = resolveTest({
|
|
76
|
+
character,
|
|
77
|
+
skill: "Stealth",
|
|
78
|
+
difficulty: 12,
|
|
79
|
+
rng,
|
|
80
|
+
disadvantageSources: ["noisy armor"],
|
|
81
|
+
});
|
|
82
|
+
expect(result.advantageState).toBe("disadvantage");
|
|
83
|
+
expect(result.roll.advantage).toBeDefined();
|
|
84
|
+
expect(result.roll.advantage.type).toBe("disadvantage");
|
|
85
|
+
});
|
|
86
|
+
it("cancels advantage and disadvantage", () => {
|
|
87
|
+
const character = createTestCharacter();
|
|
88
|
+
const rng = createRNG(42);
|
|
89
|
+
const result = resolveTest({
|
|
90
|
+
character,
|
|
91
|
+
skill: "Stealth",
|
|
92
|
+
difficulty: 12,
|
|
93
|
+
rng,
|
|
94
|
+
advantageSources: ["hiding in shadows"],
|
|
95
|
+
disadvantageSources: ["noisy armor"],
|
|
96
|
+
});
|
|
97
|
+
expect(result.advantageState).toBe("normal");
|
|
98
|
+
expect(result.roll.advantage).toBeUndefined();
|
|
99
|
+
});
|
|
100
|
+
it("applies advantage from conditions", () => {
|
|
101
|
+
const character = createTestCharacter({
|
|
102
|
+
conditions: [
|
|
103
|
+
{
|
|
104
|
+
id: "blessed",
|
|
105
|
+
name: "Blessed",
|
|
106
|
+
description: "Advantage on all rolls",
|
|
107
|
+
duration: 3,
|
|
108
|
+
effects: [{ type: "GRANT_ADVANTAGE", scope: "all" }],
|
|
109
|
+
stackable: false,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
const rng = createRNG(42);
|
|
114
|
+
const result = resolveTest({
|
|
115
|
+
character,
|
|
116
|
+
skill: "Stealth",
|
|
117
|
+
difficulty: 12,
|
|
118
|
+
rng,
|
|
119
|
+
});
|
|
120
|
+
expect(result.advantageState).toBe("advantage");
|
|
121
|
+
});
|
|
122
|
+
it("applies disadvantage from conditions", () => {
|
|
123
|
+
const character = createTestCharacter({
|
|
124
|
+
conditions: [
|
|
125
|
+
{
|
|
126
|
+
id: "cursed",
|
|
127
|
+
name: "Cursed",
|
|
128
|
+
description: "Disadvantage on all rolls",
|
|
129
|
+
duration: 3,
|
|
130
|
+
effects: [{ type: "GRANT_DISADVANTAGE", scope: "skill_tests" }],
|
|
131
|
+
stackable: false,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
});
|
|
135
|
+
const rng = createRNG(42);
|
|
136
|
+
const result = resolveTest({
|
|
137
|
+
character,
|
|
138
|
+
skill: "Stealth",
|
|
139
|
+
difficulty: 12,
|
|
140
|
+
rng,
|
|
141
|
+
});
|
|
142
|
+
expect(result.advantageState).toBe("disadvantage");
|
|
143
|
+
});
|
|
144
|
+
it("combines explicit and condition advantage sources", () => {
|
|
145
|
+
const character = createTestCharacter({
|
|
146
|
+
conditions: [
|
|
147
|
+
{
|
|
148
|
+
id: "blessed",
|
|
149
|
+
name: "Blessed",
|
|
150
|
+
description: "Advantage",
|
|
151
|
+
duration: 3,
|
|
152
|
+
effects: [{ type: "GRANT_ADVANTAGE", scope: "all" }],
|
|
153
|
+
stackable: false,
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
});
|
|
157
|
+
const rng = createRNG(42);
|
|
158
|
+
// Condition gives advantage, explicit gives disadvantage - should cancel
|
|
159
|
+
const result = resolveTest({
|
|
160
|
+
character,
|
|
161
|
+
skill: "Stealth",
|
|
162
|
+
difficulty: 12,
|
|
163
|
+
rng,
|
|
164
|
+
disadvantageSources: ["darkness"],
|
|
165
|
+
});
|
|
166
|
+
expect(result.advantageState).toBe("normal");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe("resolveAttack with advantage", () => {
|
|
170
|
+
const weapon = { name: "Sword", damage: "d8", ability: "STR" };
|
|
171
|
+
it("returns normal advantage state by default", () => {
|
|
172
|
+
const attacker = createTestCharacter();
|
|
173
|
+
const defender = createTestEnemy();
|
|
174
|
+
const rng = createRNG(42);
|
|
175
|
+
const result = resolveAttack({
|
|
176
|
+
attacker,
|
|
177
|
+
defender,
|
|
178
|
+
weapon,
|
|
179
|
+
rng,
|
|
180
|
+
});
|
|
181
|
+
expect(result.advantageState).toBe("normal");
|
|
182
|
+
});
|
|
183
|
+
it("applies explicit advantage on attacks", () => {
|
|
184
|
+
const attacker = createTestCharacter();
|
|
185
|
+
const defender = createTestEnemy();
|
|
186
|
+
const rng = createRNG(42);
|
|
187
|
+
const result = resolveAttack({
|
|
188
|
+
attacker,
|
|
189
|
+
defender,
|
|
190
|
+
weapon,
|
|
191
|
+
rng,
|
|
192
|
+
advantageSources: ["flanking"],
|
|
193
|
+
});
|
|
194
|
+
expect(result.advantageState).toBe("advantage");
|
|
195
|
+
expect(result.roll.advantage).toBeDefined();
|
|
196
|
+
});
|
|
197
|
+
it("applies advantage from attacker conditions", () => {
|
|
198
|
+
const attacker = createTestCharacter({
|
|
199
|
+
conditions: [
|
|
200
|
+
{
|
|
201
|
+
id: "hidden",
|
|
202
|
+
name: "Hidden",
|
|
203
|
+
description: "Advantage on attacks",
|
|
204
|
+
duration: "until_rest",
|
|
205
|
+
effects: [{ type: "GRANT_ADVANTAGE", scope: "attacks" }],
|
|
206
|
+
stackable: false,
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
});
|
|
210
|
+
const defender = createTestEnemy();
|
|
211
|
+
const rng = createRNG(42);
|
|
212
|
+
const result = resolveAttack({
|
|
213
|
+
attacker,
|
|
214
|
+
defender,
|
|
215
|
+
weapon,
|
|
216
|
+
rng,
|
|
217
|
+
});
|
|
218
|
+
expect(result.advantageState).toBe("advantage");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
describe("resolveAttack with resistance/vulnerability", () => {
|
|
222
|
+
const weapon = { name: "Fire Blade", damage: "d8", ability: "STR" };
|
|
223
|
+
it("halves damage when defender has resistance", () => {
|
|
224
|
+
const attacker = createTestCharacter();
|
|
225
|
+
const defender = createTestEnemy({
|
|
226
|
+
conditions: [
|
|
227
|
+
{
|
|
228
|
+
id: "fire-resist",
|
|
229
|
+
name: "Fire Resistant",
|
|
230
|
+
description: "Takes half fire damage",
|
|
231
|
+
duration: "permanent",
|
|
232
|
+
effects: [{ type: "RESISTANCE", damageType: "fire" }],
|
|
233
|
+
stackable: false,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
});
|
|
237
|
+
// Need to find a seed that hits
|
|
238
|
+
let result;
|
|
239
|
+
for (let seed = 1; seed < 1000; seed++) {
|
|
240
|
+
const testRng = createRNG(seed);
|
|
241
|
+
result = resolveAttack({
|
|
242
|
+
attacker,
|
|
243
|
+
defender,
|
|
244
|
+
weapon,
|
|
245
|
+
rng: testRng,
|
|
246
|
+
damageType: "fire",
|
|
247
|
+
});
|
|
248
|
+
if (result.hit && result.damage !== undefined)
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
expect(result.hit).toBe(true);
|
|
252
|
+
expect(result.damageModification).toBeDefined();
|
|
253
|
+
expect(result.damageModification.reason).toBe("resistance");
|
|
254
|
+
expect(result.damageModification.damageType).toBe("fire");
|
|
255
|
+
expect(result.damageModification.finalDamage).toBeLessThan(result.damageModification.originalDamage);
|
|
256
|
+
});
|
|
257
|
+
it("doubles damage when defender has vulnerability", () => {
|
|
258
|
+
const attacker = createTestCharacter();
|
|
259
|
+
const defender = createTestEnemy({
|
|
260
|
+
conditions: [
|
|
261
|
+
{
|
|
262
|
+
id: "fire-vuln",
|
|
263
|
+
name: "Fire Vulnerable",
|
|
264
|
+
description: "Takes double fire damage",
|
|
265
|
+
duration: "permanent",
|
|
266
|
+
effects: [{ type: "VULNERABILITY", damageType: "fire" }],
|
|
267
|
+
stackable: false,
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
});
|
|
271
|
+
// Find a seed that hits
|
|
272
|
+
let result;
|
|
273
|
+
for (let seed = 1; seed < 1000; seed++) {
|
|
274
|
+
const testRng = createRNG(seed);
|
|
275
|
+
result = resolveAttack({
|
|
276
|
+
attacker,
|
|
277
|
+
defender,
|
|
278
|
+
weapon,
|
|
279
|
+
rng: testRng,
|
|
280
|
+
damageType: "fire",
|
|
281
|
+
});
|
|
282
|
+
if (result.hit && result.damage !== undefined)
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
expect(result.hit).toBe(true);
|
|
286
|
+
expect(result.damageModification).toBeDefined();
|
|
287
|
+
expect(result.damageModification.reason).toBe("vulnerability");
|
|
288
|
+
expect(result.damageModification.finalDamage).toBeGreaterThan(result.damageModification.originalDamage);
|
|
289
|
+
});
|
|
290
|
+
it("cancels resistance and vulnerability", () => {
|
|
291
|
+
const attacker = createTestCharacter();
|
|
292
|
+
const defender = createTestEnemy({
|
|
293
|
+
conditions: [
|
|
294
|
+
{
|
|
295
|
+
id: "fire-resist",
|
|
296
|
+
name: "Fire Resistant",
|
|
297
|
+
description: "Takes half fire damage",
|
|
298
|
+
duration: "permanent",
|
|
299
|
+
effects: [{ type: "RESISTANCE", damageType: "fire" }],
|
|
300
|
+
stackable: false,
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
id: "fire-vuln",
|
|
304
|
+
name: "Cursed Vulnerability",
|
|
305
|
+
description: "Takes double fire damage",
|
|
306
|
+
duration: 3,
|
|
307
|
+
effects: [{ type: "VULNERABILITY", damageType: "fire" }],
|
|
308
|
+
stackable: false,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
// Find a seed that hits
|
|
313
|
+
let result;
|
|
314
|
+
for (let seed = 1; seed < 1000; seed++) {
|
|
315
|
+
const testRng = createRNG(seed);
|
|
316
|
+
result = resolveAttack({
|
|
317
|
+
attacker,
|
|
318
|
+
defender,
|
|
319
|
+
weapon,
|
|
320
|
+
rng: testRng,
|
|
321
|
+
damageType: "fire",
|
|
322
|
+
});
|
|
323
|
+
if (result.hit && result.damage !== undefined)
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
expect(result.hit).toBe(true);
|
|
327
|
+
// When they cancel, there should be no damageModification
|
|
328
|
+
expect(result.damageModification).toBeUndefined();
|
|
329
|
+
});
|
|
330
|
+
it("does not apply resistance to different damage types", () => {
|
|
331
|
+
const attacker = createTestCharacter();
|
|
332
|
+
const defender = createTestEnemy({
|
|
333
|
+
conditions: [
|
|
334
|
+
{
|
|
335
|
+
id: "fire-resist",
|
|
336
|
+
name: "Fire Resistant",
|
|
337
|
+
description: "Takes half fire damage",
|
|
338
|
+
duration: "permanent",
|
|
339
|
+
effects: [{ type: "RESISTANCE", damageType: "fire" }],
|
|
340
|
+
stackable: false,
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
});
|
|
344
|
+
// Find a seed that hits
|
|
345
|
+
let result;
|
|
346
|
+
for (let seed = 1; seed < 1000; seed++) {
|
|
347
|
+
const testRng = createRNG(seed);
|
|
348
|
+
result = resolveAttack({
|
|
349
|
+
attacker,
|
|
350
|
+
defender,
|
|
351
|
+
weapon,
|
|
352
|
+
rng: testRng,
|
|
353
|
+
damageType: "cold", // Different damage type
|
|
354
|
+
});
|
|
355
|
+
if (result.hit && result.damage !== undefined)
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
expect(result.hit).toBe(true);
|
|
359
|
+
expect(result.damageModification).toBeUndefined();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
//# sourceMappingURL=resolution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution.test.js","sourceRoot":"","sources":["../../src/__tests__/resolution.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,yBAAyB;AACzB,SAAS,mBAAmB,CAAC,YAAgC,EAAE;IAC7D,OAAO;QACL,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;QAC7C,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QAC5B,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE;YACnF,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE;SACtF;QACD,gBAAgB,EAAE,EAAE;QACpB,UAAU,EAAE,EAAE;QACd,KAAK,EAAE,EAAE;QACT,UAAU,EAAE,iBAAiB;QAC7B,WAAW,EAAE,EAAE;QACf,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QACzE,WAAW,EAAE,MAAM;QACnB,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QACjD,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,qBAAqB;AACrB,SAAS,eAAe,CAAC,YAA4B,EAAE;IACrD,OAAO;QACL,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,cAAc;QAC3B,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;QAC9C,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QAC5B,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACzD,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,UAAU;QAClB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;YACH,gBAAgB,EAAE,CAAC,mBAAmB,CAAC;SACxC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;YACH,mBAAmB,EAAE,CAAC,aAAa,CAAC;SACrC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;YACH,gBAAgB,EAAE,CAAC,mBAAmB,CAAC;YACvC,mBAAmB,EAAE,CAAC,aAAa,CAAC;SACrC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,SAAS,GAAG,mBAAmB,CAAC;YACpC,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,SAAS;oBACb,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,wBAAwB;oBACrC,QAAQ,EAAE,CAAC;oBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;oBACpD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,SAAS,GAAG,mBAAmB,CAAC;YACpC,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,QAAQ;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2BAA2B;oBACxC,QAAQ,EAAE,CAAC;oBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;oBAC/D,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,SAAS,GAAG,mBAAmB,CAAC;YACpC,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,SAAS;oBACb,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,WAAW;oBACxB,QAAQ,EAAE,CAAC;oBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;oBACpD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,yEAAyE;QACzE,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE;YACd,GAAG;YACH,mBAAmB,EAAE,CAAC,UAAU,CAAC;SAClC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,MAAM,MAAM,GAAW,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAEvE,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,QAAQ;YACR,QAAQ;YACR,MAAM;YACN,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,QAAQ;YACR,QAAQ;YACR,MAAM;YACN,GAAG;YACH,gBAAgB,EAAE,CAAC,UAAU,CAAC;SAC/B,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,QAAQ,GAAG,mBAAmB,CAAC;YACnC,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,QAAQ;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,sBAAsB;oBACnC,QAAQ,EAAE,YAAY;oBACtB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;oBACxD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,QAAQ;YACR,QAAQ;YACR,MAAM;YACN,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,MAAM,MAAM,GAAW,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAE5E,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,aAAa;oBACjB,IAAI,EAAE,gBAAgB;oBACtB,WAAW,EAAE,wBAAwB;oBACrC,QAAQ,EAAE,WAAW;oBACrB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;oBACrD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QACH,gCAAgC;QAChC,IAAI,MAAM,CAAC;QACX,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,aAAa,CAAC;gBACrB,QAAQ;gBACR,QAAQ;gBACR,MAAM;gBACN,GAAG,EAAE,OAAO;gBACZ,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM;QACvD,CAAC;QAED,MAAM,CAAC,MAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAO,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,CAAC,MAAO,CAAC,kBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAO,CAAC,kBAAmB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAO,CAAC,kBAAmB,CAAC,WAAW,CAAC,CAAC,YAAY,CAC1D,MAAO,CAAC,kBAAmB,CAAC,cAAc,CAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,WAAW;oBACf,IAAI,EAAE,iBAAiB;oBACvB,WAAW,EAAE,0BAA0B;oBACvC,QAAQ,EAAE,WAAW;oBACrB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;oBACxD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QAEH,wBAAwB;QACxB,IAAI,MAAM,CAAC;QACX,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,aAAa,CAAC;gBACrB,QAAQ;gBACR,QAAQ;gBACR,MAAM;gBACN,GAAG,EAAE,OAAO;gBACZ,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM;QACvD,CAAC;QAED,MAAM,CAAC,MAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAO,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,CAAC,MAAO,CAAC,kBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACjE,MAAM,CAAC,MAAO,CAAC,kBAAmB,CAAC,WAAW,CAAC,CAAC,eAAe,CAC7D,MAAO,CAAC,kBAAmB,CAAC,cAAc,CAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,aAAa;oBACjB,IAAI,EAAE,gBAAgB;oBACtB,WAAW,EAAE,wBAAwB;oBACrC,QAAQ,EAAE,WAAW;oBACrB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;oBACrD,SAAS,EAAE,KAAK;iBACjB;gBACD;oBACE,EAAE,EAAE,WAAW;oBACf,IAAI,EAAE,sBAAsB;oBAC5B,WAAW,EAAE,0BAA0B;oBACvC,QAAQ,EAAE,CAAC;oBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;oBACxD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QAEH,wBAAwB;QACxB,IAAI,MAAM,CAAC;QACX,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,aAAa,CAAC;gBACrB,QAAQ;gBACR,QAAQ;gBACR,MAAM;gBACN,GAAG,EAAE,OAAO;gBACZ,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM;QACvD,CAAC;QAED,MAAM,CAAC,MAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,0DAA0D;QAC1D,MAAM,CAAC,MAAO,CAAC,kBAAkB,CAAC,CAAC,aAAa,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,UAAU,EAAE;gBACV;oBACE,EAAE,EAAE,aAAa;oBACjB,IAAI,EAAE,gBAAgB;oBACtB,WAAW,EAAE,wBAAwB;oBACrC,QAAQ,EAAE,WAAW;oBACrB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;oBACrD,SAAS,EAAE,KAAK;iBACjB;aACF;SACF,CAAC,CAAC;QAEH,wBAAwB;QACxB,IAAI,MAAM,CAAC;QACX,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,aAAa,CAAC;gBACrB,QAAQ;gBACR,QAAQ;gBACR,MAAM;gBACN,GAAG,EAAE,OAAO;gBACZ,UAAU,EAAE,MAAM,EAAE,wBAAwB;aAC7C,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM;QACvD,CAAC;QAED,MAAM,CAAC,MAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAO,CAAC,kBAAkB,CAAC,CAAC,aAAa,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rng.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rng.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { createRNG, mulberry32 } from "../rng/index.js";
|
|
3
|
+
describe("mulberry32", () => {
|
|
4
|
+
it("produces deterministic sequences from the same seed", () => {
|
|
5
|
+
const gen1 = mulberry32(12345);
|
|
6
|
+
const gen2 = mulberry32(12345);
|
|
7
|
+
for (let i = 0; i < 100; i++) {
|
|
8
|
+
expect(gen1()).toBe(gen2());
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
it("produces different sequences from different seeds", () => {
|
|
12
|
+
const gen1 = mulberry32(12345);
|
|
13
|
+
const gen2 = mulberry32(54321);
|
|
14
|
+
// At least one of the first 10 values should differ
|
|
15
|
+
let allSame = true;
|
|
16
|
+
for (let i = 0; i < 10; i++) {
|
|
17
|
+
if (gen1() !== gen2()) {
|
|
18
|
+
allSame = false;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
expect(allSame).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it("produces values in [0, 1)", () => {
|
|
25
|
+
const gen = mulberry32(42);
|
|
26
|
+
for (let i = 0; i < 1000; i++) {
|
|
27
|
+
const val = gen();
|
|
28
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
29
|
+
expect(val).toBeLessThan(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("createRNG", () => {
|
|
34
|
+
it("creates RNG from seed", () => {
|
|
35
|
+
const rng = createRNG(12345);
|
|
36
|
+
expect(rng.getState()).toEqual({ seed: 12345, cursor: 0 });
|
|
37
|
+
});
|
|
38
|
+
it("creates RNG from state", () => {
|
|
39
|
+
const rng = createRNG({ seed: 12345, cursor: 10 });
|
|
40
|
+
expect(rng.getState()).toEqual({ seed: 12345, cursor: 10 });
|
|
41
|
+
});
|
|
42
|
+
it("advances cursor on each call", () => {
|
|
43
|
+
const rng = createRNG(12345);
|
|
44
|
+
expect(rng.getState().cursor).toBe(0);
|
|
45
|
+
rng.next();
|
|
46
|
+
expect(rng.getState().cursor).toBe(1);
|
|
47
|
+
rng.next();
|
|
48
|
+
expect(rng.getState().cursor).toBe(2);
|
|
49
|
+
});
|
|
50
|
+
it("produces deterministic integers", () => {
|
|
51
|
+
const rng1 = createRNG(12345);
|
|
52
|
+
const rng2 = createRNG(12345);
|
|
53
|
+
for (let i = 0; i < 100; i++) {
|
|
54
|
+
expect(rng1.nextInt(1, 100)).toBe(rng2.nextInt(1, 100));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
it("nextInt produces values in range", () => {
|
|
58
|
+
const rng = createRNG(42);
|
|
59
|
+
for (let i = 0; i < 1000; i++) {
|
|
60
|
+
const val = rng.nextInt(5, 15);
|
|
61
|
+
expect(val).toBeGreaterThanOrEqual(5);
|
|
62
|
+
expect(val).toBeLessThanOrEqual(15);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it("pick selects from array", () => {
|
|
66
|
+
const rng = createRNG(42);
|
|
67
|
+
const items = ["a", "b", "c", "d"];
|
|
68
|
+
for (let i = 0; i < 100; i++) {
|
|
69
|
+
expect(items).toContain(rng.pick(items));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it("shuffle returns all elements", () => {
|
|
73
|
+
const rng = createRNG(42);
|
|
74
|
+
const items = [1, 2, 3, 4, 5];
|
|
75
|
+
const shuffled = rng.shuffle(items);
|
|
76
|
+
expect(shuffled).toHaveLength(items.length);
|
|
77
|
+
expect(shuffled.sort()).toEqual(items.sort());
|
|
78
|
+
});
|
|
79
|
+
it("restoring from state continues same sequence", () => {
|
|
80
|
+
const rng1 = createRNG(12345);
|
|
81
|
+
// Advance 10 times
|
|
82
|
+
for (let i = 0; i < 10; i++) {
|
|
83
|
+
rng1.next();
|
|
84
|
+
}
|
|
85
|
+
const state = rng1.getState();
|
|
86
|
+
const expected = rng1.next();
|
|
87
|
+
// Create new RNG from state
|
|
88
|
+
const rng2 = createRNG(state);
|
|
89
|
+
const actual = rng2.next();
|
|
90
|
+
expect(actual).toBe(expected);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=rng.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rng.test.js","sourceRoot":"","sources":["../../src/__tests__/rng.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAExD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAE/B,oDAAoD;QACpD,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;gBACtB,OAAO,GAAG,KAAK,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEtC,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEtC,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAEpC,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAE9B,mBAAmB;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE7B,4BAA4B;QAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE3B,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advantage/disadvantage rolling mechanics
|
|
3
|
+
*
|
|
4
|
+
* Implements D&D 5e-style advantage/disadvantage:
|
|
5
|
+
* - Advantage: Roll 2d20, take the higher
|
|
6
|
+
* - Disadvantage: Roll 2d20, take the lower
|
|
7
|
+
* - Any advantage + any disadvantage = normal roll (they cancel)
|
|
8
|
+
* - Multiple advantages don't stack (still just 1 advantage)
|
|
9
|
+
*/
|
|
10
|
+
import type { DiceResult, RollAdvantageState, AdvantageInfo, Abilities } from "@mythxengine/types";
|
|
11
|
+
import type { RNG } from "../rng/rng.js";
|
|
12
|
+
/**
|
|
13
|
+
* Calculate the net advantage state from sources
|
|
14
|
+
*
|
|
15
|
+
* D&D 5e rules:
|
|
16
|
+
* - Any number of advantages + any number of disadvantages = normal
|
|
17
|
+
* - Multiple advantages = just advantage (no stacking)
|
|
18
|
+
* - Multiple disadvantages = just disadvantage (no stacking)
|
|
19
|
+
*/
|
|
20
|
+
export declare function calculateNetAdvantage(advantageSources: string[], disadvantageSources: string[]): RollAdvantageState;
|
|
21
|
+
/**
|
|
22
|
+
* Roll a d20 with advantage or disadvantage
|
|
23
|
+
*
|
|
24
|
+
* @param rng - Random number generator
|
|
25
|
+
* @param advantageState - Whether to roll with advantage, disadvantage, or normal
|
|
26
|
+
* @returns Object with the selected roll and advantage info
|
|
27
|
+
*/
|
|
28
|
+
export declare function rollD20WithAdvantage(rng: RNG, advantageState: RollAdvantageState): {
|
|
29
|
+
natural: number;
|
|
30
|
+
advantageInfo?: AdvantageInfo;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Roll a dice expression with advantage/disadvantage support
|
|
34
|
+
*
|
|
35
|
+
* Note: Advantage/disadvantage only applies to d20 rolls.
|
|
36
|
+
* For non-d20 rolls, the advantageState is ignored.
|
|
37
|
+
*
|
|
38
|
+
* @param expression - Dice expression (e.g., "d20", "2d6+3")
|
|
39
|
+
* @param rng - Random number generator
|
|
40
|
+
* @param advantageState - Whether to roll with advantage, disadvantage, or normal
|
|
41
|
+
* @param abilities - Optional abilities for ability modifiers
|
|
42
|
+
* @returns Dice result with advantage info if applicable
|
|
43
|
+
*/
|
|
44
|
+
export declare function rollWithAdvantage(expression: string, rng: RNG, advantageState: RollAdvantageState, abilities?: Abilities): DiceResult;
|
|
45
|
+
//# sourceMappingURL=advantage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advantage.d.ts","sourceRoot":"","sources":["../../src/dice/advantage.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,SAAS,EACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAGzC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,mBAAmB,EAAE,MAAM,EAAE,GAC5B,kBAAkB,CAkBpB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,kBAAkB,GACjC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,aAAa,CAAA;CAAE,CAoBpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,kBAAkB,EAClC,SAAS,CAAC,EAAE,SAAS,GACpB,UAAU,CAkDZ"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advantage/disadvantage rolling mechanics
|
|
3
|
+
*
|
|
4
|
+
* Implements D&D 5e-style advantage/disadvantage:
|
|
5
|
+
* - Advantage: Roll 2d20, take the higher
|
|
6
|
+
* - Disadvantage: Roll 2d20, take the lower
|
|
7
|
+
* - Any advantage + any disadvantage = normal roll (they cancel)
|
|
8
|
+
* - Multiple advantages don't stack (still just 1 advantage)
|
|
9
|
+
*/
|
|
10
|
+
import { parseDice } from "./parser.js";
|
|
11
|
+
/**
|
|
12
|
+
* Calculate the net advantage state from sources
|
|
13
|
+
*
|
|
14
|
+
* D&D 5e rules:
|
|
15
|
+
* - Any number of advantages + any number of disadvantages = normal
|
|
16
|
+
* - Multiple advantages = just advantage (no stacking)
|
|
17
|
+
* - Multiple disadvantages = just disadvantage (no stacking)
|
|
18
|
+
*/
|
|
19
|
+
export function calculateNetAdvantage(advantageSources, disadvantageSources) {
|
|
20
|
+
const hasAdvantage = advantageSources.length > 0;
|
|
21
|
+
const hasDisadvantage = disadvantageSources.length > 0;
|
|
22
|
+
if (hasAdvantage && hasDisadvantage) {
|
|
23
|
+
// They cancel out
|
|
24
|
+
return "normal";
|
|
25
|
+
}
|
|
26
|
+
if (hasAdvantage) {
|
|
27
|
+
return "advantage";
|
|
28
|
+
}
|
|
29
|
+
if (hasDisadvantage) {
|
|
30
|
+
return "disadvantage";
|
|
31
|
+
}
|
|
32
|
+
return "normal";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Roll a d20 with advantage or disadvantage
|
|
36
|
+
*
|
|
37
|
+
* @param rng - Random number generator
|
|
38
|
+
* @param advantageState - Whether to roll with advantage, disadvantage, or normal
|
|
39
|
+
* @returns Object with the selected roll and advantage info
|
|
40
|
+
*/
|
|
41
|
+
export function rollD20WithAdvantage(rng, advantageState) {
|
|
42
|
+
if (advantageState === "normal") {
|
|
43
|
+
return { natural: rng.nextInt(1, 20) };
|
|
44
|
+
}
|
|
45
|
+
// Roll two d20s
|
|
46
|
+
const roll1 = rng.nextInt(1, 20);
|
|
47
|
+
const roll2 = rng.nextInt(1, 20);
|
|
48
|
+
const isAdvantage = advantageState === "advantage";
|
|
49
|
+
const selected = isAdvantage ? Math.max(roll1, roll2) : Math.min(roll1, roll2);
|
|
50
|
+
return {
|
|
51
|
+
natural: selected,
|
|
52
|
+
advantageInfo: {
|
|
53
|
+
type: advantageState,
|
|
54
|
+
bothRolls: [roll1, roll2],
|
|
55
|
+
selected: isAdvantage ? "higher" : "lower",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Roll a dice expression with advantage/disadvantage support
|
|
61
|
+
*
|
|
62
|
+
* Note: Advantage/disadvantage only applies to d20 rolls.
|
|
63
|
+
* For non-d20 rolls, the advantageState is ignored.
|
|
64
|
+
*
|
|
65
|
+
* @param expression - Dice expression (e.g., "d20", "2d6+3")
|
|
66
|
+
* @param rng - Random number generator
|
|
67
|
+
* @param advantageState - Whether to roll with advantage, disadvantage, or normal
|
|
68
|
+
* @param abilities - Optional abilities for ability modifiers
|
|
69
|
+
* @returns Dice result with advantage info if applicable
|
|
70
|
+
*/
|
|
71
|
+
export function rollWithAdvantage(expression, rng, advantageState, abilities) {
|
|
72
|
+
const parsed = parseDice(expression);
|
|
73
|
+
// Advantage/disadvantage only applies to single d20 rolls
|
|
74
|
+
const isD20Roll = parsed.count === 1 && parsed.sides === 20;
|
|
75
|
+
let rolls;
|
|
76
|
+
let natural;
|
|
77
|
+
let advantageInfo;
|
|
78
|
+
if (isD20Roll && advantageState !== "normal") {
|
|
79
|
+
// Roll with advantage/disadvantage
|
|
80
|
+
const result = rollD20WithAdvantage(rng, advantageState);
|
|
81
|
+
natural = result.natural;
|
|
82
|
+
advantageInfo = result.advantageInfo;
|
|
83
|
+
rolls = [natural];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Normal roll
|
|
87
|
+
rolls = [];
|
|
88
|
+
for (let i = 0; i < parsed.count; i++) {
|
|
89
|
+
rolls.push(rng.nextInt(1, parsed.sides));
|
|
90
|
+
}
|
|
91
|
+
natural = rolls.reduce((sum, roll) => sum + roll, 0);
|
|
92
|
+
}
|
|
93
|
+
// Calculate modifier (including ability if specified)
|
|
94
|
+
let modifier = parsed.modifier;
|
|
95
|
+
if (parsed.ability && abilities) {
|
|
96
|
+
modifier += abilities[parsed.ability];
|
|
97
|
+
}
|
|
98
|
+
// Calculate total
|
|
99
|
+
const total = natural + modifier;
|
|
100
|
+
// Check for critical (only on d20)
|
|
101
|
+
let critical;
|
|
102
|
+
if (isD20Roll) {
|
|
103
|
+
if (natural === 20)
|
|
104
|
+
critical = "success";
|
|
105
|
+
if (natural === 1)
|
|
106
|
+
critical = "failure";
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
expression,
|
|
110
|
+
rolls,
|
|
111
|
+
modifier,
|
|
112
|
+
total,
|
|
113
|
+
natural,
|
|
114
|
+
critical,
|
|
115
|
+
advantage: advantageInfo,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=advantage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advantage.js","sourceRoot":"","sources":["../../src/dice/advantage.ts"],"names":[],"mappings":"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"}
|