From a19a996d1d8d94265b1910592bd82f6a71cf5d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20R=C3=BCmpelein?= Date: Sun, 10 Jan 2021 16:40:11 +0100 Subject: [PATCH] Display (only!) selection options to the user. --- spec/support/ds4rolls/executor.spec.ts | 28 ++++++------ src/module/rolls/check-factory.ts | 62 ++++++++++++++++++++++---- src/module/rolls/check.ts | 2 +- src/module/rolls/roll-data.ts | 4 +- src/module/rolls/roll-executor.ts | 4 +- src/templates/roll/roll-options.hbs | 16 +++++++ 6 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 src/templates/roll/roll-options.hbs diff --git a/spec/support/ds4rolls/executor.spec.ts b/spec/support/ds4rolls/executor.spec.ts index 705241a9..58997a98 100644 --- a/spec/support/ds4rolls/executor.spec.ts +++ b/spec/support/ds4rolls/executor.spec.ts @@ -65,37 +65,37 @@ describe("DS4 Rolls with one die and slaying dice, followup throw.", () => { describe("DS4 Rolls with one die and crit roll modifications.", () => { it("Should do a crit success on `1`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [1])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [1])).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [1]), ); }); it("Should do a crit success on `maxCritSucc`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [2])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [2])).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [2]), ); }); it("Should do a success on lower edge case `3`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [3])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [3])).toEqual( new RollResult(3, RollResultStatus.SUCCESS, [3]), ); }); it("Should do a success on upper edge case `18`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [18])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [18])).toEqual( new RollResult(0, RollResultStatus.FAILURE, [18]), ); }); - it("Should do a crit fail on `minCritFail`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [19])).toEqual( + it("Should do a crit fail on `minCritFailure`.", () => { + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [19])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19]), ); }); it("Should do a crit fail on `20`", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [20])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [20])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [20]), ); }); @@ -171,37 +171,37 @@ describe("DS4 Rolls with multiple dice and no modifiers.", () => { describe("DS4 Rolls with multiple dice and min/max modifiers.", () => { it("Should do a crit fail on `19` for first roll.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [19, 15, 6])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [19, 15, 6])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19, 15, 6]), ); }); it("Should succeed with all rolls crit successes (1 and 2).", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [2, 1, 2])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [2, 1, 2])).toEqual( new RollResult(48, RollResultStatus.CRITICAL_SUCCESS, [2, 1, 2]), ); }); it("Should succeed with the last roll not being sufficient.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 15, 15])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 15, 15])).toEqual( new RollResult(30, RollResultStatus.SUCCESS, [15, 15, 15]), ); }); it("Should succeed with the last roll a crit success `2`.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 15, 2])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 15, 2])).toEqual( new RollResult(38, RollResultStatus.SUCCESS, [15, 15, 2]), ); }); it("Should succeed with the last roll being `20` and one crit success '2'.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 2, 20])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 2, 20])).toEqual( new RollResult(43, RollResultStatus.SUCCESS, [15, 2, 20]), ); }); it("Should succeed with the last roll being `19` and one crit success '2'.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 2, 19])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 2, 19])).toEqual( new RollResult(42, RollResultStatus.SUCCESS, [15, 2, 19]), ); }); @@ -209,7 +209,7 @@ describe("DS4 Rolls with multiple dice and min/max modifiers.", () => { describe("DS4 Rolls with multiple dice and fail modifiers.", () => { it("Should do a crit fail on `19` for first roll.", () => { - expect(rollCheckMultipleDice(48, { minCritFail: 19 }, [19, 15, 6])).toEqual( + expect(rollCheckMultipleDice(48, { minCritFailure: 19 }, [19, 15, 6])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19, 15, 6]), ); }); diff --git a/src/module/rolls/check-factory.ts b/src/module/rolls/check-factory.ts index 43b06927..24c563c0 100644 --- a/src/module/rolls/check-factory.ts +++ b/src/module/rolls/check-factory.ts @@ -14,6 +14,8 @@ class DefaultCheckOptions implements DS4CheckFactoryOptions { } } +const defaultCheckOptions = new DefaultCheckOptions(); + /** * Most basic class responsible for generating the chat formula and passing it to the chat as roll. */ @@ -53,8 +55,8 @@ class CheckFactory { } createCritTerm(): string { - const minCritRequired = this.checkOptions.minCritFailure !== CheckFactory.defaultCheckOptions.minCritFailure; - const maxCritRequired = this.checkOptions.maxCritSuccess !== CheckFactory.defaultCheckOptions.maxCritSuccess; + const minCritRequired = this.checkOptions.minCritFailure !== defaultCheckOptions.minCritFailure; + const maxCritRequired = this.checkOptions.maxCritSuccess !== defaultCheckOptions.maxCritSuccess; if (minCritRequired || maxCritRequired) { return "c" + (this.checkOptions.maxCritSuccess ?? "") + "," + (this.checkOptions.minCritFailure ?? ""); @@ -66,8 +68,6 @@ class CheckFactory { createSlayingDiceTerm(): string { return this.checkOptions.useSlayingDice ? "x" : null; } - - static defaultCheckOptions = new DefaultCheckOptions(); } // TODO: Figure out return of roll (void should be Ok, tough?) @@ -78,10 +78,10 @@ class CheckFactory { */ export async function createCheckRoll(targetValue: number, options: Partial): Promise { // Ask for additional required data; - const gmModifier = await askGmModifier(); + const gmModifierData = await askGmModifier(targetValue, options); // Create Factory - const cf = new CheckFactory(targetValue, gmModifier, options); + const cf = new CheckFactory(targetValue, gmModifierData.gmModifier, options); // Possibly additional processing @@ -92,11 +92,53 @@ export async function createCheckRoll(targetValue: number, options: Partial} The number by the user. */ -async function askGmModifier(): Promise { +async function askGmModifier( + targetValue: number, + options: Partial, + { template, title }: { template?: string; title?: string } = {}, +): Promise { // Render model interface and return value - return 0; + const usedTemplate = template ?? "systems/ds4/templates/roll/roll-options.hbs"; + const templateData = { + cssClass: "roll-option", + title: title ?? "Roll Options", + checkTargetValue: targetValue, + maxCritSuccess: options.maxCritSuccess ?? defaultCheckOptions.maxCritSuccess, + minCritFailure: options.minCritFailure ?? defaultCheckOptions.minCritFailure, + rollModes: rollModes, + }; + const renderedHtml = await renderTemplate(usedTemplate, templateData); + + // TODO: Localize + const dialogData: DialogData = { + title: title ?? "Roll Options", + close: (html) => null, + content: renderedHtml, + buttons: { + ok: { + label: "OK", + callback: (html) => null, + }, + cancel: { + label: "Cancel", + callback: (html) => null, + }, + }, + default: "ok", + }; + + const dialog = new Dialog(dialogData, {}).render(true); + + return { gmModifier: 0 }; +} + +interface GmModifierData { + gmModifier: number; } export interface DS4CheckFactoryOptions { @@ -106,4 +148,6 @@ export interface DS4CheckFactoryOptions { rollMode: DS4RollMode; } -export type DS4RollMode = "roll" | "gmroll" | "blindroll" | "selfroll"; +const rollModes = ["roll", "gmroll", "blindroll", "selfroll"] as const; +type DS4RollModeTuple = typeof rollModes; +export type DS4RollMode = DS4RollModeTuple[number]; diff --git a/src/module/rolls/check.ts b/src/module/rolls/check.ts index 7911cded..38773fb3 100644 --- a/src/module/rolls/check.ts +++ b/src/module/rolls/check.ts @@ -86,7 +86,7 @@ export class DS4Check extends DiceTerm { } else { return ds4roll(targetValueToUse, { maxCritSuccess: this.maxCritSuccess, - minCritFail: this.minCritFailure, + minCritFailure: this.minCritFailure, slayingDiceRepetition: slayingDiceRepetition, useSlayingDice: slayingDiceRepetition, }); diff --git a/src/module/rolls/roll-data.ts b/src/module/rolls/roll-data.ts index 964034c9..78329e44 100644 --- a/src/module/rolls/roll-data.ts +++ b/src/module/rolls/roll-data.ts @@ -1,13 +1,13 @@ export interface RollOptions { maxCritSuccess: number; - minCritFail: number; + minCritFailure: number; useSlayingDice: boolean; slayingDiceRepetition: boolean; } export class DefaultRollOptions implements RollOptions { public maxCritSuccess = 1; - public minCritFail = 20; + public minCritFailure = 20; public useSlayingDice = false; public slayingDiceRepetition = false; diff --git a/src/module/rolls/roll-executor.ts b/src/module/rolls/roll-executor.ts index 72e6b2c4..c7e187b1 100644 --- a/src/module/rolls/roll-executor.ts +++ b/src/module/rolls/roll-executor.ts @@ -48,7 +48,7 @@ export function rollCheckSingleDie( if (rolledDie <= usedOptions.maxCritSuccess) { return new RollResult(checkTargetValue, RollResultStatus.CRITICAL_SUCCESS, usedDice, true); - } else if (rolledDie >= usedOptions.minCritFail && !isSlayingDiceRepetition(usedOptions)) { + } else if (rolledDie >= usedOptions.minCritFailure && !isSlayingDiceRepetition(usedOptions)) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true); } else { if (rolledDie <= checkTargetValue) { @@ -90,7 +90,7 @@ export function rollCheckMultipleDice( const slayingDiceRepetition = isSlayingDiceRepetition(usedOptions); // Slaying Dice require a different handling. - if (firstResult >= usedOptions.minCritFail && !slayingDiceRepetition) { + if (firstResult >= usedOptions.minCritFailure && !slayingDiceRepetition) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true); } diff --git a/src/templates/roll/roll-options.hbs b/src/templates/roll/roll-options.hbs new file mode 100644 index 00000000..4cab330e --- /dev/null +++ b/src/templates/roll/roll-options.hbs @@ -0,0 +1,16 @@ +
+ + + + + + + + + + +