import { DS4RollProvider, RollProvider } from "./roll-provider"; export function ds4test(testValue: number, rollOptions: RollOptions = new RollOptions()): RollResult { const finalRollValue = testValue; if (finalRollValue <= 20) { return rollCheckSingleDie(finalRollValue, rollOptions); } else { return rollCheckMultipleDice(finalRollValue, rollOptions); } } export function rollCheckSingleDie( testValue: number, rollOptions: RollOptions, provider: RollProvider = new DS4RollProvider(), ): RollResult { const roll = provider.getNextRoll(); const dice = [roll]; if (roll <= rollOptions.maxCritSucc) { return new RollResult(testValue, RollResultStatus.CRITICAL_SUCCESS, dice); } else if (roll >= rollOptions.minCritFail) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, dice); } else { if (roll <= testValue) { return new RollResult(roll, RollResultStatus.SUCCESS, dice); } else { return new RollResult(0, RollResultStatus.FAILURE, dice); } } } export function rollCheckMultipleDice( testValue: number, rollOptions: RollOptions, provider: RollProvider = new DS4RollProvider(), ): RollResult { const finalCheck = testValue % 20; const numberOfDice = Math.ceil(testValue / 20); const dice = provider.getNextRolls(numberOfDice); const firstResult = dice[0]; if (firstResult >= rollOptions.minCritFail) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, dice); } const partitionCallback = (prev: [Array, Array], cur: number) => { if (cur <= rollOptions.maxCritSucc) { prev[0].push(cur); } else { prev[1].push(cur); } return prev; }; const [critSuccesses, otherRolls] = dice .reduce(partitionCallback, [[], []]) .map((a) => a.sort((r1, r2) => r2 - r1)); const sortedRollResults: Array = critSuccesses.concat(otherRolls); const evaluationResult = sortedRollResults .map((value, index) => { if (index == numberOfDice - 1) { if (value == 1) { return finalCheck; } else { return value <= finalCheck ? value : 0; } } else { if (value <= rollOptions.maxCritSucc) { return 20; } else { return value; } } }) .reduce((a, b) => a + b); return new RollResult(evaluationResult, RollResultStatus.SUCCESS, sortedRollResults); } export class RollOptions { public maxCritSucc = 1; public minCritFail = 20; } export class RollResult { constructor(public value: number, public status: RollResultStatus, public dice: Array) {} } export enum RollResultStatus { FAILURE, SUCCESS, CRITICAL_FAILURE, CRITICAL_SUCCESS, }