ds4/src/module/rolls/roll-executor.ts
2020-12-31 02:27:21 +01:00

99 lines
2.9 KiB
TypeScript

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<number>, Array<number>], 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<number> = 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<number>) {}
}
export enum RollResultStatus {
FAILURE,
SUCCESS,
CRITICAL_FAILURE,
CRITICAL_SUCCESS,
}