Use a dice modifier instead of a custom DiceTerm
This commit is contained in:
parent
bea124c3b8
commit
150942215e
12 changed files with 87 additions and 106 deletions
|
@ -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
|
||||
|
|
26
README.md
26
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
|
||||
|
||||
|
|
10
package.json
10
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": [
|
||||
{
|
||||
|
|
BIN
risk-dice-modifier.png
Normal file
BIN
risk-dice-modifier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
risk-dice.png
BIN
risk-dice.png
Binary file not shown.
Before Width: | Height: | Size: 8.3 KiB |
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"RiskDice.ErrorNumberMustBeAtLeast3": "Die Anzahl an Würfeln muss mindestens 3 sein."
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"RiskDice.ErrorNumberMustBeAtLeast3": "The number of dice must be at least 3."
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
12
src/module/risk-dice-modifier.ts
Normal file
12
src/module/risk-dice-modifier.ts
Normal 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();
|
||||
});
|
|
@ -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();
|
||||
});
|
|
@ -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
52
src/module/risk.ts
Normal 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;
|
||||
});
|
||||
}
|
Reference in a new issue