Use a dice modifier instead of a custom DiceTerm

This commit is contained in:
Johannes Loher 2021-02-07 19:06:21 +01:00
parent bea124c3b8
commit 150942215e
12 changed files with 87 additions and 106 deletions

View file

@ -33,12 +33,12 @@ build:
stage: build stage: build
script: script:
- npm run build - npm run build
- mv dist risk-dice - mv dist-modifier
cache: cache:
<<: *global_cache <<: *global_cache
artifacts: artifacts:
paths: paths:
- risk-dice - risk-dice-modifier
expire_in: 1 week expire_in: 1 week
.release-template: &release-template .release-template: &release-template

View file

@ -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. system.
This module provides a new dice type which represents a risk die. Rolling a risk This module provides a new dice modifier `ri` for regular Dice. This modifier
die ist just rolling a number of dice combined with s special way of calculating causes the dice roller to keep / drop dice according to the following rules:
the total: - If there are either two `1`s or a `1` and a `2` in the results, keep only
- If there are either two `1`s or a `1` and a `2` in the results, the total sum these dice.
is `1 + 1` or `1 + 2` respectively. - Otherwise, keep the 2 dice with the highest results.
- Otherwise, the total result is the sum of the 2 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 ## 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 simply paste the following URL into the **Install Module** dialog on the Setup
menu of the application. 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 ## Development

View file

@ -1,16 +1,16 @@
{ {
"private": true, "private": true,
"name": "risk-dice", "name": "risk-dice-modifier",
"description": "An implementation of Risk Dice as found for example in the Splittermond game system", "description": "An implementation of risk rolls as found for example in the Splittermond game system",
"version": "0.0.1", "version": "0.0.1",
"license": "MIT", "license": "MIT",
"homepage": "https://git.f3l.de/ghost/risk-dice", "homepage": "https://git.f3l.de/ghost/risk-dice-modifier",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.f3l.de/ghost/risk-dice" "url": "https://git.f3l.de/ghost/risk-dice-modifier"
}, },
"bugs": { "bugs": {
"url": "https://git.f3l.de/ghost/risk-dice/-/issues" "url": "https://git.f3l.de/ghost/risk-dice-modifier/-/issues"
}, },
"contributors": [ "contributors": [
{ {

BIN
risk-dice-modifier.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -1,3 +0,0 @@
{
"RiskDice.ErrorNumberMustBeAtLeast3": "Die Anzahl an Würfeln muss mindestens 3 sein."
}

View file

@ -1,3 +0,0 @@
{
"RiskDice.ErrorNumberMustBeAtLeast3": "The number of dice must be at least 3."
}

View file

@ -1,26 +1,14 @@
{ {
"name": "risk-dice", "name": "risk-dice-modifier",
"title": "Risk Dice", "title": "Risk Dice Modifier",
"description": "An implementation of Risk Dice as found for example in the Splittermond game system", "description": "An implementation of risk rolls as found for example in the Splittermond game system",
"author": "Johannes Loher", "author": "Johannes Loher",
"version": "0.0.1", "version": "0.0.1",
"minimumCoreVersion": "0.7.9", "minimumCoreVersion": "0.7.9",
"compatibleCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9",
"esmodules": ["module/risk-dice.js"], "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", "url": "https://git.f3l.de/ghost/risk-dice",
"manifest": "https://git.f3l.de/ghost/risk-dice/-/raw/latest/src/system.json?inline=false", "manifest": "https://git.f3l.de/ghost/risk-dice-modifier/-/raw/latest/src/system.json?inline=false",
"download": "https://git.f3l.de/ghost/risk-dice/-/jobs/artifacts/0.0.1/download?job=build", "download": "https://git.f3l.de/ghost/risk-dice-modifier/-/jobs/artifacts/0.0.1/download?job=build",
"license": "MIT" "license": "MIT"
} }

View file

@ -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();
});

View file

@ -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();
});

View file

@ -1,51 +0,0 @@
export class RiskDie extends DiceTerm {
constructor({ modifiers, ...other }: Partial<DiceTerm.TermData>) {
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';
}

52
src/module/risk.ts Normal file
View file

@ -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;
});
}