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
|
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
|
||||||
|
|
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.
|
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
|
||||||
|
|
||||||
|
|
10
package.json
10
package.json
|
@ -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
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",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
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