diff --git a/spec/support/ds4rolls.spec.ts b/spec/support/ds4rolls.spec.ts index 093f3157..6b8e3228 100644 --- a/spec/support/ds4rolls.spec.ts +++ b/spec/support/ds4rolls.spec.ts @@ -1,4 +1,10 @@ -import { rollCheckSingleDie, RollOptions, RollResult, RollResultStatus } from "../../src/module/rolls/roll-executor"; +import { + rollCheckMultipleDice, + rollCheckSingleDie, + RollOptions, + RollResult, + RollResultStatus, +} from "../../src/module/rolls/roll-executor"; import { RollProvider } from "../../src/module/rolls/roll-provider"; describe("DS4 Rolls with one die and no modifications.", () => { @@ -68,6 +74,7 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(1); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [1]), ); @@ -77,6 +84,7 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(2); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [2]), ); @@ -86,6 +94,7 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(3); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(3, RollResultStatus.SUCCESS, [3]), ); @@ -95,6 +104,7 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(18); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(0, RollResultStatus.FAILURE, [18]), ); @@ -104,6 +114,7 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(19); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19]), ); @@ -113,8 +124,61 @@ describe("DS4 Rolls with one die and crit roll modifications.", () => { const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRoll"]); rollProvider.getNextRoll = jasmine.createSpy("getNextRoll").and.returnValue(20); + expect(rollCheckSingleDie(4, { maxCritSucc: 2, minCritFail: 19 }, rollProvider)).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [20]), ); }); }); + +describe("DS4 Rools with multiple dice and no modifiers.", () => { + it("Should do a crit fail on `20` for first roll.", () => { + const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRolls"]); + + rollProvider.getNextRolls = jasmine.createSpy("getNextRolls").and.returnValue([20, 15, 6]); + + expect(rollCheckMultipleDice(48, new RollOptions(), rollProvider)).toEqual( + new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [20, 15, 6]), + ); + }); + + it("Should succeed with all rolls crit successes.", () => { + const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRolls"]); + + rollProvider.getNextRolls = jasmine.createSpy("getNextRolls").and.returnValue([1, 1, 1]); + + expect(rollCheckMultipleDice(48, new RollOptions(), rollProvider)).toEqual( + new RollResult(48, RollResultStatus.SUCCESS, [1, 1, 1]), + ); + }); + + it("Should succeed with the last roll not being suficient.", () => { + const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRolls"]); + + rollProvider.getNextRolls = jasmine.createSpy("getNextRolls").and.returnValue([15, 15, 15]); + + expect(rollCheckMultipleDice(48, new RollOptions(), rollProvider)).toEqual( + new RollResult(30, RollResultStatus.SUCCESS, [15, 15, 15]), + ); + }); + + it("Should succeed with the last roll a crit success.", () => { + const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRolls"]); + + rollProvider.getNextRolls = jasmine.createSpy("getNextRolls").and.returnValue([15, 15, 1]); + + expect(rollCheckMultipleDice(48, new RollOptions(), rollProvider)).toEqual( + new RollResult(35, RollResultStatus.SUCCESS, [1, 15, 15]), + ); + }); + + it("Should succeed with the last roll being 20 and one crit success.", () => { + const rollProvider: RollProvider = jasmine.createSpyObj("rollProvider", ["getNextRolls"]); + + rollProvider.getNextRolls = jasmine.createSpy("getNextRolls").and.returnValue([15, 1, 20]); + + expect(rollCheckMultipleDice(48, new RollOptions(), rollProvider)).toEqual( + new RollResult(40, RollResultStatus.SUCCESS, [1, 20, 15]), + ); + }); +}); diff --git a/src/module/rolls/roll-executor.ts b/src/module/rolls/roll-executor.ts index a4b67e32..1c23d3f2 100644 --- a/src/module/rolls/roll-executor.ts +++ b/src/module/rolls/roll-executor.ts @@ -30,27 +30,41 @@ export function rollCheckSingleDie( } } -function rollCheckMultipleDice(testValue: number, rollOptions: RollOptions): RollResult { +export function rollCheckMultipleDice( + testValue: number, + rollOptions: RollOptions, + provider: RollProvider = new DS4RollProvider(), +): RollResult { const finalCheck = testValue % 20; const numberOfDice = Math.ceil(testValue / 20); - const rolls = new Array(); - for (let i = 0; i < numberOfDice; i++) { - const roll = new Roll("1d20"); - roll.roll(); - rolls.concat(roll); - } - const dice = rolls.map((r) => r.total); - const firstResult = dice[1]; + const dice = provider.getNextRolls(numberOfDice); + + console.log(dice[0]); + console.log(rollOptions.minCritFail); + + const firstResult = dice[0]; if (firstResult >= rollOptions.minCritFail) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, dice); } - const [otherRolls, critSuccesses] = dice - .partition((r) => r <= rollOptions.maxCritSucc) + 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)); + console.log(critSuccesses); + console.log(otherRolls); + const sortedRollResults: Array = critSuccesses.concat(otherRolls); const evaluationResult = sortedRollResults @@ -59,7 +73,7 @@ function rollCheckMultipleDice(testValue: number, rollOptions: RollOptions): Rol if (value == 1) { return finalCheck; } else { - return value >= finalCheck ? value : 0; + return value <= finalCheck ? value : 0; } } else { if (value <= rollOptions.maxCritSucc) {