diff --git a/spec/rolls/check-evaluation.spec.ts b/spec/rolls/check-evaluation.spec.ts index 4df65e2c..8498bdde 100644 --- a/spec/rolls/check-evaluation.spec.ts +++ b/spec/rolls/check-evaluation.spec.ts @@ -48,30 +48,134 @@ describe("evaluateCheck with a single die", () => { { result: 20, checkTargetNumber: 4, active: false, discarded: true, failure: true }, ]); }); + + it("should roll a die even when the checkTargetNumber is 0 and coup on 1", () => { + expect(evaluateCheck([1], 0)).toEqual([ + { result: 1, checkTargetNumber: 0, active: true, discarded: false, success: true, count: 0 }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is 0 and fail on values > 1 and < 20", () => { + for (let i = 2; i < 20; i++) { + expect(evaluateCheck([i], 0)).toEqual([ + { result: i, checkTargetNumber: 0, active: false, discarded: true }, + ]); + } + }); + + it("should roll a die even when the checkTargetNumber is 0 and fumble on 20", () => { + expect(evaluateCheck([20], 0)).toEqual([ + { result: 20, checkTargetNumber: 0, active: false, discarded: true, failure: true }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is < 0 and coup on 1", () => { + expect(evaluateCheck([1], -1)).toEqual([ + { result: 1, checkTargetNumber: -1, active: true, discarded: false, success: true, count: -1 }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is < 0 and fail on values > 1 and < 20", () => { + for (let i = 2; i < 20; i++) { + expect(evaluateCheck([i], -1)).toEqual([ + { result: i, checkTargetNumber: -1, active: false, discarded: true }, + ]); + } + }); + + it("should roll a die even when the checkTargetNumber is < 0 and fumble on 20", () => { + expect(evaluateCheck([20], -1)).toEqual([ + { result: 20, checkTargetNumber: -1, active: false, discarded: true, failure: true }, + ]); + }); }); describe("evaluateCheck with a single die and coup / fumble modification", () => { + const maximumCoupResult = 2; + const minimumFumbleResult = 19; + it("should assign the checkTargetNumber to the single die and coup on 'maximumCoupResult'", () => { - expect(evaluateCheck([2], 4, { maximumCoupResult: 2 })).toEqual([ - { result: 2, checkTargetNumber: 4, active: true, discarded: false, success: true, count: 4 }, + expect(evaluateCheck([maximumCoupResult], 4, { maximumCoupResult })).toEqual([ + { + result: maximumCoupResult, + checkTargetNumber: 4, + active: true, + discarded: false, + success: true, + count: 4, + }, ]); }); - it("should assign the checkTargetNumber to the single die and not coup on lower edge case '3'", () => { - expect(evaluateCheck([3], 4, { maximumCoupResult: 2 })).toEqual([ - { result: 3, checkTargetNumber: 4, active: true, discarded: false }, + it("should assign the checkTargetNumber to the single die and not coup on lower edge case 'maximumCoupResult + 1'", () => { + expect(evaluateCheck([maximumCoupResult + 1], 4, { maximumCoupResult })).toEqual([ + { result: maximumCoupResult + 1, checkTargetNumber: 4, active: true, discarded: false }, ]); }); - it("should assign the checkTargetNumber to the single die and fumble on 'minimumFUmbleResultResult'", () => { - expect(evaluateCheck([19], 20, { minimumFumbleResult: 19 })).toEqual([ - { result: 19, checkTargetNumber: 20, active: true, discarded: false, failure: true }, + it("should assign the checkTargetNumber to the single die and fumble on 'minimumFumbleResultResult'", () => { + expect(evaluateCheck([minimumFumbleResult], 20, { minimumFumbleResult })).toEqual([ + { result: minimumFumbleResult, checkTargetNumber: 20, active: true, discarded: false, failure: true }, ]); }); - it("should assign the checkTargetNumber to the single die and not fumble on upper edge case '18'", () => { - expect(evaluateCheck([18], 20, { minimumFumbleResult: 19 })).toEqual([ - { result: 18, checkTargetNumber: 20, active: true, discarded: false }, + it("should assign the checkTargetNumber to the single die and not fumble on upper edge case 'minimumFumbleResult - 1'", () => { + expect(evaluateCheck([minimumFumbleResult - 1], 20, { minimumFumbleResult })).toEqual([ + { result: minimumFumbleResult - 1, checkTargetNumber: 20, active: true, discarded: false }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is 0 and coup on 'maximumCoupResult'", () => { + expect(evaluateCheck([maximumCoupResult], 0, { maximumCoupResult })).toEqual([ + { + result: maximumCoupResult, + checkTargetNumber: 0, + active: true, + discarded: false, + success: true, + count: 0, + }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is 0 and fail on '> maximumCoupResult and < minimumFumbleResult", () => { + for (let i = maximumCoupResult + 1; i < minimumFumbleResult; i++) { + expect(evaluateCheck([i], 0, { maximumCoupResult, minimumFumbleResult })).toEqual([ + { result: i, checkTargetNumber: 0, active: false, discarded: true }, + ]); + } + }); + + it("should roll a die even when the checkTargetNumber is 0 and fumble on 'minimumFumbleResult'", () => { + expect(evaluateCheck([minimumFumbleResult], 0, { minimumFumbleResult })).toEqual([ + { result: minimumFumbleResult, checkTargetNumber: 0, active: false, discarded: true, failure: true }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is < 0 and coup on 'maximumCoupResult'", () => { + expect(evaluateCheck([maximumCoupResult], -1, { maximumCoupResult })).toEqual([ + { + result: maximumCoupResult, + checkTargetNumber: -1, + active: true, + discarded: false, + success: true, + count: -1, + }, + ]); + }); + + it("should roll a die even when the checkTargetNumber is < 0 and fail on '> maximumCoupResult and < minimumFumbleResult", () => { + for (let i = maximumCoupResult + 1; i < minimumFumbleResult; i++) { + expect(evaluateCheck([i], -1, { maximumCoupResult, minimumFumbleResult })).toEqual([ + { result: i, checkTargetNumber: -1, active: false, discarded: true }, + ]); + } + }); + + it("should roll a die even when the checkTargetNumber is < 0 and fumble on 'minimumFumbleResult'", () => { + expect(evaluateCheck([minimumFumbleResult], -1, { minimumFumbleResult })).toEqual([ + { result: minimumFumbleResult, checkTargetNumber: -1, active: false, discarded: true, failure: true }, ]); }); }); diff --git a/src/module/rolls/check-evaluation.ts b/src/module/rolls/check-evaluation.ts index 442ecf3d..d0322a73 100644 --- a/src/module/rolls/check-evaluation.ts +++ b/src/module/rolls/check-evaluation.ts @@ -113,5 +113,5 @@ function evaluateDiceWithSubChecks( } export function getRequiredNumberOfDice(checkTargetNumber: number): number { - return Math.ceil(checkTargetNumber / 20); + return Math.max(Math.ceil(checkTargetNumber / 20), 1); } diff --git a/src/module/rolls/check-factory.ts b/src/module/rolls/check-factory.ts index b98d96cf..6e90977b 100644 --- a/src/module/rolls/check-factory.ts +++ b/src/module/rolls/check-factory.ts @@ -45,8 +45,8 @@ class CheckFactory { ); } - createCheckTargetNumberModifier(): string | null { - return "v" + (this.checkTargetNumber + this.gmModifier); + createCheckTargetNumberModifier(): string { + return "v" + Math.max(this.checkTargetNumber + this.gmModifier, 0); } createCoupFumbleModifier(): string | null {