@swrpg-online/dice
Version:
A TypeScript library that creates dice rolls using the narrative dice system for the Star Wars Roleplaying Game by Fantasy Flight Games and Edge Studio.
634 lines (633 loc) • 17.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.roll = void 0;
const hints_1 = require("./hints");
const rollDie = (sides) => Math.floor(Math.random() * sides) + 1;
const boostDieResult = (roll) => {
switch (roll) {
case 3:
return {
successes: 1,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 4:
return {
successes: 1,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 5:
return {
successes: 0,
failures: 0,
advantages: 2,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 6:
return {
successes: 0,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const setBackDieResult = (roll) => {
switch (roll) {
case 3:
case 4:
return {
successes: 0,
failures: 1,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 5:
case 6:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 1,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const abilityDieResult = (roll) => {
switch (roll) {
case 2:
case 3:
return {
successes: 1,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 4:
return {
successes: 2,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 5:
case 6:
return {
successes: 0,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 7:
return {
successes: 1,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 8:
return {
successes: 0,
failures: 0,
advantages: 2,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const difficultyDieResult = (roll) => {
switch (roll) {
case 2:
return {
successes: 0,
failures: 1,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 3:
return {
successes: 0,
failures: 2,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 4:
case 5:
case 6:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 1,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 7:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 2,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 8:
return {
successes: 0,
failures: 1,
advantages: 0,
threats: 1,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const proficiencyDieResult = (roll) => {
switch (roll) {
case 2:
case 3:
return {
successes: 1,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 4:
case 5:
return {
successes: 2,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 6:
return {
successes: 0,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 7:
case 8:
case 9:
return {
successes: 1,
failures: 0,
advantages: 1,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 10:
case 11:
return {
successes: 0,
failures: 0,
advantages: 2,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 12:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 1,
despair: 0,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const challengeDieResult = (roll) => {
switch (roll) {
case 2:
case 3:
return {
successes: 0,
failures: 1,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 4:
case 5:
return {
successes: 0,
failures: 2,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 6:
case 7:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 1,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 8:
case 9:
return {
successes: 0,
failures: 1,
advantages: 0,
threats: 1,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 10:
case 11:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 2,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
case 12:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 1,
lightSide: 0,
darkSide: 0,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const forceDieResult = (roll) => {
switch (roll) {
case 1:
case 2:
case 3:
case 4:
case 5:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 1,
darkSide: 0,
};
case 6:
case 7:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 2,
darkSide: 0,
};
case 8:
case 9:
case 10:
case 11:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 1,
};
case 12:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 2,
};
default:
return {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
};
}
};
const sumResults = (results, options) => {
const sums = results.reduce((acc, curr) => ({
successes: acc.successes + curr.successes,
failures: acc.failures + curr.failures,
advantages: acc.advantages + curr.advantages,
threats: acc.threats + curr.threats,
triumphs: acc.triumphs + curr.triumphs,
despair: acc.despair + curr.despair,
lightSide: acc.lightSide + (curr.lightSide || 0),
darkSide: acc.darkSide + (curr.darkSide || 0),
}), {
successes: 0,
failures: 0,
advantages: 0,
threats: 0,
triumphs: 0,
despair: 0,
lightSide: 0,
darkSide: 0,
});
let netSuccesses = 0;
let netFailures = 0;
if (sums.successes === sums.failures) {
netSuccesses = 0;
netFailures = 0;
}
else if (sums.successes > sums.failures) {
netSuccesses = sums.successes - sums.failures;
}
else {
netFailures = sums.failures - sums.successes;
}
const result = {
successes: netSuccesses,
failures: netFailures,
advantages: sums.advantages,
threats: sums.threats,
triumphs: sums.triumphs,
despair: sums.despair,
lightSide: sums.lightSide,
darkSide: sums.darkSide,
};
return result;
};
const roll = (pool, options) => {
var _a, _b, _c, _d, _e, _f, _g;
const boostCount = (_a = pool.boostDice) !== null && _a !== void 0 ? _a : 0;
const abilityCount = (_b = pool.abilityDice) !== null && _b !== void 0 ? _b : 0;
const proficiencyCount = (_c = pool.proficiencyDice) !== null && _c !== void 0 ? _c : 0;
const setBackCount = (_d = pool.setBackDice) !== null && _d !== void 0 ? _d : 0;
const difficultyCount = (_e = pool.difficultyDice) !== null && _e !== void 0 ? _e : 0;
const challengeCount = (_f = pool.challengeDice) !== null && _f !== void 0 ? _f : 0;
const forceCount = (_g = pool.forceDice) !== null && _g !== void 0 ? _g : 0;
// Ensure all dice counts are non-negative
const sanitizedPool = {
boostDice: Math.max(0, boostCount),
abilityDice: Math.max(0, abilityCount),
proficiencyDice: Math.max(0, proficiencyCount),
setBackDice: Math.max(0, setBackCount),
difficultyDice: Math.max(0, difficultyCount),
challengeDice: Math.max(0, challengeCount),
forceDice: Math.max(0, forceCount),
};
const detailedResults = [];
// Roll boost dice
for (let i = 0; i < sanitizedPool.boostDice; i++) {
const roll = rollDie(6);
detailedResults.push({
type: "boost",
roll,
result: boostDieResult(roll),
});
}
// Roll ability dice
for (let i = 0; i < sanitizedPool.abilityDice; i++) {
const roll = rollDie(8);
detailedResults.push({
type: "ability",
roll,
result: abilityDieResult(roll),
});
}
// Roll proficiency dice
for (let i = 0; i < sanitizedPool.proficiencyDice; i++) {
const roll = rollDie(12);
detailedResults.push({
type: "proficiency",
roll,
result: proficiencyDieResult(roll),
});
}
// Roll setback dice
for (let i = 0; i < sanitizedPool.setBackDice; i++) {
const roll = rollDie(6);
detailedResults.push({
type: "setback",
roll,
result: setBackDieResult(roll),
});
}
// Roll difficulty dice
for (let i = 0; i < sanitizedPool.difficultyDice; i++) {
const roll = rollDie(8);
detailedResults.push({
type: "difficulty",
roll,
result: difficultyDieResult(roll),
});
}
// Roll challenge dice
for (let i = 0; i < sanitizedPool.challengeDice; i++) {
const roll = rollDie(12);
detailedResults.push({
type: "challenge",
roll,
result: challengeDieResult(roll),
});
}
// Roll force dice
for (let i = 0; i < sanitizedPool.forceDice; i++) {
const roll = rollDie(12);
detailedResults.push({
type: "force",
roll,
result: forceDieResult(roll),
});
}
const summary = sumResults(detailedResults.map((r) => r.result));
if (options === null || options === void 0 ? void 0 : options.hints) {
const applicableHints = hints_1.hints.filter((hint) => {
const { cost } = hint;
return Object.entries(cost).some(([symbol, required]) => {
const summaryKey = (symbol.toLowerCase() + "s");
const value = summary[summaryKey];
if (typeof value !== "number")
return false;
return required <= value;
});
});
summary.hints = applicableHints.map((hint) => `${(0, hints_1.hintCostDisplayText)(hint)} - ${hint.description}`);
}
return {
results: detailedResults,
summary: summary,
};
};
exports.roll = roll;