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
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

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.
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

View file

@ -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": [
{

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",
"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"
}

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