Implement swapping edge case, restructure sources.
This commit is contained in:
parent
3f6f9f795f
commit
55beeb92c9
5 changed files with 173 additions and 76 deletions
28
src/module/rolls/roll-data.ts
Normal file
28
src/module/rolls/roll-data.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
export interface RollOptions {
|
||||
maxCritSucc: number;
|
||||
minCritFail: number;
|
||||
useSlayingDice: boolean;
|
||||
slayingDiceRepetition: boolean;
|
||||
}
|
||||
|
||||
export class DefaultRollOptions implements RollOptions {
|
||||
public maxCritSucc = 1;
|
||||
public minCritFail = 20;
|
||||
public useSlayingDice = false;
|
||||
public slayingDiceRepetition = false;
|
||||
|
||||
mergeWith(other: Partial<RollOptions>): RollOptions {
|
||||
return { ...this, ...other } as RollOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export class RollResult {
|
||||
constructor(public value: number, public status: RollResultStatus, public dice: Array<number>) {}
|
||||
}
|
||||
|
||||
export enum RollResultStatus {
|
||||
FAILURE,
|
||||
SUCCESS,
|
||||
CRITICAL_FAILURE,
|
||||
CRITICAL_SUCCESS,
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import { DefaultRollOptions, RollOptions, RollResult, RollResultStatus } from "./roll-data";
|
||||
import { DS4RollProvider, RollProvider } from "./roll-provider";
|
||||
import { isDiceSwapNecessary, isSlayingDiceRepetition } from "./roll-utils";
|
||||
|
||||
export function ds4test(testValue: number, rollOptions: Partial<RollOptions> = {}): RollResult {
|
||||
const finalRollValue = testValue;
|
||||
|
@ -20,7 +22,7 @@ export function rollCheckSingleDie(
|
|||
|
||||
if (roll <= usedOptions.maxCritSucc) {
|
||||
return new RollResult(testValue, RollResultStatus.CRITICAL_SUCCESS, dice);
|
||||
} else if (roll >= usedOptions.minCritFail) {
|
||||
} else if (roll >= usedOptions.minCritFail && !isSlayingDiceRepetition(usedOptions)) {
|
||||
return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, dice);
|
||||
} else {
|
||||
if (roll <= testValue) {
|
||||
|
@ -44,7 +46,8 @@ export function rollCheckMultipleDice(
|
|||
|
||||
const firstResult = dice[0];
|
||||
|
||||
if (firstResult >= usedOptions.minCritFail) {
|
||||
// Slaying Dice require a different handling.
|
||||
if (firstResult >= usedOptions.minCritFail && !isSlayingDiceRepetition(usedOptions)) {
|
||||
return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, dice);
|
||||
}
|
||||
|
||||
|
@ -61,13 +64,22 @@ export function rollCheckMultipleDice(
|
|||
.reduce(partitionCallback, [[], []])
|
||||
.map((a) => a.sort((r1, r2) => r2 - r1));
|
||||
|
||||
const sortedRollResults: Array<number> = critSuccesses.concat(otherRolls);
|
||||
const swapLastWithCrit: boolean = isDiceSwapNecessary(critSuccesses, otherRolls, finalCheck);
|
||||
|
||||
let sortedRollResults: Array<number>;
|
||||
|
||||
if (swapLastWithCrit) {
|
||||
const diceToMove = critSuccesses[0];
|
||||
const remainingSuccesses = critSuccesses.slice(1);
|
||||
sortedRollResults = remainingSuccesses.concat(otherRolls).concat([diceToMove]);
|
||||
} else {
|
||||
sortedRollResults = critSuccesses.concat(otherRolls);
|
||||
}
|
||||
|
||||
const evaluationResult = sortedRollResults
|
||||
.map((value, index) => {
|
||||
if (index == numberOfDice - 1) {
|
||||
console.log(`Last dice: ${value}, checking against ${finalCheck}`);
|
||||
if (value == 1) {
|
||||
if (value <= usedOptions.maxCritSucc) {
|
||||
return finalCheck;
|
||||
} else if (value <= finalCheck) {
|
||||
return value;
|
||||
|
@ -86,32 +98,3 @@ export function rollCheckMultipleDice(
|
|||
|
||||
return new RollResult(evaluationResult, RollResultStatus.SUCCESS, sortedRollResults);
|
||||
}
|
||||
|
||||
export interface RollOptions {
|
||||
maxCritSucc: number;
|
||||
minCritFail: number;
|
||||
useSlayingDice: boolean;
|
||||
slayingDiceRepetition: boolean;
|
||||
}
|
||||
|
||||
class DefaultRollOptions implements RollOptions {
|
||||
public maxCritSucc = 1;
|
||||
public minCritFail = 20;
|
||||
public useSlayingDice = false;
|
||||
public slayingDiceRepetition = false;
|
||||
|
||||
mergeWith(other: Partial<RollOptions>): RollOptions {
|
||||
return { ...this, ...other } as RollOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export class RollResult {
|
||||
constructor(public value: number, public status: RollResultStatus, public dice: Array<number>) {}
|
||||
}
|
||||
|
||||
export enum RollResultStatus {
|
||||
FAILURE,
|
||||
SUCCESS,
|
||||
CRITICAL_FAILURE,
|
||||
CRITICAL_SUCCESS,
|
||||
}
|
||||
|
|
22
src/module/rolls/roll-utils.ts
Normal file
22
src/module/rolls/roll-utils.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { RollOptions } from "./roll-data";
|
||||
|
||||
export function isDiceSwapNecessary(
|
||||
critSuccesses: Array<number>,
|
||||
otherRolls: Array<number>,
|
||||
finalRollValue: number,
|
||||
): boolean {
|
||||
if (critSuccesses.length == 0 || otherRolls.length == 0) {
|
||||
return false;
|
||||
}
|
||||
const amountOfOtherRolls = otherRolls.length;
|
||||
const lastDice = otherRolls[amountOfOtherRolls - 1];
|
||||
if (lastDice <= finalRollValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lastDice + finalRollValue > 20;
|
||||
}
|
||||
|
||||
export function isSlayingDiceRepetition(opts: RollOptions): boolean {
|
||||
return opts.useSlayingDice && opts.slayingDiceRepetition;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue