diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2cf6fcb..c32e0c3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,12 +33,12 @@ build: stage: build script: - npm run build - - mv dist risk-dice + - mv dist-modifier cache: <<: *global_cache artifacts: paths: - - risk-dice + - risk-dice-modifier expire_in: 1 week .release-template: &release-template diff --git a/README.md b/README.md index 0256d0d..a47094e 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,27 @@ -# Risk Dice +# Risk Dice Modifier -An implementation of risk dice as found for example in the Splittermond game +An implementation of risk rolls as found for example in the Splittermond game system. -This module provides a new dice type which represents a risk die. Rolling a risk -die ist just rolling a number of dice combined with s special way of calculating -the total: -- If there are either two `1`s or a `1` and a `2` in the results, the total sum - is `1 + 1` or `1 + 2` respectively. -- Otherwise, the total result is the sum of the 2 highest results. - +This module provides a new dice modifier `ri` for regular Dice. This modifier +causes the dice roller to keep / drop dice according to the following rules: +- If there are either two `1`s or a `1` and a `2` in the results, keep only + these dice. +- Otherwise, keep the 2 dice with the highest results. ``` -/roll dr # Roll a risk die. +/roll 4d10ri # Roll 4d10 is risk die mode ``` -![Risk Dice](./risk-dice.png) - - +![Risk Dice Modifier](./risk-dice-modifier.png) ## Installation -To install and use the Risk Dice module for Foundry Virtual Tabletop, +To install and use the Risk Dice Modifier module for Foundry Virtual Tabletop, simply paste the following URL into the **Install Module** dialog on the Setup menu of the application. -https://git.f3l.de/ghost/risk-dice/-/raw/latest/src/module.json?inline=false +https://git.f3l.de/ghost/risk-dice-modifier/-/raw/latest/src/module.json?inline=false ## Development diff --git a/package.json b/package.json index 290dee1..13c7f00 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { "private": true, - "name": "risk-dice", - "description": "An implementation of Risk Dice as found for example in the Splittermond game system", + "name": "risk-dice-modifier", + "description": "An implementation of risk rolls as found for example in the Splittermond game system", "version": "0.0.1", "license": "MIT", - "homepage": "https://git.f3l.de/ghost/risk-dice", + "homepage": "https://git.f3l.de/ghost/risk-dice-modifier", "repository": { "type": "git", - "url": "https://git.f3l.de/ghost/risk-dice" + "url": "https://git.f3l.de/ghost/risk-dice-modifier" }, "bugs": { - "url": "https://git.f3l.de/ghost/risk-dice/-/issues" + "url": "https://git.f3l.de/ghost/risk-dice-modifier/-/issues" }, "contributors": [ { diff --git a/risk-dice-modifier.png b/risk-dice-modifier.png new file mode 100644 index 0000000..bde7656 Binary files /dev/null and b/risk-dice-modifier.png differ diff --git a/risk-dice.png b/risk-dice.png deleted file mode 100644 index d5e57b5..0000000 Binary files a/risk-dice.png and /dev/null differ diff --git a/src/lang/de.json b/src/lang/de.json deleted file mode 100644 index 069831f..0000000 --- a/src/lang/de.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "RiskDice.ErrorNumberMustBeAtLeast3": "Die Anzahl an Würfeln muss mindestens 3 sein." -} diff --git a/src/lang/en.json b/src/lang/en.json deleted file mode 100644 index fbf72b3..0000000 --- a/src/lang/en.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "RiskDice.ErrorNumberMustBeAtLeast3": "The number of dice must be at least 3." -} diff --git a/src/module.json b/src/module.json index 5052f5f..cf4bde8 100644 --- a/src/module.json +++ b/src/module.json @@ -1,26 +1,14 @@ { - "name": "risk-dice", - "title": "Risk Dice", - "description": "An implementation of Risk Dice as found for example in the Splittermond game system", + "name": "risk-dice-modifier", + "title": "Risk Dice Modifier", + "description": "An implementation of risk rolls as found for example in the Splittermond game system", "author": "Johannes Loher", "version": "0.0.1", "minimumCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9", "esmodules": ["module/risk-dice.js"], - "languages": [ - { - "lang": "en", - "name": "English", - "path": "lang/en.json" - }, - { - "lang": "de", - "name": "Deutsch", - "path": "lang/de.json" - } - ], "url": "https://git.f3l.de/ghost/risk-dice", - "manifest": "https://git.f3l.de/ghost/risk-dice/-/raw/latest/src/system.json?inline=false", - "download": "https://git.f3l.de/ghost/risk-dice/-/jobs/artifacts/0.0.1/download?job=build", + "manifest": "https://git.f3l.de/ghost/risk-dice-modifier/-/raw/latest/src/system.json?inline=false", + "download": "https://git.f3l.de/ghost/risk-dice-modifier/-/jobs/artifacts/0.0.1/download?job=build", "license": "MIT" } diff --git a/src/module/risk-dice-modifier.ts b/src/module/risk-dice-modifier.ts new file mode 100644 index 0000000..53d01d6 --- /dev/null +++ b/src/module/risk-dice-modifier.ts @@ -0,0 +1,12 @@ +import { risk } from './risk'; + +function registerRiskModifier(): void { + // TODO: Make it possible to extend MODIFIERS in foundry-vtt-types + // eslint-disable-next-line + // @ts-ignore + Die.MODIFIERS.ri = risk; +} + +Hooks.once('init', () => { + registerRiskModifier(); +}); diff --git a/src/module/risk-dice.ts b/src/module/risk-dice.ts deleted file mode 100644 index 86486ab..0000000 --- a/src/module/risk-dice.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RiskDie } from './risk-die'; - -function registerRiskDie(): void { - CONFIG.Dice.types.push(RiskDie); - CONFIG.Dice.terms.r = RiskDie; -} - -Hooks.once('init', () => { - registerRiskDie(); -}); diff --git a/src/module/risk-die.ts b/src/module/risk-die.ts deleted file mode 100644 index 87be868..0000000 --- a/src/module/risk-die.ts +++ /dev/null @@ -1,51 +0,0 @@ -export class RiskDie extends DiceTerm { - constructor({ modifiers, ...other }: Partial) { - const numberModifier = modifiers?.filter((m) => m[0] === 'n')[0]; - const numberRegex = new RegExp('n([0-9]+)?'); - const numberMatch = numberModifier?.match(numberRegex); - const [numberString] = numberMatch?.slice(1) || [`${4}`]; - const number = parseInt(numberString); - - const facesModifier = modifiers?.filter((m) => m[0] === 'f')[0]; - const facesRegex = new RegExp('f([0-9]+)?'); - const facesMatch = facesModifier?.match(facesRegex); - const [facesString] = facesMatch?.slice(1) || [`${10}`]; - const faces = parseInt(facesString); - - if (number < 3) { - throw new Error(game.i18n.localize('RiskDice.ErrorNumberMustBeAtLeast3')); - } - - super({ ...other, modifiers, number, faces }); - } - - /** - * Return the dice expression portion of the full term formula, excluding any flavor text. - */ - get expression(): string { - return `d${RiskDie.DENOMINATION}${this.modifiers.join('')}`; - } - - get total(): number | null { - if (!this._evaluated) return null; - if (this.values.includes(1) && this.values.includes(2)) { - return 3; - } else if (this.values.filter((res) => res === 1).length > 1) { - return 2; - } else { - return this.values - .sort((a, b) => b - a) - .slice(0, 2) - .reduce((acc, e) => acc + e, 0); - } - } - - /** @override */ - static MODIFIERS = { - n: (): void => undefined, // Modifier is consumed in constructor for number - f: (): void => undefined, // Modifier is consumed in constructor for faces - }; - - /** @override */ - static DENOMINATION = 'r'; -} diff --git a/src/module/risk.ts b/src/module/risk.ts new file mode 100644 index 0000000..116aa0b --- /dev/null +++ b/src/module/risk.ts @@ -0,0 +1,52 @@ +export function risk(this: Die): void { + const activeResults = this.results.filter((result) => result.active); + const activeValues = activeResults.map((result) => result.result); + + activeResults.forEach((result) => { + markResultInactive(result); + }); + + if (activeValues.includes(1) && activeValues.includes(2)) { + markFirstOneAndFirstTwoActive(activeResults); + } else if (activeValues.filter((value) => value === 1).length > 1) { + markFirstTwoOnesActive(activeResults); + } else { + markTwoBiggestResultsActive(activeResults); + } +} + +function markResultInactive(result: DiceTerm.Result): void { + result.active = false; + result.discarded = true; +} + +function markResultActive(result: DiceTerm.Result): void { + result.active = true; + result.discarded = false; +} + +function markFirstOneAndFirstTwoActive(results: DiceTerm.Result[]): void { + const firstOne = results.find((result) => result.result === 1) as DiceTerm.Result; + markResultActive(firstOne); + + const firstTwo = results.find((result) => result.result === 2) as DiceTerm.Result; + markResultActive(firstTwo); +} + +function markFirstTwoOnesActive(results: DiceTerm.Result[]): void { + const [firstOne, secondOne] = results.filter((result) => result.result === 1); + firstOne.active = true; + firstOne.discarded = false; + secondOne.active = true; + secondOne.discarded = false; +} + +function markTwoBiggestResultsActive(results: DiceTerm.Result[]): void { + [...results] + .sort((a, b) => b.result - a.result) + .slice(0, 2) + .forEach((result) => { + result.active = true; + result.discarded = false; + }); +}