@dicelette/core 1.28.1 → 1.28.2
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/dist/index.d.mts +26 -15
- package/dist/index.d.ts +26 -15
- package/dist/index.js +502 -429
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +496 -424
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
replaceFormulaInDice: () => replaceFormulaInDice,
|
|
61
61
|
replaceInFormula: () => replaceInFormula,
|
|
62
62
|
replaceUnknown: () => replaceUnknown,
|
|
63
|
+
resolveFormulaHint: () => resolveFormulaHint,
|
|
63
64
|
roll: () => roll,
|
|
64
65
|
standardizeDice: () => standardizeDice,
|
|
65
66
|
templateSchema: () => templateSchema,
|
|
@@ -277,211 +278,259 @@ function includeDiceType(dice, diceType, userStats) {
|
|
|
277
278
|
}
|
|
278
279
|
|
|
279
280
|
// src/roll.ts
|
|
280
|
-
var
|
|
281
|
-
var
|
|
281
|
+
var import_rpg_dice_roller8 = require("@dice-roller/rpg-dice-roller");
|
|
282
|
+
var import_mathjs10 = require("mathjs");
|
|
282
283
|
|
|
283
284
|
// src/dice/bulk.ts
|
|
284
|
-
var
|
|
285
|
-
var
|
|
285
|
+
var import_rpg_dice_roller7 = require("@dice-roller/rpg-dice-roller");
|
|
286
|
+
var import_mathjs8 = require("mathjs");
|
|
286
287
|
|
|
287
288
|
// src/dice/compare.ts
|
|
288
|
-
var
|
|
289
|
+
var import_rpg_dice_roller4 = require("@dice-roller/rpg-dice-roller");
|
|
289
290
|
var import_mathjs2 = require("mathjs");
|
|
290
291
|
|
|
291
292
|
// src/utils.ts
|
|
293
|
+
var import_uniformize2 = require("uniformize");
|
|
294
|
+
var import_rpg_dice_roller3 = require("@dice-roller/rpg-dice-roller");
|
|
295
|
+
var import_random_js2 = require("random-js");
|
|
296
|
+
|
|
297
|
+
// src/verify_template.ts
|
|
292
298
|
var import_mathjs = require("mathjs");
|
|
299
|
+
var import_random_js = require("random-js");
|
|
293
300
|
var import_uniformize = require("uniformize");
|
|
294
301
|
var import_rpg_dice_roller2 = require("@dice-roller/rpg-dice-roller");
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
function levenshteinDistance(str1, str2) {
|
|
306
|
-
const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
|
|
307
|
-
for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;
|
|
308
|
-
for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;
|
|
309
|
-
for (let j = 1; j <= str2.length; j++) {
|
|
310
|
-
for (let i = 1; i <= str1.length; i++) {
|
|
311
|
-
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
312
|
-
matrix[j][i] = Math.min(
|
|
313
|
-
matrix[j][i - 1] + 1,
|
|
314
|
-
// insertion
|
|
315
|
-
matrix[j - 1][i] + 1,
|
|
316
|
-
// deletion
|
|
317
|
-
matrix[j - 1][i - 1] + cost
|
|
318
|
-
// substitution
|
|
319
|
-
);
|
|
302
|
+
function evalStatsDice(testDice, allStats, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto, pity) {
|
|
303
|
+
let dice = testDice.trimEnd();
|
|
304
|
+
if (allStats && Object.keys(allStats).length > 0) {
|
|
305
|
+
const names = Object.keys(allStats);
|
|
306
|
+
for (const name of names) {
|
|
307
|
+
const regex = new RegExp(escapeRegex(name.standardize()), "gi");
|
|
308
|
+
if (dice.standardize().match(regex)) {
|
|
309
|
+
const statValue = allStats[name];
|
|
310
|
+
dice = dice.standardize().replace(regex, statValue.toString()).trimEnd();
|
|
311
|
+
}
|
|
320
312
|
}
|
|
321
313
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
for (const [normalizedKey, original] of normalizedStats) {
|
|
329
|
-
if (normalizedKey.startsWith(searchTerm))
|
|
330
|
-
candidates.push([original, calculateSimilarity(searchTerm, normalizedKey)]);
|
|
331
|
-
}
|
|
332
|
-
if (candidates.length === 1) return candidates[0][0];
|
|
333
|
-
if (candidates.length > 0) {
|
|
334
|
-
candidates.sort((a, b) => b[1] - a[1]);
|
|
335
|
-
if (candidates[0][1] >= similarityThreshold) return candidates[0][0];
|
|
336
|
-
}
|
|
337
|
-
let bestMatch;
|
|
338
|
-
let bestSimilarity = 0;
|
|
339
|
-
for (const [normalizedKey, original] of normalizedStats) {
|
|
340
|
-
const similarity = calculateSimilarity(searchTerm, normalizedKey);
|
|
341
|
-
if (similarity === 1) return original;
|
|
342
|
-
if (similarity > bestSimilarity && similarity >= similarityThreshold) {
|
|
343
|
-
bestSimilarity = similarity;
|
|
344
|
-
bestMatch = original;
|
|
345
|
-
}
|
|
314
|
+
try {
|
|
315
|
+
if (!roll(replaceFormulaInDice(replaceExpByRandom(dice)), engine, pity))
|
|
316
|
+
throw new DiceTypeError(dice, "evalStatsDice", "no roll result");
|
|
317
|
+
return testDice;
|
|
318
|
+
} catch (error) {
|
|
319
|
+
throw new DiceTypeError(dice, "evalStatsDice", error);
|
|
346
320
|
}
|
|
347
|
-
return bestMatch;
|
|
348
321
|
}
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
322
|
+
function diceRandomParse(value, template, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
323
|
+
if (!template.statistics) return replaceFormulaInDice(value.standardize());
|
|
324
|
+
value = value.standardize();
|
|
325
|
+
const statNames = Object.keys(template.statistics);
|
|
326
|
+
let newDice = value;
|
|
327
|
+
for (const name of statNames) {
|
|
328
|
+
const regex = new RegExp(escapeRegex(name.standardize()), "gi");
|
|
329
|
+
if (value.match(regex)) {
|
|
330
|
+
let max;
|
|
331
|
+
let min;
|
|
332
|
+
const foundStat = template.statistics?.[name];
|
|
333
|
+
if (foundStat) {
|
|
334
|
+
max = foundStat.max;
|
|
335
|
+
min = foundStat.min;
|
|
336
|
+
}
|
|
337
|
+
const total = template.total || 100;
|
|
338
|
+
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
339
|
+
newDice = value.replace(regex, randomStatValue.toString());
|
|
340
|
+
}
|
|
353
341
|
}
|
|
354
|
-
return
|
|
355
|
-
searchTerm.standardize(),
|
|
356
|
-
normalizeRecord,
|
|
357
|
-
similarityThreshold
|
|
358
|
-
) || null;
|
|
342
|
+
return replaceFormulaInDice(newDice);
|
|
359
343
|
}
|
|
360
|
-
function
|
|
361
|
-
|
|
344
|
+
function diceTypeRandomParse(dice, template, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
345
|
+
dice = replaceExpByRandom(dice);
|
|
346
|
+
if (!template.statistics) return dice;
|
|
347
|
+
const firstStatNotcombinaison = Object.keys(template.statistics).find(
|
|
348
|
+
(stat) => !template.statistics?.[stat].combinaison
|
|
349
|
+
);
|
|
350
|
+
if (!firstStatNotcombinaison) return dice;
|
|
351
|
+
const stats = template.statistics[firstStatNotcombinaison];
|
|
352
|
+
const { min, max } = stats;
|
|
353
|
+
const total = template.total || 100;
|
|
354
|
+
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
355
|
+
return replaceFormulaInDice(dice.replaceAll("$", randomStatValue.toString()));
|
|
362
356
|
}
|
|
363
|
-
function
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
357
|
+
function evalCombinaison(combinaison, stats) {
|
|
358
|
+
const newStats = {};
|
|
359
|
+
for (const [stat, combin] of Object.entries(combinaison)) {
|
|
360
|
+
let formula = combin.standardize();
|
|
361
|
+
for (const [statName, value] of Object.entries(stats)) {
|
|
362
|
+
const regex = new RegExp(statName.standardize(), "gi");
|
|
363
|
+
formula = formula.replace(regex, value.toString());
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
newStats[stat] = (0, import_mathjs.evaluate)(formula);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
throw new FormulaError(stat, "evalCombinaison", error);
|
|
369
|
+
}
|
|
370
370
|
}
|
|
371
|
-
return
|
|
371
|
+
return newStats;
|
|
372
372
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
function evalOneCombinaison(combinaison, stats) {
|
|
374
|
+
let formula = combinaison.standardize();
|
|
375
|
+
for (const [statName, value] of Object.entries(stats)) {
|
|
376
|
+
const regex = new RegExp(statName.standardize(), "gi");
|
|
377
|
+
formula = formula.replace(regex, value.toString());
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
return (0, import_mathjs.evaluate)(formula);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
throw new FormulaError(combinaison, "evalOneCombinaison", error);
|
|
383
|
+
}
|
|
377
384
|
}
|
|
378
|
-
function
|
|
379
|
-
return
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
);
|
|
385
|
+
function convertNumber(number) {
|
|
386
|
+
if (number === void 0 || number === null) return void 0;
|
|
387
|
+
if (number.toString().length === 0 || Number.isNaN(Number.parseInt(number.toString(), 10)))
|
|
388
|
+
return void 0;
|
|
389
|
+
if (isNumber(number)) return Number.parseInt(number.toString(), 10);
|
|
390
|
+
return void 0;
|
|
383
391
|
}
|
|
384
|
-
function
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
392
|
+
function verifyTemplateValue(template, verify = true, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
393
|
+
const parsedTemplate = templateSchema.parse(template);
|
|
394
|
+
const { success, failure } = parsedTemplate.critical ?? {};
|
|
395
|
+
const criticicalVal = {
|
|
396
|
+
success: convertNumber(success),
|
|
397
|
+
failure: convertNumber(failure)
|
|
398
|
+
};
|
|
399
|
+
const statistiqueTemplate = {
|
|
400
|
+
diceType: parsedTemplate.diceType,
|
|
401
|
+
statistics: parsedTemplate.statistics,
|
|
402
|
+
critical: criticicalVal,
|
|
403
|
+
total: parsedTemplate.total,
|
|
404
|
+
charName: parsedTemplate.charName,
|
|
405
|
+
damage: parsedTemplate.damage,
|
|
406
|
+
customCritical: parsedTemplate.customCritical,
|
|
407
|
+
forceDistrib: parsedTemplate.forceDistrib
|
|
408
|
+
};
|
|
409
|
+
if (!verify) return statistiqueTemplate;
|
|
410
|
+
if (statistiqueTemplate.diceType) {
|
|
411
|
+
if (statistiqueTemplate.diceType.match(DETECT_CRITICAL)) {
|
|
412
|
+
throw new DiceTypeError(
|
|
413
|
+
statistiqueTemplate.diceType,
|
|
414
|
+
"critical_dice_type",
|
|
415
|
+
"contains critical detection: should be in custom critical instead"
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
const cleanedDice2 = diceTypeRandomParse(
|
|
419
|
+
statistiqueTemplate.diceType,
|
|
420
|
+
statistiqueTemplate,
|
|
421
|
+
engine
|
|
422
|
+
);
|
|
423
|
+
const rolled = roll(cleanedDice2, engine);
|
|
424
|
+
if (!rolled) throw new DiceTypeError(cleanedDice2, "no_roll_result", "no roll result");
|
|
393
425
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const [,
|
|
400
|
-
|
|
426
|
+
if (statistiqueTemplate.customCritical) {
|
|
427
|
+
if (!statistiqueTemplate.diceType) {
|
|
428
|
+
throw new DiceTypeError("no_dice_type", "no_dice_type", "no dice type");
|
|
429
|
+
}
|
|
430
|
+
const customCritical = statistiqueTemplate.customCritical;
|
|
431
|
+
for (const [, custom] of Object.entries(customCritical)) {
|
|
432
|
+
const cleanedDice2 = createCriticalCustom(
|
|
433
|
+
statistiqueTemplate.diceType,
|
|
434
|
+
custom,
|
|
435
|
+
statistiqueTemplate,
|
|
436
|
+
engine
|
|
437
|
+
);
|
|
438
|
+
const rolled = roll(cleanedDice2, engine);
|
|
439
|
+
if (!rolled)
|
|
440
|
+
throw new DiceTypeError(cleanedDice2, "verifyTemplateValue", "no roll result");
|
|
441
|
+
}
|
|
401
442
|
}
|
|
402
|
-
|
|
443
|
+
testDiceRegistered(statistiqueTemplate, engine);
|
|
444
|
+
testStatCombinaison(statistiqueTemplate, engine);
|
|
445
|
+
return statistiqueTemplate;
|
|
403
446
|
}
|
|
404
|
-
function
|
|
405
|
-
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
447
|
+
function testDiceRegistered(template, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
448
|
+
if (!template.damage) return;
|
|
449
|
+
if (Object.keys(template.damage).length === 0) throw new EmptyObjectError();
|
|
450
|
+
if (Object.keys(template.damage).length > 25) throw new TooManyDice();
|
|
451
|
+
for (const [name, dice] of Object.entries(template.damage)) {
|
|
452
|
+
if (!dice) continue;
|
|
453
|
+
const diceReplaced = replaceExpByRandom(dice);
|
|
454
|
+
const randomDiceParsed = diceRandomParse(diceReplaced, template, engine);
|
|
455
|
+
try {
|
|
456
|
+
const rolled = roll(randomDiceParsed, engine);
|
|
457
|
+
if (!rolled) throw new DiceTypeError(name, "no_roll_result", dice);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
throw new DiceTypeError(name, "testDiceRegistered", error);
|
|
411
460
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
result += outsideText.slice(lastIndex);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function testStatCombinaison(template, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
464
|
+
if (!template.statistics) return;
|
|
465
|
+
const onlycombinaisonStats = Object.fromEntries(
|
|
466
|
+
Object.entries(template.statistics).filter(
|
|
467
|
+
([_, value]) => value.combinaison !== void 0
|
|
468
|
+
)
|
|
469
|
+
);
|
|
470
|
+
const allOtherStats = Object.fromEntries(
|
|
471
|
+
Object.entries(template.statistics).filter(([_, value]) => !value.combinaison)
|
|
472
|
+
);
|
|
473
|
+
if (Object.keys(onlycombinaisonStats).length === 0) return;
|
|
474
|
+
const allStats = Object.keys(template.statistics).filter(
|
|
475
|
+
(stat) => !template.statistics[stat].combinaison
|
|
476
|
+
);
|
|
477
|
+
if (allStats.length === 0) throw new NoStatisticsError();
|
|
478
|
+
const error = [];
|
|
479
|
+
for (const [stat, value] of Object.entries(onlycombinaisonStats)) {
|
|
480
|
+
let formula = value.combinaison;
|
|
481
|
+
for (const [other, data] of Object.entries(allOtherStats)) {
|
|
482
|
+
const { max, min } = data;
|
|
483
|
+
const total = template.total || 100;
|
|
484
|
+
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
485
|
+
const regex = new RegExp(other, "gi");
|
|
486
|
+
formula = formula.replace(regex, randomStatValue.toString());
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
(0, import_mathjs.evaluate)(formula);
|
|
490
|
+
} catch (e) {
|
|
491
|
+
error.push(stat);
|
|
444
492
|
}
|
|
445
|
-
dice = result;
|
|
446
493
|
}
|
|
447
|
-
if (
|
|
448
|
-
return
|
|
494
|
+
if (error.length > 0) throw new FormulaError(error.join(", "), "testStatCombinaison");
|
|
495
|
+
return;
|
|
449
496
|
}
|
|
450
|
-
function
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
if (
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
const result = (0, import_mathjs.evaluate)(formulae);
|
|
459
|
-
modifiedDice = modifiedDice.replace(match.groups.formula, result.toString());
|
|
460
|
-
} catch (error) {
|
|
461
|
-
throw new FormulaError(match.groups.formula, "replaceFormulasInDice", error);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
497
|
+
function generateRandomStat(total = 100, max, min, engine = import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto) {
|
|
498
|
+
let randomStatValue = total + 1;
|
|
499
|
+
const random = new import_random_js.Random(engine || import_rpg_dice_roller2.NumberGenerator.engines.nodeCrypto);
|
|
500
|
+
while (randomStatValue >= total || randomStatValue === 0) {
|
|
501
|
+
if (max && min) randomStatValue = randomInt(min, max, engine, random);
|
|
502
|
+
else if (max) randomStatValue = randomInt(1, max, engine, random);
|
|
503
|
+
else if (min) randomStatValue = randomInt(min, total, engine, random);
|
|
504
|
+
else randomStatValue = randomInt(1, total, engine, random);
|
|
464
505
|
}
|
|
465
|
-
return
|
|
506
|
+
return randomStatValue;
|
|
466
507
|
}
|
|
467
|
-
|
|
468
|
-
|
|
508
|
+
|
|
509
|
+
// src/utils.ts
|
|
510
|
+
function escapeRegex(string) {
|
|
511
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
512
|
+
}
|
|
513
|
+
function standardizeDice(dice) {
|
|
514
|
+
return dice.replace(
|
|
515
|
+
/(\[[^\]]+])|([^[]+)/g,
|
|
516
|
+
(_match, insideBrackets, outsideText) => insideBrackets ? insideBrackets : outsideText.standardize().replaceAll("df", "dF")
|
|
517
|
+
);
|
|
469
518
|
}
|
|
470
519
|
function isNumber(value) {
|
|
471
520
|
return value !== void 0 && (typeof value === "number" || !Number.isNaN(Number(value)) && typeof value === "string" && value.trim().length > 0);
|
|
472
521
|
}
|
|
473
|
-
function replaceExpByRandom(dice, engine =
|
|
522
|
+
function replaceExpByRandom(dice, engine = import_rpg_dice_roller3.NumberGenerator.engines.nodeCrypto) {
|
|
474
523
|
const diceRegex = /\{exp( ?\|\| ?(?<default>\d+))?}/gi;
|
|
475
524
|
return dice.replace(diceRegex, (_match, _p1, _p2, _offset, _string, groups) => {
|
|
476
525
|
const defaultValue = groups?.default;
|
|
477
526
|
return defaultValue ?? randomInt(1, 999, engine).toString();
|
|
478
527
|
});
|
|
479
528
|
}
|
|
480
|
-
function randomInt(min, max, engine =
|
|
481
|
-
if (!rng) rng = new
|
|
529
|
+
function randomInt(min, max, engine = import_rpg_dice_roller3.NumberGenerator.engines.nodeCrypto, rng) {
|
|
530
|
+
if (!rng) rng = new import_random_js2.Random(engine || void 0);
|
|
482
531
|
return rng.integer(min, max);
|
|
483
532
|
}
|
|
484
|
-
function createCriticalCustom(dice, customCritical, template, engine =
|
|
533
|
+
function createCriticalCustom(dice, customCritical, template, engine = import_rpg_dice_roller3.NumberGenerator.engines.nodeCrypto) {
|
|
485
534
|
const compareRegex = dice.match(SIGN_REGEX_SPACE);
|
|
486
535
|
let customDice = dice;
|
|
487
536
|
const compareValue = diceTypeRandomParse(customCritical.value, template, engine);
|
|
@@ -524,7 +573,7 @@ function canComparisonFail(maxRollValue, compare, minRollValue = 1) {
|
|
|
524
573
|
return true;
|
|
525
574
|
}
|
|
526
575
|
}
|
|
527
|
-
function rollCompare(value, engine =
|
|
576
|
+
function rollCompare(value, engine = import_rpg_dice_roller4.NumberGenerator.engines.nodeCrypto, pity) {
|
|
528
577
|
if (isNumber(value)) return { value: Number.parseInt(value, 10) };
|
|
529
578
|
if (!value || typeof value === "string" && value.trim() === "") {
|
|
530
579
|
return { value: 0, diceResult: value };
|
|
@@ -543,7 +592,7 @@ function rollCompare(value, engine = import_rpg_dice_roller3.NumberGenerator.eng
|
|
|
543
592
|
diceResult: rollComp?.result
|
|
544
593
|
};
|
|
545
594
|
}
|
|
546
|
-
function getCompare(dice, compareRegex, engine =
|
|
595
|
+
function getCompare(dice, compareRegex, engine = import_rpg_dice_roller4.NumberGenerator.engines.nodeCrypto, pity) {
|
|
547
596
|
if (dice.match(/((\{.*,(.*)+\}|([><=!]+\d+f))([><=]|!=)+\d+\}?)|\{(.*)(([><=]|!=)+).*\}/))
|
|
548
597
|
return { dice, compare: void 0 };
|
|
549
598
|
dice = dice.replace(SIGN_REGEX_SPACE, "");
|
|
@@ -599,7 +648,7 @@ function canComparisonSucceed(maxRollValue, compare, minRollValue) {
|
|
|
599
648
|
var import_mathjs4 = require("mathjs");
|
|
600
649
|
|
|
601
650
|
// src/dice/signs.ts
|
|
602
|
-
var
|
|
651
|
+
var import_rpg_dice_roller5 = require("@dice-roller/rpg-dice-roller");
|
|
603
652
|
var import_mathjs3 = require("mathjs");
|
|
604
653
|
|
|
605
654
|
// src/dice/replace.ts
|
|
@@ -689,7 +738,7 @@ function inverseSign(sign) {
|
|
|
689
738
|
return "==";
|
|
690
739
|
}
|
|
691
740
|
}
|
|
692
|
-
function compareSignFormule(toRoll, compareRegex, element, diceResult, engine =
|
|
741
|
+
function compareSignFormule(toRoll, compareRegex, element, diceResult, engine = import_rpg_dice_roller5.NumberGenerator.engines.nodeCrypto, pity, rollBounds) {
|
|
693
742
|
let results = "";
|
|
694
743
|
let trivial = false;
|
|
695
744
|
const compareResult = getCompare(toRoll, compareRegex, engine);
|
|
@@ -750,43 +799,278 @@ function normalizeExplodingSuccess(dice) {
|
|
|
750
799
|
parsedValue = 0;
|
|
751
800
|
}
|
|
752
801
|
}
|
|
753
|
-
const normalizedSegment = "!";
|
|
754
|
-
const replacedDice = dice.replace(match[0], normalizedSegment);
|
|
755
|
-
return {
|
|
756
|
-
dice: replacedDice,
|
|
757
|
-
originalDice: dice,
|
|
758
|
-
sign: normalizedSign,
|
|
759
|
-
value: parsedValue,
|
|
760
|
-
normalizedSegment,
|
|
761
|
-
originalSegment: match[0]
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
function countExplodingSuccesses(diceRoll, sign, value) {
|
|
765
|
-
const rollsArray = Array.isArray(diceRoll) ? diceRoll : [diceRoll];
|
|
766
|
-
const flatValues = [];
|
|
767
|
-
for (const dr of rollsArray) {
|
|
768
|
-
const groups = dr.rolls ?? [];
|
|
769
|
-
for (const group of groups) {
|
|
770
|
-
const innerRolls = group.rolls ?? [];
|
|
771
|
-
for (const roll2 of innerRolls) {
|
|
772
|
-
if (typeof roll2.value === "number") flatValues.push(roll2.value);
|
|
802
|
+
const normalizedSegment = "!";
|
|
803
|
+
const replacedDice = dice.replace(match[0], normalizedSegment);
|
|
804
|
+
return {
|
|
805
|
+
dice: replacedDice,
|
|
806
|
+
originalDice: dice,
|
|
807
|
+
sign: normalizedSign,
|
|
808
|
+
value: parsedValue,
|
|
809
|
+
normalizedSegment,
|
|
810
|
+
originalSegment: match[0]
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function countExplodingSuccesses(diceRoll, sign, value) {
|
|
814
|
+
const rollsArray = Array.isArray(diceRoll) ? diceRoll : [diceRoll];
|
|
815
|
+
const flatValues = [];
|
|
816
|
+
for (const dr of rollsArray) {
|
|
817
|
+
const groups = dr.rolls ?? [];
|
|
818
|
+
for (const group of groups) {
|
|
819
|
+
const innerRolls = group.rolls ?? [];
|
|
820
|
+
for (const roll2 of innerRolls) {
|
|
821
|
+
if (typeof roll2.value === "number") flatValues.push(roll2.value);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return flatValues.reduce(
|
|
826
|
+
(acc, current) => acc + (matchComparison(sign, current, value) ? 1 : 0),
|
|
827
|
+
0
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// src/dice/extract.ts
|
|
832
|
+
var import_rpg_dice_roller6 = require("@dice-roller/rpg-dice-roller");
|
|
833
|
+
|
|
834
|
+
// src/similarities/generateStatsDice.ts
|
|
835
|
+
var import_mathjs5 = require("mathjs");
|
|
836
|
+
|
|
837
|
+
// src/similarities/similarity.ts
|
|
838
|
+
function calculateSimilarity(str1, str2) {
|
|
839
|
+
const longer = str1.length > str2.length ? str1 : str2;
|
|
840
|
+
const shorter = str1.length > str2.length ? str2 : str1;
|
|
841
|
+
if (longer.length === 0) return 1;
|
|
842
|
+
const distance = levenshteinDistance(longer, shorter);
|
|
843
|
+
return (longer.length - distance) / longer.length;
|
|
844
|
+
}
|
|
845
|
+
function levenshteinDistance(str1, str2) {
|
|
846
|
+
const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
|
|
847
|
+
for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;
|
|
848
|
+
for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;
|
|
849
|
+
for (let j = 1; j <= str2.length; j++) {
|
|
850
|
+
for (let i = 1; i <= str1.length; i++) {
|
|
851
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
852
|
+
matrix[j][i] = Math.min(
|
|
853
|
+
matrix[j][i - 1] + 1,
|
|
854
|
+
// insertion
|
|
855
|
+
matrix[j - 1][i] + 1,
|
|
856
|
+
// deletion
|
|
857
|
+
matrix[j - 1][i - 1] + cost
|
|
858
|
+
// substitution
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return matrix[str2.length][str1.length];
|
|
863
|
+
}
|
|
864
|
+
function findBestStatMatch(searchTerm, normalizedStats, similarityThreshold = MIN_THRESHOLD_MATCH) {
|
|
865
|
+
const exact = normalizedStats.get(searchTerm);
|
|
866
|
+
if (exact) return exact;
|
|
867
|
+
const candidates = [];
|
|
868
|
+
for (const [normalizedKey, original] of normalizedStats) {
|
|
869
|
+
if (normalizedKey.startsWith(searchTerm))
|
|
870
|
+
candidates.push([original, calculateSimilarity(searchTerm, normalizedKey)]);
|
|
871
|
+
}
|
|
872
|
+
if (candidates.length === 1) return candidates[0][0];
|
|
873
|
+
if (candidates.length > 0) {
|
|
874
|
+
candidates.sort((a, b) => b[1] - a[1]);
|
|
875
|
+
if (candidates[0][1] >= similarityThreshold) return candidates[0][0];
|
|
876
|
+
}
|
|
877
|
+
let bestMatch;
|
|
878
|
+
let bestSimilarity = 0;
|
|
879
|
+
for (const [normalizedKey, original] of normalizedStats) {
|
|
880
|
+
const similarity = calculateSimilarity(searchTerm, normalizedKey);
|
|
881
|
+
if (similarity === 1) return original;
|
|
882
|
+
if (similarity > bestSimilarity && similarity >= similarityThreshold) {
|
|
883
|
+
bestSimilarity = similarity;
|
|
884
|
+
bestMatch = original;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return bestMatch;
|
|
888
|
+
}
|
|
889
|
+
function findBestRecord(record, searchTerm, similarityThreshold = MIN_THRESHOLD_MATCH) {
|
|
890
|
+
const normalizeRecord = /* @__PURE__ */ new Map();
|
|
891
|
+
for (const key of Object.keys(record)) {
|
|
892
|
+
normalizeRecord.set(key.standardize(), key);
|
|
893
|
+
}
|
|
894
|
+
return findBestStatMatch(
|
|
895
|
+
searchTerm.standardize(),
|
|
896
|
+
normalizeRecord,
|
|
897
|
+
similarityThreshold
|
|
898
|
+
) || null;
|
|
899
|
+
}
|
|
900
|
+
function replaceUnknown(dice, replacer) {
|
|
901
|
+
return dice.replaceAll(REMOVER_PATTERN.STAT_MATCHER, replacer).replaceAll("+0", "").replaceAll("-0", "");
|
|
902
|
+
}
|
|
903
|
+
function verifyStatMatcherPattern(dice, replaceUnknow) {
|
|
904
|
+
if (REMOVER_PATTERN.STAT_MATCHER.test(dice)) {
|
|
905
|
+
if (replaceUnknow)
|
|
906
|
+
return replaceUnknown(dice, replaceUnknow);
|
|
907
|
+
const matched = dice.matchAll(new RegExp(REMOVER_PATTERN.STAT_MATCHER));
|
|
908
|
+
const stats = matched ? Array.from(matched, (m) => m?.[0]).map((s) => `\`${s}\``).join(", ") : "unknown";
|
|
909
|
+
throw new DiceTypeError(stats, "unknown_stats");
|
|
910
|
+
}
|
|
911
|
+
return dice.replaceAll("+0", "").replaceAll("-0", "");
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// src/similarities/generateStatsDice.ts
|
|
915
|
+
function handleDiceAfterD(tokenStd, normalizedStats) {
|
|
916
|
+
const diceMatch = /^(\d*)d(.+)$/i.exec(tokenStd);
|
|
917
|
+
if (!diceMatch) return null;
|
|
918
|
+
const diceCount = diceMatch[1] || "";
|
|
919
|
+
const afterD = diceMatch[2];
|
|
920
|
+
const bestMatch = findBestStatMatch(afterD, normalizedStats, 1);
|
|
921
|
+
if (bestMatch) {
|
|
922
|
+
const [, value] = bestMatch;
|
|
923
|
+
return `${diceCount}d${value.toString()}`;
|
|
924
|
+
}
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
function handleSimpleToken(tokenStd, token, normalizedStats, minThreshold) {
|
|
928
|
+
const bestMatch = findBestStatMatch(tokenStd, normalizedStats, minThreshold);
|
|
929
|
+
if (bestMatch) {
|
|
930
|
+
const [, value] = bestMatch;
|
|
931
|
+
return value.toString();
|
|
932
|
+
}
|
|
933
|
+
return token;
|
|
934
|
+
}
|
|
935
|
+
function generateStatsDice(originalDice, stats, minThreshold = 0.6, dollarValue) {
|
|
936
|
+
let dice = originalDice.standardize();
|
|
937
|
+
if (stats && Object.keys(stats).length > 0) {
|
|
938
|
+
const normalizedStats = /* @__PURE__ */ new Map();
|
|
939
|
+
for (const [key, value] of Object.entries(stats)) {
|
|
940
|
+
const normalized = key.standardize();
|
|
941
|
+
normalizedStats.set(normalized, [key, value]);
|
|
942
|
+
}
|
|
943
|
+
const partsRegex = /(\[[^\]]+])|([^[]+)/g;
|
|
944
|
+
let result = "";
|
|
945
|
+
let match;
|
|
946
|
+
while ((match = partsRegex.exec(dice)) !== null) {
|
|
947
|
+
const insideBrackets = match[1];
|
|
948
|
+
const outsideText = match[2];
|
|
949
|
+
if (insideBrackets) {
|
|
950
|
+
result += insideBrackets;
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
if (!outsideText) {
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
const tokenRegex = /(\$?[\p{L}\p{N}_.]+)/gu;
|
|
957
|
+
let lastIndex = 0;
|
|
958
|
+
let tokenMatch;
|
|
959
|
+
while ((tokenMatch = tokenRegex.exec(outsideText)) !== null) {
|
|
960
|
+
result += outsideText.slice(lastIndex, tokenMatch.index);
|
|
961
|
+
const token = tokenMatch[0];
|
|
962
|
+
const tokenHasDollar = token.startsWith("$");
|
|
963
|
+
const tokenForCompare = tokenHasDollar ? token.slice(1) : token;
|
|
964
|
+
const tokenStd = tokenForCompare.standardize();
|
|
965
|
+
const diceReplacement = handleDiceAfterD(tokenStd, normalizedStats);
|
|
966
|
+
if (diceReplacement) {
|
|
967
|
+
result += diceReplacement;
|
|
968
|
+
lastIndex = tokenRegex.lastIndex;
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
result += handleSimpleToken(tokenStd, token, normalizedStats, minThreshold);
|
|
972
|
+
lastIndex = tokenRegex.lastIndex;
|
|
973
|
+
}
|
|
974
|
+
result += outsideText.slice(lastIndex);
|
|
975
|
+
}
|
|
976
|
+
dice = result;
|
|
977
|
+
}
|
|
978
|
+
if (dollarValue) dice = dice.replaceAll("$", dollarValue);
|
|
979
|
+
return replaceFormulaInDice(dice);
|
|
980
|
+
}
|
|
981
|
+
function replaceFormulaInDice(dice) {
|
|
982
|
+
const formula = /(?<formula>\{{2}(.+?)}{2})/gim;
|
|
983
|
+
let match;
|
|
984
|
+
let modifiedDice = dice;
|
|
985
|
+
while ((match = formula.exec(dice)) !== null) {
|
|
986
|
+
if (match.groups?.formula) {
|
|
987
|
+
const formulae = match.groups.formula.replaceAll("{{", "").replaceAll("}}", "");
|
|
988
|
+
try {
|
|
989
|
+
const result = (0, import_mathjs5.evaluate)(formulae);
|
|
990
|
+
modifiedDice = modifiedDice.replace(match.groups.formula, result.toString());
|
|
991
|
+
} catch (error) {
|
|
992
|
+
throw new FormulaError(match.groups.formula, "replaceFormulasInDice", error);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return cleanedDice(modifiedDice);
|
|
997
|
+
}
|
|
998
|
+
function cleanedDice(dice) {
|
|
999
|
+
return dice.replaceAll("+-", "-").replaceAll("--", "+").replaceAll("++", "+").replaceAll("=>", ">=").replaceAll("=<", "<=").trimEnd();
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/similarities/resolveFormula.ts
|
|
1003
|
+
var import_mathjs6 = require("mathjs");
|
|
1004
|
+
function toFiniteNumber(value) {
|
|
1005
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1006
|
+
return void 0;
|
|
1007
|
+
}
|
|
1008
|
+
function substituteFormulaTokens(expr, resolvedStats, similarityThreshold = MIN_THRESHOLD_MATCH) {
|
|
1009
|
+
return expr.replace(/([\p{L}\p{M}._-]+)/gu, (token) => {
|
|
1010
|
+
const match = findBestStatMatch(token, resolvedStats, similarityThreshold);
|
|
1011
|
+
return match !== void 0 ? match.toString() : token;
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
function resolveFormulaHint(formula, allAttributes, similarityThreshold = MIN_THRESHOLD_MATCH) {
|
|
1015
|
+
const trimmed = formula.trim();
|
|
1016
|
+
if (!trimmed) return { kind: "not-formula" };
|
|
1017
|
+
if (isNumber(trimmed)) return { kind: "not-formula" };
|
|
1018
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1019
|
+
const pending = /* @__PURE__ */ new Map();
|
|
1020
|
+
for (const [name, val] of Object.entries(allAttributes)) {
|
|
1021
|
+
const norm = name.standardize();
|
|
1022
|
+
if (typeof val === "number") {
|
|
1023
|
+
if (Number.isFinite(val)) resolved.set(norm, val);
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
const t = val.trim();
|
|
1027
|
+
if (!t) continue;
|
|
1028
|
+
if (isNumber(t)) {
|
|
1029
|
+
const numeric = Number(t);
|
|
1030
|
+
if (Number.isFinite(numeric)) resolved.set(norm, numeric);
|
|
1031
|
+
} else {
|
|
1032
|
+
pending.set(norm, t.standardize());
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
for (const [normName, expr2] of pending) {
|
|
1036
|
+
pending.set(normName, substituteFormulaTokens(expr2, resolved, similarityThreshold));
|
|
1037
|
+
}
|
|
1038
|
+
let progress = true;
|
|
1039
|
+
while (pending.size > 0 && progress) {
|
|
1040
|
+
progress = false;
|
|
1041
|
+
for (const [normName, expr2] of pending) {
|
|
1042
|
+
try {
|
|
1043
|
+
const result = toFiniteNumber((0, import_mathjs6.evaluate)(expr2));
|
|
1044
|
+
if (result === void 0) continue;
|
|
1045
|
+
resolved.set(normName, result);
|
|
1046
|
+
pending.delete(normName);
|
|
1047
|
+
progress = true;
|
|
1048
|
+
for (const [otherNorm, otherExpr] of pending) {
|
|
1049
|
+
pending.set(
|
|
1050
|
+
otherNorm,
|
|
1051
|
+
substituteFormulaTokens(otherExpr, resolved, similarityThreshold)
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
} catch {
|
|
773
1055
|
}
|
|
774
1056
|
}
|
|
775
1057
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1058
|
+
const normFormula = trimmed.standardize();
|
|
1059
|
+
const expr = substituteFormulaTokens(normFormula, resolved, similarityThreshold);
|
|
1060
|
+
try {
|
|
1061
|
+
const result = toFiniteNumber((0, import_mathjs6.evaluate)(expr));
|
|
1062
|
+
if (result !== void 0) return { kind: "resolved", value: result };
|
|
1063
|
+
return { kind: "error" };
|
|
1064
|
+
} catch {
|
|
1065
|
+
return { kind: "error" };
|
|
1066
|
+
}
|
|
780
1067
|
}
|
|
781
1068
|
|
|
782
|
-
// src/dice/extract.ts
|
|
783
|
-
var import_rpg_dice_roller5 = require("@dice-roller/rpg-dice-roller");
|
|
784
|
-
|
|
785
1069
|
// src/dice/calculator.ts
|
|
786
|
-
var
|
|
1070
|
+
var import_mathjs7 = require("mathjs");
|
|
787
1071
|
function calculator(sign, value, total) {
|
|
788
1072
|
if (sign === "^") sign = "**";
|
|
789
|
-
return (0,
|
|
1073
|
+
return (0, import_mathjs7.evaluate)(`${total} ${sign} ${value}`);
|
|
790
1074
|
}
|
|
791
1075
|
|
|
792
1076
|
// src/dice/extract.ts
|
|
@@ -821,10 +1105,10 @@ function extractValuesFromOutput(output) {
|
|
|
821
1105
|
}
|
|
822
1106
|
return values;
|
|
823
1107
|
}
|
|
824
|
-
function getRollBounds(dice, engine =
|
|
1108
|
+
function getRollBounds(dice, engine = import_rpg_dice_roller6.NumberGenerator.engines.nodeCrypto) {
|
|
825
1109
|
try {
|
|
826
|
-
const roller = new
|
|
827
|
-
|
|
1110
|
+
const roller = new import_rpg_dice_roller6.DiceRoller();
|
|
1111
|
+
import_rpg_dice_roller6.NumberGenerator.generator.engine = engine;
|
|
828
1112
|
const rollResult = roller.roll(dice);
|
|
829
1113
|
const instance = Array.isArray(rollResult) ? rollResult[0] : rollResult;
|
|
830
1114
|
const { minTotal, maxTotal } = instance;
|
|
@@ -937,8 +1221,8 @@ function handleBulkRolls(dice, isCurlyBulk, bulkContent, compare, explodingSucce
|
|
|
937
1221
|
sort
|
|
938
1222
|
);
|
|
939
1223
|
}
|
|
940
|
-
const roller = new
|
|
941
|
-
|
|
1224
|
+
const roller = new import_rpg_dice_roller7.DiceRoller();
|
|
1225
|
+
import_rpg_dice_roller7.NumberGenerator.generator.engine = engine;
|
|
942
1226
|
for (let i = 0; i < numberOfDice; i++) {
|
|
943
1227
|
try {
|
|
944
1228
|
roller.roll(diceToRoll);
|
|
@@ -960,8 +1244,8 @@ function handleBulkRolls(dice, isCurlyBulk, bulkContent, compare, explodingSucce
|
|
|
960
1244
|
function handleBulkRollsWithComparison(numberOfDice, diceToRoll, comments, activeCompare, explodingSuccess, diceDisplay, isCurlyBulk, curlyCompare, compare, engine, sort) {
|
|
961
1245
|
const results = [];
|
|
962
1246
|
let successCount = 0;
|
|
963
|
-
const roller = new
|
|
964
|
-
|
|
1247
|
+
const roller = new import_rpg_dice_roller7.DiceRoller();
|
|
1248
|
+
import_rpg_dice_roller7.NumberGenerator.generator.engine = engine;
|
|
965
1249
|
let trivialComparisonDetected = false;
|
|
966
1250
|
const formatOutput = (output, addStar) => {
|
|
967
1251
|
const formatted = addStar && isCurlyBulk ? output.replace(
|
|
@@ -995,7 +1279,7 @@ function handleBulkRollsWithComparison(numberOfDice, diceToRoll, comments, activ
|
|
|
995
1279
|
results.push(formattedRollOutput);
|
|
996
1280
|
} else {
|
|
997
1281
|
const rollTotal = rollInstance.total;
|
|
998
|
-
const isSuccess = (0,
|
|
1282
|
+
const isSuccess = (0, import_mathjs8.evaluate)(
|
|
999
1283
|
`${rollTotal}${activeCompare.sign}${activeCompare.value}`
|
|
1000
1284
|
);
|
|
1001
1285
|
if (isSuccess) successCount++;
|
|
@@ -1058,7 +1342,7 @@ function handleBulkRollsWithComparison(numberOfDice, diceToRoll, comments, activ
|
|
|
1058
1342
|
}
|
|
1059
1343
|
|
|
1060
1344
|
// src/dice/pity.ts
|
|
1061
|
-
var
|
|
1345
|
+
var import_mathjs9 = require("mathjs");
|
|
1062
1346
|
function handlePitySystem(dice, compare, diceRoll, roller, engine) {
|
|
1063
1347
|
const currentRoll = Array.isArray(diceRoll) ? diceRoll[0] : diceRoll;
|
|
1064
1348
|
const maxPossible = currentRoll ? currentRoll.maxTotal : null;
|
|
@@ -1066,7 +1350,7 @@ function handlePitySystem(dice, compare, diceRoll, roller, engine) {
|
|
|
1066
1350
|
if (!isComparisonPossible) {
|
|
1067
1351
|
return { rerollCount: 0 };
|
|
1068
1352
|
}
|
|
1069
|
-
let isFail = (0,
|
|
1353
|
+
let isFail = (0, import_mathjs9.evaluate)(`${roller.total}${compare.sign}${compare.value}`);
|
|
1070
1354
|
if (isFail) {
|
|
1071
1355
|
return { rerollCount: 0 };
|
|
1072
1356
|
}
|
|
@@ -1081,14 +1365,14 @@ function handlePitySystem(dice, compare, diceRoll, roller, engine) {
|
|
|
1081
1365
|
}
|
|
1082
1366
|
rerollCount++;
|
|
1083
1367
|
if (res && res.total !== void 0) {
|
|
1084
|
-
isFail = (0,
|
|
1368
|
+
isFail = (0, import_mathjs9.evaluate)(`${res.total}${compare.sign}${compare.value}`);
|
|
1085
1369
|
}
|
|
1086
1370
|
}
|
|
1087
1371
|
return { rerollCount, result: res };
|
|
1088
1372
|
}
|
|
1089
1373
|
|
|
1090
1374
|
// src/roll.ts
|
|
1091
|
-
function roll(dice, engine =
|
|
1375
|
+
function roll(dice, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto, pity, sort) {
|
|
1092
1376
|
if (sort === "none" /* None */) sort = void 0;
|
|
1093
1377
|
const prepared = prepareDice(dice);
|
|
1094
1378
|
if (!prepared.dice.includes("d")) return void 0;
|
|
@@ -1129,8 +1413,8 @@ function roll(dice, engine = import_rpg_dice_roller7.NumberGenerator.engines.nod
|
|
|
1129
1413
|
sort
|
|
1130
1414
|
);
|
|
1131
1415
|
}
|
|
1132
|
-
const roller = new
|
|
1133
|
-
|
|
1416
|
+
const roller = new import_rpg_dice_roller8.DiceRoller();
|
|
1417
|
+
import_rpg_dice_roller8.NumberGenerator.generator.engine = engine;
|
|
1134
1418
|
let diceWithoutComment = processedDice.replace(COMMENT_REGEX, "").trimEnd();
|
|
1135
1419
|
diceWithoutComment = setSortOrder(diceWithoutComment, sort);
|
|
1136
1420
|
let diceRoll;
|
|
@@ -1207,7 +1491,7 @@ function roll(dice, engine = import_rpg_dice_roller7.NumberGenerator.engines.nod
|
|
|
1207
1491
|
trivial: compare?.trivial ? true : void 0
|
|
1208
1492
|
};
|
|
1209
1493
|
}
|
|
1210
|
-
function sharedRolls(dice, engine =
|
|
1494
|
+
function sharedRolls(dice, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto, pity, explodingSuccessMain, diceDisplay, isSharedCurly, sort) {
|
|
1211
1495
|
if (!explodingSuccessMain)
|
|
1212
1496
|
explodingSuccessMain = normalizeExplodingSuccess(dice.split(";")[0] ?? dice);
|
|
1213
1497
|
if (explodingSuccessMain) {
|
|
@@ -1242,13 +1526,13 @@ function sharedRolls(dice, engine = import_rpg_dice_roller7.NumberGenerator.engi
|
|
|
1242
1526
|
const sortFromMain = getSortOrder(diceMain);
|
|
1243
1527
|
const rollBounds = getRollBounds(diceMain, engine);
|
|
1244
1528
|
let diceResult = roll(diceMain, engine, pity, sort);
|
|
1245
|
-
if (!diceResult
|
|
1529
|
+
if (!diceResult?.total) {
|
|
1246
1530
|
if (hidden) {
|
|
1247
1531
|
diceResult = roll(fixParenthesis(split[0]), engine, pity, sort);
|
|
1248
1532
|
hidden = false;
|
|
1249
1533
|
} else return void 0;
|
|
1250
1534
|
}
|
|
1251
|
-
if (!diceResult
|
|
1535
|
+
if (!diceResult?.total) return void 0;
|
|
1252
1536
|
if (explodingSuccessMain && diceResult.result) {
|
|
1253
1537
|
const values = extractValuesFromOutput(diceResult.result);
|
|
1254
1538
|
diceResult.total = values.filter(
|
|
@@ -1290,7 +1574,7 @@ function sharedRolls(dice, engine = import_rpg_dice_roller7.NumberGenerator.engi
|
|
|
1290
1574
|
const { diceAll } = replaceText(element, diceResult.total, diceResult.dice);
|
|
1291
1575
|
let successCount = 0;
|
|
1292
1576
|
try {
|
|
1293
|
-
const evaluated = (0,
|
|
1577
|
+
const evaluated = (0, import_mathjs10.evaluate)(toRoll);
|
|
1294
1578
|
successCount = evaluated ? 1 : 0;
|
|
1295
1579
|
} catch (error) {
|
|
1296
1580
|
const evaluated = roll(toRoll, engine, pity);
|
|
@@ -1324,7 +1608,7 @@ function sharedRolls(dice, engine = import_rpg_dice_roller7.NumberGenerator.engi
|
|
|
1324
1608
|
diceResult.dice
|
|
1325
1609
|
);
|
|
1326
1610
|
try {
|
|
1327
|
-
const evaluated = (0,
|
|
1611
|
+
const evaluated = (0, import_mathjs10.evaluate)(toRoll);
|
|
1328
1612
|
results.push(`\u25C8 ${comment}${diceAll}: ${formule} = ${evaluated}`);
|
|
1329
1613
|
total += Number.parseInt(evaluated, 10);
|
|
1330
1614
|
} catch (error) {
|
|
@@ -1353,7 +1637,7 @@ function sharedRolls(dice, engine = import_rpg_dice_roller7.NumberGenerator.engi
|
|
|
1353
1637
|
trivial: hasTrivialComparison ? true : void 0
|
|
1354
1638
|
};
|
|
1355
1639
|
}
|
|
1356
|
-
function replaceInFormula(element, diceResult, compareResult, res, engine =
|
|
1640
|
+
function replaceInFormula(element, diceResult, compareResult, res, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto, pity) {
|
|
1357
1641
|
const { formule, diceAll } = replaceText(
|
|
1358
1642
|
element,
|
|
1359
1643
|
diceResult.total ?? 0,
|
|
@@ -1363,7 +1647,7 @@ function replaceInFormula(element, diceResult, compareResult, res, engine = impo
|
|
|
1363
1647
|
const invertedSign = res ? compareResult.compare.sign : inverseSign(compareResult.compare.sign);
|
|
1364
1648
|
let evaluateRoll;
|
|
1365
1649
|
try {
|
|
1366
|
-
evaluateRoll = (0,
|
|
1650
|
+
evaluateRoll = (0, import_mathjs10.evaluate)(compareResult.dice);
|
|
1367
1651
|
return `${validSign} ${diceAll}: ${formule} = ${evaluateRoll}${invertedSign}${compareResult.compare?.value}`;
|
|
1368
1652
|
} catch (error) {
|
|
1369
1653
|
const evaluateRoll2 = roll(compareResult.dice, engine, pity);
|
|
@@ -1372,218 +1656,6 @@ function replaceInFormula(element, diceResult, compareResult, res, engine = impo
|
|
|
1372
1656
|
return `${validSign} ${diceAll}: ${formule} = ${evaluateRoll2}${invertedSign}${compareResult.compare?.value}`;
|
|
1373
1657
|
}
|
|
1374
1658
|
}
|
|
1375
|
-
|
|
1376
|
-
// src/verify_template.ts
|
|
1377
|
-
var import_mathjs9 = require("mathjs");
|
|
1378
|
-
var import_random_js2 = require("random-js");
|
|
1379
|
-
var import_uniformize2 = require("uniformize");
|
|
1380
|
-
var import_rpg_dice_roller8 = require("@dice-roller/rpg-dice-roller");
|
|
1381
|
-
function evalStatsDice(testDice, allStats, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto, pity) {
|
|
1382
|
-
let dice = testDice.trimEnd();
|
|
1383
|
-
if (allStats && Object.keys(allStats).length > 0) {
|
|
1384
|
-
const names = Object.keys(allStats);
|
|
1385
|
-
for (const name of names) {
|
|
1386
|
-
const regex = new RegExp(escapeRegex(name.standardize()), "gi");
|
|
1387
|
-
if (dice.standardize().match(regex)) {
|
|
1388
|
-
const statValue = allStats[name];
|
|
1389
|
-
dice = dice.standardize().replace(regex, statValue.toString()).trimEnd();
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
try {
|
|
1394
|
-
if (!roll(replaceFormulaInDice(replaceExpByRandom(dice)), engine, pity))
|
|
1395
|
-
throw new DiceTypeError(dice, "evalStatsDice", "no roll result");
|
|
1396
|
-
return testDice;
|
|
1397
|
-
} catch (error) {
|
|
1398
|
-
throw new DiceTypeError(dice, "evalStatsDice", error);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
function diceRandomParse(value, template, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1402
|
-
if (!template.statistics) return replaceFormulaInDice(value.standardize());
|
|
1403
|
-
value = value.standardize();
|
|
1404
|
-
const statNames = Object.keys(template.statistics);
|
|
1405
|
-
let newDice = value;
|
|
1406
|
-
for (const name of statNames) {
|
|
1407
|
-
const regex = new RegExp(escapeRegex(name.standardize()), "gi");
|
|
1408
|
-
if (value.match(regex)) {
|
|
1409
|
-
let max;
|
|
1410
|
-
let min;
|
|
1411
|
-
const foundStat = template.statistics?.[name];
|
|
1412
|
-
if (foundStat) {
|
|
1413
|
-
max = foundStat.max;
|
|
1414
|
-
min = foundStat.min;
|
|
1415
|
-
}
|
|
1416
|
-
const total = template.total || 100;
|
|
1417
|
-
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
1418
|
-
newDice = value.replace(regex, randomStatValue.toString());
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
return replaceFormulaInDice(newDice);
|
|
1422
|
-
}
|
|
1423
|
-
function diceTypeRandomParse(dice, template, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1424
|
-
dice = replaceExpByRandom(dice);
|
|
1425
|
-
if (!template.statistics) return dice;
|
|
1426
|
-
const firstStatNotcombinaison = Object.keys(template.statistics).find(
|
|
1427
|
-
(stat) => !template.statistics?.[stat].combinaison
|
|
1428
|
-
);
|
|
1429
|
-
if (!firstStatNotcombinaison) return dice;
|
|
1430
|
-
const stats = template.statistics[firstStatNotcombinaison];
|
|
1431
|
-
const { min, max } = stats;
|
|
1432
|
-
const total = template.total || 100;
|
|
1433
|
-
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
1434
|
-
return replaceFormulaInDice(dice.replaceAll("$", randomStatValue.toString()));
|
|
1435
|
-
}
|
|
1436
|
-
function evalCombinaison(combinaison, stats) {
|
|
1437
|
-
const newStats = {};
|
|
1438
|
-
for (const [stat, combin] of Object.entries(combinaison)) {
|
|
1439
|
-
let formula = combin.standardize();
|
|
1440
|
-
for (const [statName, value] of Object.entries(stats)) {
|
|
1441
|
-
const regex = new RegExp(statName.standardize(), "gi");
|
|
1442
|
-
formula = formula.replace(regex, value.toString());
|
|
1443
|
-
}
|
|
1444
|
-
try {
|
|
1445
|
-
newStats[stat] = (0, import_mathjs9.evaluate)(formula);
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
throw new FormulaError(stat, "evalCombinaison", error);
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
return newStats;
|
|
1451
|
-
}
|
|
1452
|
-
function evalOneCombinaison(combinaison, stats) {
|
|
1453
|
-
let formula = combinaison.standardize();
|
|
1454
|
-
for (const [statName, value] of Object.entries(stats)) {
|
|
1455
|
-
const regex = new RegExp(statName.standardize(), "gi");
|
|
1456
|
-
formula = formula.replace(regex, value.toString());
|
|
1457
|
-
}
|
|
1458
|
-
try {
|
|
1459
|
-
return (0, import_mathjs9.evaluate)(formula);
|
|
1460
|
-
} catch (error) {
|
|
1461
|
-
throw new FormulaError(combinaison, "evalOneCombinaison", error);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
function convertNumber(number) {
|
|
1465
|
-
if (number === void 0 || number === null) return void 0;
|
|
1466
|
-
if (number.toString().length === 0 || Number.isNaN(Number.parseInt(number.toString(), 10)))
|
|
1467
|
-
return void 0;
|
|
1468
|
-
if (isNumber(number)) return Number.parseInt(number.toString(), 10);
|
|
1469
|
-
return void 0;
|
|
1470
|
-
}
|
|
1471
|
-
function verifyTemplateValue(template, verify = true, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1472
|
-
const parsedTemplate = templateSchema.parse(template);
|
|
1473
|
-
const { success, failure } = parsedTemplate.critical ?? {};
|
|
1474
|
-
const criticicalVal = {
|
|
1475
|
-
success: convertNumber(success),
|
|
1476
|
-
failure: convertNumber(failure)
|
|
1477
|
-
};
|
|
1478
|
-
const statistiqueTemplate = {
|
|
1479
|
-
diceType: parsedTemplate.diceType,
|
|
1480
|
-
statistics: parsedTemplate.statistics,
|
|
1481
|
-
critical: criticicalVal,
|
|
1482
|
-
total: parsedTemplate.total,
|
|
1483
|
-
charName: parsedTemplate.charName,
|
|
1484
|
-
damage: parsedTemplate.damage,
|
|
1485
|
-
customCritical: parsedTemplate.customCritical,
|
|
1486
|
-
forceDistrib: parsedTemplate.forceDistrib
|
|
1487
|
-
};
|
|
1488
|
-
if (!verify) return statistiqueTemplate;
|
|
1489
|
-
if (statistiqueTemplate.diceType) {
|
|
1490
|
-
if (statistiqueTemplate.diceType.match(DETECT_CRITICAL)) {
|
|
1491
|
-
throw new DiceTypeError(
|
|
1492
|
-
statistiqueTemplate.diceType,
|
|
1493
|
-
"critical_dice_type",
|
|
1494
|
-
"contains critical detection: should be in custom critical instead"
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
const cleanedDice2 = diceTypeRandomParse(
|
|
1498
|
-
statistiqueTemplate.diceType,
|
|
1499
|
-
statistiqueTemplate,
|
|
1500
|
-
engine
|
|
1501
|
-
);
|
|
1502
|
-
const rolled = roll(cleanedDice2, engine);
|
|
1503
|
-
if (!rolled) throw new DiceTypeError(cleanedDice2, "no_roll_result", "no roll result");
|
|
1504
|
-
}
|
|
1505
|
-
if (statistiqueTemplate.customCritical) {
|
|
1506
|
-
if (!statistiqueTemplate.diceType) {
|
|
1507
|
-
throw new DiceTypeError("no_dice_type", "no_dice_type", "no dice type");
|
|
1508
|
-
}
|
|
1509
|
-
const customCritical = statistiqueTemplate.customCritical;
|
|
1510
|
-
for (const [, custom] of Object.entries(customCritical)) {
|
|
1511
|
-
const cleanedDice2 = createCriticalCustom(
|
|
1512
|
-
statistiqueTemplate.diceType,
|
|
1513
|
-
custom,
|
|
1514
|
-
statistiqueTemplate,
|
|
1515
|
-
engine
|
|
1516
|
-
);
|
|
1517
|
-
const rolled = roll(cleanedDice2, engine);
|
|
1518
|
-
if (!rolled)
|
|
1519
|
-
throw new DiceTypeError(cleanedDice2, "verifyTemplateValue", "no roll result");
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
testDiceRegistered(statistiqueTemplate, engine);
|
|
1523
|
-
testStatCombinaison(statistiqueTemplate, engine);
|
|
1524
|
-
return statistiqueTemplate;
|
|
1525
|
-
}
|
|
1526
|
-
function testDiceRegistered(template, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1527
|
-
if (!template.damage) return;
|
|
1528
|
-
if (Object.keys(template.damage).length === 0) throw new EmptyObjectError();
|
|
1529
|
-
if (Object.keys(template.damage).length > 25) throw new TooManyDice();
|
|
1530
|
-
for (const [name, dice] of Object.entries(template.damage)) {
|
|
1531
|
-
if (!dice) continue;
|
|
1532
|
-
const diceReplaced = replaceExpByRandom(dice);
|
|
1533
|
-
const randomDiceParsed = diceRandomParse(diceReplaced, template, engine);
|
|
1534
|
-
try {
|
|
1535
|
-
const rolled = roll(randomDiceParsed, engine);
|
|
1536
|
-
if (!rolled) throw new DiceTypeError(name, "no_roll_result", dice);
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
throw new DiceTypeError(name, "testDiceRegistered", error);
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
function testStatCombinaison(template, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1543
|
-
if (!template.statistics) return;
|
|
1544
|
-
const onlycombinaisonStats = Object.fromEntries(
|
|
1545
|
-
Object.entries(template.statistics).filter(
|
|
1546
|
-
([_, value]) => value.combinaison !== void 0
|
|
1547
|
-
)
|
|
1548
|
-
);
|
|
1549
|
-
const allOtherStats = Object.fromEntries(
|
|
1550
|
-
Object.entries(template.statistics).filter(([_, value]) => !value.combinaison)
|
|
1551
|
-
);
|
|
1552
|
-
if (Object.keys(onlycombinaisonStats).length === 0) return;
|
|
1553
|
-
const allStats = Object.keys(template.statistics).filter(
|
|
1554
|
-
(stat) => !template.statistics[stat].combinaison
|
|
1555
|
-
);
|
|
1556
|
-
if (allStats.length === 0) throw new NoStatisticsError();
|
|
1557
|
-
const error = [];
|
|
1558
|
-
for (const [stat, value] of Object.entries(onlycombinaisonStats)) {
|
|
1559
|
-
let formula = value.combinaison;
|
|
1560
|
-
for (const [other, data] of Object.entries(allOtherStats)) {
|
|
1561
|
-
const { max, min } = data;
|
|
1562
|
-
const total = template.total || 100;
|
|
1563
|
-
const randomStatValue = generateRandomStat(total, max, min, engine);
|
|
1564
|
-
const regex = new RegExp(other, "gi");
|
|
1565
|
-
formula = formula.replace(regex, randomStatValue.toString());
|
|
1566
|
-
}
|
|
1567
|
-
try {
|
|
1568
|
-
(0, import_mathjs9.evaluate)(formula);
|
|
1569
|
-
} catch (e) {
|
|
1570
|
-
error.push(stat);
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
if (error.length > 0) throw new FormulaError(error.join(", "), "testStatCombinaison");
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
|
-
function generateRandomStat(total = 100, max, min, engine = import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto) {
|
|
1577
|
-
let randomStatValue = total + 1;
|
|
1578
|
-
const random = new import_random_js2.Random(engine || import_rpg_dice_roller8.NumberGenerator.engines.nodeCrypto);
|
|
1579
|
-
while (randomStatValue >= total || randomStatValue === 0) {
|
|
1580
|
-
if (max && min) randomStatValue = randomInt(min, max, engine, random);
|
|
1581
|
-
else if (max) randomStatValue = randomInt(1, max, engine, random);
|
|
1582
|
-
else if (min) randomStatValue = randomInt(min, total, engine, random);
|
|
1583
|
-
else randomStatValue = randomInt(1, total, engine, random);
|
|
1584
|
-
}
|
|
1585
|
-
return randomStatValue;
|
|
1586
|
-
}
|
|
1587
1659
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1588
1660
|
0 && (module.exports = {
|
|
1589
1661
|
COMMENT_REGEX,
|
|
@@ -1626,6 +1698,7 @@ function generateRandomStat(total = 100, max, min, engine = import_rpg_dice_roll
|
|
|
1626
1698
|
replaceFormulaInDice,
|
|
1627
1699
|
replaceInFormula,
|
|
1628
1700
|
replaceUnknown,
|
|
1701
|
+
resolveFormulaHint,
|
|
1629
1702
|
roll,
|
|
1630
1703
|
standardizeDice,
|
|
1631
1704
|
templateSchema,
|