@swrpg-online/dice 1.0.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -62
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +47 -47
- package/dist/dice.d.ts +2 -2
- package/dist/dice.js +173 -7
- package/dist/hints.d.ts +11 -0
- package/dist/hints.js +246 -0
- package/dist/types.d.ts +19 -1
- package/dist/types.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,25 +7,71 @@
|
|
|
7
7
|
|
|
8
8
|
A TypeScript library that creates dice rolls using the [narrative dice system](https://star-wars-rpg-ffg.fandom.com/wiki/Narrative_Dice) for the Star Wars Role-Playing Game by [Fantasy Flight Games](https://www.fantasyflightgames.com/en/starwarsrpg/) and [Edge Studio](https://www.edge-studio.net/categories-games/starwarsrpg/).
|
|
9
9
|
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- Complete narrative dice system implementation
|
|
13
|
+
- Detailed roll breakdown for each die
|
|
14
|
+
- Action hints to suggest possible uses for advantages, triumphs, etc.
|
|
15
|
+
- Roll results include:
|
|
16
|
+
- Successes / Failures
|
|
17
|
+
- Advantages / Threats
|
|
18
|
+
- Triumphs / Despairs
|
|
19
|
+
- Light / Dark Side Points (Force dice)
|
|
20
|
+
- Comprehensive Test Coverage
|
|
21
|
+
- The safety of TypeScript
|
|
22
|
+
- CLI Support
|
|
23
|
+
|
|
10
24
|
## Installation
|
|
11
25
|
|
|
26
|
+
### As a CLI Tool
|
|
27
|
+
|
|
28
|
+
To use the dice roller from the command line:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm i -g @swrpg-online/dice
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### As a project dependency
|
|
35
|
+
|
|
12
36
|
```bash
|
|
13
37
|
npm i @swrpg-online/dice
|
|
14
38
|
```
|
|
15
39
|
|
|
16
|
-
|
|
40
|
+
## CLI Usage
|
|
17
41
|
|
|
18
|
-
|
|
42
|
+
```
|
|
43
|
+
swrpg-dice <dice-notation> [options]
|
|
44
|
+
```
|
|
19
45
|
|
|
20
|
-
|
|
21
|
-
- Detailed roll breakdown for each die
|
|
22
|
-
- Comprehensive test coverage
|
|
23
|
-
- TypeScript type safety
|
|
24
|
-
- roll from a CLI
|
|
46
|
+
Example:
|
|
25
47
|
|
|
26
|
-
|
|
48
|
+
```
|
|
49
|
+
swrpg-dice 2y 1g 1p 1b 1sb --hints
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Output:
|
|
27
53
|
|
|
28
|
-
|
|
54
|
+
```
|
|
55
|
+
1 Success(es), 4 Advantage(s), 1 Threat(s)
|
|
56
|
+
|
|
57
|
+
Possible actions:
|
|
58
|
+
• 1 Advantage or 1 Triumph - Recover one strain (may be applied more than once).
|
|
59
|
+
• 1 Advantage or 1 Triumph - Add a boost die to the next allied active character's check.
|
|
60
|
+
• 1 Advantage or 1 Triumph - Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or
|
|
61
|
+
...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Dice Options:
|
|
65
|
+
|
|
66
|
+
- y/pro = Yellow / Proficiency
|
|
67
|
+
- g/a = Green / Ability
|
|
68
|
+
- b/boo = Blue / Boost
|
|
69
|
+
- r/c = Red / Challenge
|
|
70
|
+
- p/diff = Purple / Difficulty
|
|
71
|
+
- blk/k/sb/s = Black / Setback
|
|
72
|
+
- w/f = White / Force
|
|
73
|
+
|
|
74
|
+
## Programmatic Usage
|
|
29
75
|
|
|
30
76
|
```typescript
|
|
31
77
|
import { roll, DicePool } from '@swrpg-online/dice';
|
|
@@ -39,9 +85,8 @@ const pool: DicePool = {
|
|
|
39
85
|
|
|
40
86
|
const result = roll(pool);
|
|
41
87
|
|
|
42
|
-
|
|
43
|
-
console.log(result.
|
|
44
|
-
console.log(result.summary); // Summary of total successes, advantages, etc.
|
|
88
|
+
console.log(result.results);
|
|
89
|
+
console.log(result.summary);
|
|
45
90
|
|
|
46
91
|
=> {
|
|
47
92
|
"results": [
|
|
@@ -57,18 +102,6 @@ console.log(result.summary); // Summary of total successes, advantages, etc.
|
|
|
57
102
|
"despair": 0
|
|
58
103
|
}
|
|
59
104
|
},
|
|
60
|
-
{
|
|
61
|
-
"type": "ability",
|
|
62
|
-
"roll": 3,
|
|
63
|
-
"result": {
|
|
64
|
-
"successes": 1,
|
|
65
|
-
"failures": 0,
|
|
66
|
-
"advantages": 0,
|
|
67
|
-
"threats": 0,
|
|
68
|
-
"triumphs": 0,
|
|
69
|
-
"despair": 0
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
105
|
{
|
|
73
106
|
"type": "proficiency",
|
|
74
107
|
"roll": 10,
|
|
@@ -81,30 +114,7 @@ console.log(result.summary); // Summary of total successes, advantages, etc.
|
|
|
81
114
|
"despair": 0
|
|
82
115
|
}
|
|
83
116
|
},
|
|
84
|
-
|
|
85
|
-
"type": "difficulty",
|
|
86
|
-
"roll": 2,
|
|
87
|
-
"result": {
|
|
88
|
-
"successes": 0,
|
|
89
|
-
"failures": 1,
|
|
90
|
-
"advantages": 0,
|
|
91
|
-
"threats": 0,
|
|
92
|
-
"triumphs": 0,
|
|
93
|
-
"despair": 0
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"type": "challenge",
|
|
98
|
-
"roll": 11,
|
|
99
|
-
"result": {
|
|
100
|
-
"successes": 0,
|
|
101
|
-
"failures": 0,
|
|
102
|
-
"advantages": 0,
|
|
103
|
-
"threats": 2,
|
|
104
|
-
"triumphs": 0,
|
|
105
|
-
"despair": 0
|
|
106
|
-
}
|
|
107
|
-
}
|
|
117
|
+
...
|
|
108
118
|
],
|
|
109
119
|
"summary": {
|
|
110
120
|
"successes": 0,
|
|
@@ -117,21 +127,9 @@ console.log(result.summary); // Summary of total successes, advantages, etc.
|
|
|
117
127
|
}
|
|
118
128
|
```
|
|
119
129
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- Detailed breakdown of each die roll
|
|
123
|
-
- Die type identification
|
|
124
|
-
- Individual results per die
|
|
125
|
-
- Overall summary of the roll
|
|
126
|
-
|
|
127
|
-
# Roadmap or Under Review
|
|
130
|
+
# License
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
- implement ability to add success, failure, and so on to dice pools
|
|
131
|
-
- ship combat?
|
|
132
|
-
- crits?
|
|
133
|
-
- polyhedral dice for convenience?
|
|
134
|
-
- anything else?
|
|
132
|
+
This project is licensed under the MIT License.
|
|
135
133
|
|
|
136
134
|
# Contribution
|
|
137
135
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DicePool } from "./types";
|
|
2
|
+
import { DicePool, RollResult } from "./types";
|
|
3
3
|
export declare function parseDiceNotation(input: string): DicePool;
|
|
4
|
-
export declare
|
|
4
|
+
export declare const formatResult: (result: RollResult) => string;
|
|
5
5
|
export declare const main: () => void;
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.main = void 0;
|
|
4
|
+
exports.main = exports.formatResult = void 0;
|
|
5
5
|
exports.parseDiceNotation = parseDiceNotation;
|
|
6
|
-
exports.formatResult = formatResult;
|
|
7
6
|
const dice_1 = require("./dice");
|
|
8
7
|
// import * as path from 'path';
|
|
9
8
|
function parseDiceNotation(input) {
|
|
@@ -14,67 +13,49 @@ function parseDiceNotation(input) {
|
|
|
14
13
|
setBackDice: 0,
|
|
15
14
|
difficultyDice: 0,
|
|
16
15
|
challengeDice: 0,
|
|
16
|
+
forceDice: 0,
|
|
17
17
|
};
|
|
18
|
-
// function getImagePath(type: string): string {
|
|
19
|
-
// const basePath = path.join(__dirname, 'images');
|
|
20
|
-
// switch (type) {
|
|
21
|
-
// case 'successes':
|
|
22
|
-
// return path.join(basePath, 'success.svg'); // Adjust path and extension as needed
|
|
23
|
-
// case 'failures':
|
|
24
|
-
// return path.join(basePath, 'failure.svg');
|
|
25
|
-
// case 'advantages':
|
|
26
|
-
// return path.join(basePath, 'advantage.svg');
|
|
27
|
-
// case 'threats':
|
|
28
|
-
// return path.join(basePath, 'threat.svg');
|
|
29
|
-
// case 'triumphs':
|
|
30
|
-
// return path.join(basePath, 'triumph.svg');
|
|
31
|
-
// case 'despair':
|
|
32
|
-
// return path.join(basePath, 'despair.svg');
|
|
33
|
-
// default:
|
|
34
|
-
// return '';
|
|
35
|
-
// }
|
|
36
|
-
// }
|
|
37
18
|
const parts = input.toLowerCase().trim().split(" ");
|
|
38
19
|
for (const part of parts) {
|
|
39
20
|
const count = parseInt(part);
|
|
40
|
-
const color = part.slice(String(count).length);
|
|
21
|
+
const color = part.slice(String(count).length).toLowerCase();
|
|
41
22
|
switch (color) {
|
|
42
|
-
// y/pro = Yellow/Proficiency
|
|
23
|
+
// y/pro = Yellow / Proficiency
|
|
43
24
|
case "y":
|
|
44
25
|
pool.proficiencyDice = count;
|
|
45
26
|
break;
|
|
46
27
|
case "pro":
|
|
47
28
|
pool.proficiencyDice = count;
|
|
48
29
|
break;
|
|
49
|
-
// g/a = Green/Ability
|
|
30
|
+
// g/a = Green / Ability
|
|
50
31
|
case "g":
|
|
51
32
|
pool.abilityDice = count;
|
|
52
33
|
break;
|
|
53
34
|
case "a":
|
|
54
35
|
pool.abilityDice = count;
|
|
55
36
|
break;
|
|
56
|
-
// b/boo = Blue/Boost
|
|
37
|
+
// b/boo = Blue / Boost
|
|
57
38
|
case "b":
|
|
58
39
|
pool.boostDice = count;
|
|
59
40
|
break;
|
|
60
41
|
case "boo":
|
|
61
42
|
pool.boostDice = count;
|
|
62
43
|
break;
|
|
63
|
-
// r/c = Red/ Challenge
|
|
44
|
+
// r/c = Red / Challenge
|
|
64
45
|
case "r":
|
|
65
46
|
pool.challengeDice = count;
|
|
66
47
|
break;
|
|
67
48
|
case "c":
|
|
68
49
|
pool.challengeDice = count;
|
|
69
50
|
break;
|
|
70
|
-
// p/diff = Purple/ Difficulty
|
|
51
|
+
// p/diff = Purple / Difficulty
|
|
71
52
|
case "p":
|
|
72
53
|
pool.difficultyDice = count;
|
|
73
54
|
break;
|
|
74
55
|
case "diff":
|
|
75
56
|
pool.difficultyDice = count;
|
|
76
57
|
break;
|
|
77
|
-
// blk/k/sb/s = Black/Setback
|
|
58
|
+
// blk/k/sb/s = Black / Setback
|
|
78
59
|
case "blk":
|
|
79
60
|
pool.setBackDice = count;
|
|
80
61
|
break;
|
|
@@ -87,44 +68,63 @@ function parseDiceNotation(input) {
|
|
|
87
68
|
case "s":
|
|
88
69
|
pool.setBackDice = count;
|
|
89
70
|
break;
|
|
90
|
-
// w/f = White/Force
|
|
91
|
-
|
|
71
|
+
// w/f = White / Force
|
|
72
|
+
case "w":
|
|
73
|
+
pool.forceDice = count;
|
|
74
|
+
break;
|
|
75
|
+
case "f":
|
|
76
|
+
pool.forceDice = count;
|
|
77
|
+
break;
|
|
92
78
|
}
|
|
93
79
|
}
|
|
94
80
|
return pool;
|
|
95
81
|
}
|
|
96
|
-
|
|
97
|
-
const
|
|
82
|
+
const formatResult = (result) => {
|
|
83
|
+
const effects = [];
|
|
98
84
|
if (result.summary.successes > 0)
|
|
99
|
-
|
|
85
|
+
effects.push(`${result.summary.successes} Success(es)`);
|
|
100
86
|
if (result.summary.failures > 0)
|
|
101
|
-
|
|
87
|
+
effects.push(`${result.summary.failures} Failure(s)`);
|
|
102
88
|
if (result.summary.advantages > 0)
|
|
103
|
-
|
|
89
|
+
effects.push(`${result.summary.advantages} Advantage(s)`);
|
|
104
90
|
if (result.summary.threats > 0)
|
|
105
|
-
|
|
91
|
+
effects.push(`${result.summary.threats} Threat(s)`);
|
|
106
92
|
if (result.summary.triumphs > 0)
|
|
107
|
-
|
|
93
|
+
effects.push(`${result.summary.triumphs} Triumph(s)`);
|
|
108
94
|
if (result.summary.despair > 0)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
95
|
+
effects.push(`${result.summary.despair} Despair(s)`);
|
|
96
|
+
const resultText = effects.length > 0 ? effects.join(", ") : "No effects";
|
|
97
|
+
if (result.summary.hints && result.summary.hints.length > 0) {
|
|
98
|
+
return `${resultText}\n\nPossible actions:\n${result.summary.hints.map((hint) => " • " + hint).join("\n")}`;
|
|
99
|
+
}
|
|
100
|
+
return resultText;
|
|
101
|
+
};
|
|
102
|
+
exports.formatResult = formatResult;
|
|
112
103
|
const main = () => {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
const args = process.argv.slice(2);
|
|
105
|
+
const hintsIndex = args.indexOf("--hints");
|
|
106
|
+
const showHints = hintsIndex !== -1;
|
|
107
|
+
const diceNotation = hintsIndex !== -1
|
|
108
|
+
? args.filter((_, index) => index !== hintsIndex).join(" ")
|
|
109
|
+
: args.join(" ");
|
|
110
|
+
if (!diceNotation.trim()) {
|
|
111
|
+
console.log(`Usage: swrpg-dice <dice-notation> <dice-options>
|
|
112
|
+
Example: swrpg-dice 2y 1g 1p 1b 1sb --hints
|
|
113
|
+
Dice Options:
|
|
116
114
|
- y/pro = Yellow / Proficiency
|
|
117
115
|
- g/a = Green / Ability
|
|
118
116
|
- b/boo = Blue / Boost
|
|
119
117
|
- r/c = Red / Challenge
|
|
120
118
|
- p/diff = Purple / Difficulty
|
|
121
119
|
- blk/k/sb/s = Black / Setback
|
|
122
|
-
|
|
120
|
+
- w/f = White/Force
|
|
121
|
+
Options:
|
|
122
|
+
--hints Show possible actions based on roll results`);
|
|
123
123
|
process.exit(1);
|
|
124
124
|
}
|
|
125
|
-
const pool = parseDiceNotation(
|
|
126
|
-
const result = (0, dice_1.roll)(pool);
|
|
127
|
-
console.log(formatResult(result));
|
|
125
|
+
const pool = parseDiceNotation(diceNotation);
|
|
126
|
+
const result = (0, dice_1.roll)(pool, { hints: showHints });
|
|
127
|
+
console.log((0, exports.formatResult)(result));
|
|
128
128
|
};
|
|
129
129
|
exports.main = main;
|
|
130
130
|
if (require.main === module) {
|
package/dist/dice.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { DicePool, RollResult } from "./types";
|
|
2
|
-
export declare const roll: (pool: DicePool) => RollResult;
|
|
1
|
+
import { DicePool, RollResult, RollOptions } from "./types";
|
|
2
|
+
export declare const roll: (pool: DicePool, options?: RollOptions) => RollResult;
|
package/dist/dice.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.roll = void 0;
|
|
4
|
+
const hints_1 = require("./hints");
|
|
4
5
|
const rollDie = (sides) => Math.floor(Math.random() * sides) + 1;
|
|
5
6
|
const boostDieResult = (roll) => {
|
|
6
7
|
switch (roll) {
|
|
@@ -12,6 +13,8 @@ const boostDieResult = (roll) => {
|
|
|
12
13
|
threats: 0,
|
|
13
14
|
triumphs: 0,
|
|
14
15
|
despair: 0,
|
|
16
|
+
lightSide: 0,
|
|
17
|
+
darkSide: 0,
|
|
15
18
|
};
|
|
16
19
|
case 4:
|
|
17
20
|
return {
|
|
@@ -21,6 +24,8 @@ const boostDieResult = (roll) => {
|
|
|
21
24
|
threats: 0,
|
|
22
25
|
triumphs: 0,
|
|
23
26
|
despair: 0,
|
|
27
|
+
lightSide: 0,
|
|
28
|
+
darkSide: 0,
|
|
24
29
|
};
|
|
25
30
|
case 5:
|
|
26
31
|
return {
|
|
@@ -30,6 +35,8 @@ const boostDieResult = (roll) => {
|
|
|
30
35
|
threats: 0,
|
|
31
36
|
triumphs: 0,
|
|
32
37
|
despair: 0,
|
|
38
|
+
lightSide: 0,
|
|
39
|
+
darkSide: 0,
|
|
33
40
|
};
|
|
34
41
|
case 6:
|
|
35
42
|
return {
|
|
@@ -39,6 +46,8 @@ const boostDieResult = (roll) => {
|
|
|
39
46
|
threats: 0,
|
|
40
47
|
triumphs: 0,
|
|
41
48
|
despair: 0,
|
|
49
|
+
lightSide: 0,
|
|
50
|
+
darkSide: 0,
|
|
42
51
|
};
|
|
43
52
|
default:
|
|
44
53
|
return {
|
|
@@ -48,6 +57,8 @@ const boostDieResult = (roll) => {
|
|
|
48
57
|
threats: 0,
|
|
49
58
|
triumphs: 0,
|
|
50
59
|
despair: 0,
|
|
60
|
+
lightSide: 0,
|
|
61
|
+
darkSide: 0,
|
|
51
62
|
};
|
|
52
63
|
}
|
|
53
64
|
};
|
|
@@ -62,6 +73,8 @@ const setBackDieResult = (roll) => {
|
|
|
62
73
|
threats: 0,
|
|
63
74
|
triumphs: 0,
|
|
64
75
|
despair: 0,
|
|
76
|
+
lightSide: 0,
|
|
77
|
+
darkSide: 0,
|
|
65
78
|
};
|
|
66
79
|
case 5:
|
|
67
80
|
case 6:
|
|
@@ -72,6 +85,8 @@ const setBackDieResult = (roll) => {
|
|
|
72
85
|
threats: 1,
|
|
73
86
|
triumphs: 0,
|
|
74
87
|
despair: 0,
|
|
88
|
+
lightSide: 0,
|
|
89
|
+
darkSide: 0,
|
|
75
90
|
};
|
|
76
91
|
default:
|
|
77
92
|
return {
|
|
@@ -81,6 +96,8 @@ const setBackDieResult = (roll) => {
|
|
|
81
96
|
threats: 0,
|
|
82
97
|
triumphs: 0,
|
|
83
98
|
despair: 0,
|
|
99
|
+
lightSide: 0,
|
|
100
|
+
darkSide: 0,
|
|
84
101
|
};
|
|
85
102
|
}
|
|
86
103
|
};
|
|
@@ -95,6 +112,8 @@ const abilityDieResult = (roll) => {
|
|
|
95
112
|
threats: 0,
|
|
96
113
|
triumphs: 0,
|
|
97
114
|
despair: 0,
|
|
115
|
+
lightSide: 0,
|
|
116
|
+
darkSide: 0,
|
|
98
117
|
};
|
|
99
118
|
case 4:
|
|
100
119
|
return {
|
|
@@ -104,6 +123,8 @@ const abilityDieResult = (roll) => {
|
|
|
104
123
|
threats: 0,
|
|
105
124
|
triumphs: 0,
|
|
106
125
|
despair: 0,
|
|
126
|
+
lightSide: 0,
|
|
127
|
+
darkSide: 0,
|
|
107
128
|
};
|
|
108
129
|
case 5:
|
|
109
130
|
case 6:
|
|
@@ -114,6 +135,8 @@ const abilityDieResult = (roll) => {
|
|
|
114
135
|
threats: 0,
|
|
115
136
|
triumphs: 0,
|
|
116
137
|
despair: 0,
|
|
138
|
+
lightSide: 0,
|
|
139
|
+
darkSide: 0,
|
|
117
140
|
};
|
|
118
141
|
case 7:
|
|
119
142
|
return {
|
|
@@ -123,6 +146,8 @@ const abilityDieResult = (roll) => {
|
|
|
123
146
|
threats: 0,
|
|
124
147
|
triumphs: 0,
|
|
125
148
|
despair: 0,
|
|
149
|
+
lightSide: 0,
|
|
150
|
+
darkSide: 0,
|
|
126
151
|
};
|
|
127
152
|
case 8:
|
|
128
153
|
return {
|
|
@@ -132,6 +157,8 @@ const abilityDieResult = (roll) => {
|
|
|
132
157
|
threats: 0,
|
|
133
158
|
triumphs: 0,
|
|
134
159
|
despair: 0,
|
|
160
|
+
lightSide: 0,
|
|
161
|
+
darkSide: 0,
|
|
135
162
|
};
|
|
136
163
|
default:
|
|
137
164
|
return {
|
|
@@ -141,6 +168,8 @@ const abilityDieResult = (roll) => {
|
|
|
141
168
|
threats: 0,
|
|
142
169
|
triumphs: 0,
|
|
143
170
|
despair: 0,
|
|
171
|
+
lightSide: 0,
|
|
172
|
+
darkSide: 0,
|
|
144
173
|
};
|
|
145
174
|
}
|
|
146
175
|
};
|
|
@@ -154,6 +183,8 @@ const difficultyDieResult = (roll) => {
|
|
|
154
183
|
threats: 0,
|
|
155
184
|
triumphs: 0,
|
|
156
185
|
despair: 0,
|
|
186
|
+
lightSide: 0,
|
|
187
|
+
darkSide: 0,
|
|
157
188
|
};
|
|
158
189
|
case 3:
|
|
159
190
|
return {
|
|
@@ -163,6 +194,8 @@ const difficultyDieResult = (roll) => {
|
|
|
163
194
|
threats: 0,
|
|
164
195
|
triumphs: 0,
|
|
165
196
|
despair: 0,
|
|
197
|
+
lightSide: 0,
|
|
198
|
+
darkSide: 0,
|
|
166
199
|
};
|
|
167
200
|
case 4:
|
|
168
201
|
case 5:
|
|
@@ -174,6 +207,8 @@ const difficultyDieResult = (roll) => {
|
|
|
174
207
|
threats: 1,
|
|
175
208
|
triumphs: 0,
|
|
176
209
|
despair: 0,
|
|
210
|
+
lightSide: 0,
|
|
211
|
+
darkSide: 0,
|
|
177
212
|
};
|
|
178
213
|
case 7:
|
|
179
214
|
return {
|
|
@@ -183,6 +218,8 @@ const difficultyDieResult = (roll) => {
|
|
|
183
218
|
threats: 2,
|
|
184
219
|
triumphs: 0,
|
|
185
220
|
despair: 0,
|
|
221
|
+
lightSide: 0,
|
|
222
|
+
darkSide: 0,
|
|
186
223
|
};
|
|
187
224
|
case 8:
|
|
188
225
|
return {
|
|
@@ -192,6 +229,8 @@ const difficultyDieResult = (roll) => {
|
|
|
192
229
|
threats: 1,
|
|
193
230
|
triumphs: 0,
|
|
194
231
|
despair: 0,
|
|
232
|
+
lightSide: 0,
|
|
233
|
+
darkSide: 0,
|
|
195
234
|
};
|
|
196
235
|
default:
|
|
197
236
|
return {
|
|
@@ -201,6 +240,8 @@ const difficultyDieResult = (roll) => {
|
|
|
201
240
|
threats: 0,
|
|
202
241
|
triumphs: 0,
|
|
203
242
|
despair: 0,
|
|
243
|
+
lightSide: 0,
|
|
244
|
+
darkSide: 0,
|
|
204
245
|
};
|
|
205
246
|
}
|
|
206
247
|
};
|
|
@@ -215,6 +256,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
215
256
|
threats: 0,
|
|
216
257
|
triumphs: 0,
|
|
217
258
|
despair: 0,
|
|
259
|
+
lightSide: 0,
|
|
260
|
+
darkSide: 0,
|
|
218
261
|
};
|
|
219
262
|
case 4:
|
|
220
263
|
case 5:
|
|
@@ -225,6 +268,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
225
268
|
threats: 0,
|
|
226
269
|
triumphs: 0,
|
|
227
270
|
despair: 0,
|
|
271
|
+
lightSide: 0,
|
|
272
|
+
darkSide: 0,
|
|
228
273
|
};
|
|
229
274
|
case 6:
|
|
230
275
|
return {
|
|
@@ -234,6 +279,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
234
279
|
threats: 0,
|
|
235
280
|
triumphs: 0,
|
|
236
281
|
despair: 0,
|
|
282
|
+
lightSide: 0,
|
|
283
|
+
darkSide: 0,
|
|
237
284
|
};
|
|
238
285
|
case 7:
|
|
239
286
|
case 8:
|
|
@@ -245,6 +292,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
245
292
|
threats: 0,
|
|
246
293
|
triumphs: 0,
|
|
247
294
|
despair: 0,
|
|
295
|
+
lightSide: 0,
|
|
296
|
+
darkSide: 0,
|
|
248
297
|
};
|
|
249
298
|
case 10:
|
|
250
299
|
case 11:
|
|
@@ -255,6 +304,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
255
304
|
threats: 0,
|
|
256
305
|
triumphs: 0,
|
|
257
306
|
despair: 0,
|
|
307
|
+
lightSide: 0,
|
|
308
|
+
darkSide: 0,
|
|
258
309
|
};
|
|
259
310
|
case 12:
|
|
260
311
|
return {
|
|
@@ -264,6 +315,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
264
315
|
threats: 0,
|
|
265
316
|
triumphs: 1,
|
|
266
317
|
despair: 0,
|
|
318
|
+
lightSide: 0,
|
|
319
|
+
darkSide: 0,
|
|
267
320
|
};
|
|
268
321
|
default:
|
|
269
322
|
return {
|
|
@@ -273,6 +326,8 @@ const proficiencyDieResult = (roll) => {
|
|
|
273
326
|
threats: 0,
|
|
274
327
|
triumphs: 0,
|
|
275
328
|
despair: 0,
|
|
329
|
+
lightSide: 0,
|
|
330
|
+
darkSide: 0,
|
|
276
331
|
};
|
|
277
332
|
}
|
|
278
333
|
};
|
|
@@ -287,6 +342,8 @@ const challengeDieResult = (roll) => {
|
|
|
287
342
|
threats: 0,
|
|
288
343
|
triumphs: 0,
|
|
289
344
|
despair: 0,
|
|
345
|
+
lightSide: 0,
|
|
346
|
+
darkSide: 0,
|
|
290
347
|
};
|
|
291
348
|
case 4:
|
|
292
349
|
case 5:
|
|
@@ -297,6 +354,8 @@ const challengeDieResult = (roll) => {
|
|
|
297
354
|
threats: 0,
|
|
298
355
|
triumphs: 0,
|
|
299
356
|
despair: 0,
|
|
357
|
+
lightSide: 0,
|
|
358
|
+
darkSide: 0,
|
|
300
359
|
};
|
|
301
360
|
case 6:
|
|
302
361
|
case 7:
|
|
@@ -307,6 +366,8 @@ const challengeDieResult = (roll) => {
|
|
|
307
366
|
threats: 1,
|
|
308
367
|
triumphs: 0,
|
|
309
368
|
despair: 0,
|
|
369
|
+
lightSide: 0,
|
|
370
|
+
darkSide: 0,
|
|
310
371
|
};
|
|
311
372
|
case 8:
|
|
312
373
|
case 9:
|
|
@@ -317,6 +378,8 @@ const challengeDieResult = (roll) => {
|
|
|
317
378
|
threats: 1,
|
|
318
379
|
triumphs: 0,
|
|
319
380
|
despair: 0,
|
|
381
|
+
lightSide: 0,
|
|
382
|
+
darkSide: 0,
|
|
320
383
|
};
|
|
321
384
|
case 10:
|
|
322
385
|
case 11:
|
|
@@ -327,6 +390,8 @@ const challengeDieResult = (roll) => {
|
|
|
327
390
|
threats: 2,
|
|
328
391
|
triumphs: 0,
|
|
329
392
|
despair: 0,
|
|
393
|
+
lightSide: 0,
|
|
394
|
+
darkSide: 0,
|
|
330
395
|
};
|
|
331
396
|
case 12:
|
|
332
397
|
return {
|
|
@@ -336,6 +401,8 @@ const challengeDieResult = (roll) => {
|
|
|
336
401
|
threats: 0,
|
|
337
402
|
triumphs: 0,
|
|
338
403
|
despair: 1,
|
|
404
|
+
lightSide: 0,
|
|
405
|
+
darkSide: 0,
|
|
339
406
|
};
|
|
340
407
|
default:
|
|
341
408
|
return {
|
|
@@ -345,10 +412,79 @@ const challengeDieResult = (roll) => {
|
|
|
345
412
|
threats: 0,
|
|
346
413
|
triumphs: 0,
|
|
347
414
|
despair: 0,
|
|
415
|
+
lightSide: 0,
|
|
416
|
+
darkSide: 0,
|
|
348
417
|
};
|
|
349
418
|
}
|
|
350
419
|
};
|
|
351
|
-
const
|
|
420
|
+
const forceDieResult = (roll) => {
|
|
421
|
+
switch (roll) {
|
|
422
|
+
case 1:
|
|
423
|
+
case 2:
|
|
424
|
+
case 3:
|
|
425
|
+
case 4:
|
|
426
|
+
case 5:
|
|
427
|
+
return {
|
|
428
|
+
successes: 0,
|
|
429
|
+
failures: 0,
|
|
430
|
+
advantages: 0,
|
|
431
|
+
threats: 0,
|
|
432
|
+
triumphs: 0,
|
|
433
|
+
despair: 0,
|
|
434
|
+
lightSide: 1,
|
|
435
|
+
darkSide: 0,
|
|
436
|
+
};
|
|
437
|
+
case 6:
|
|
438
|
+
case 7:
|
|
439
|
+
return {
|
|
440
|
+
successes: 0,
|
|
441
|
+
failures: 0,
|
|
442
|
+
advantages: 0,
|
|
443
|
+
threats: 0,
|
|
444
|
+
triumphs: 0,
|
|
445
|
+
despair: 0,
|
|
446
|
+
lightSide: 2,
|
|
447
|
+
darkSide: 0,
|
|
448
|
+
};
|
|
449
|
+
case 8:
|
|
450
|
+
case 9:
|
|
451
|
+
case 10:
|
|
452
|
+
case 11:
|
|
453
|
+
return {
|
|
454
|
+
successes: 0,
|
|
455
|
+
failures: 0,
|
|
456
|
+
advantages: 0,
|
|
457
|
+
threats: 0,
|
|
458
|
+
triumphs: 0,
|
|
459
|
+
despair: 0,
|
|
460
|
+
lightSide: 0,
|
|
461
|
+
darkSide: 1,
|
|
462
|
+
};
|
|
463
|
+
case 12:
|
|
464
|
+
return {
|
|
465
|
+
successes: 0,
|
|
466
|
+
failures: 0,
|
|
467
|
+
advantages: 0,
|
|
468
|
+
threats: 0,
|
|
469
|
+
triumphs: 0,
|
|
470
|
+
despair: 0,
|
|
471
|
+
lightSide: 0,
|
|
472
|
+
darkSide: 2,
|
|
473
|
+
};
|
|
474
|
+
default:
|
|
475
|
+
return {
|
|
476
|
+
successes: 0,
|
|
477
|
+
failures: 0,
|
|
478
|
+
advantages: 0,
|
|
479
|
+
threats: 0,
|
|
480
|
+
triumphs: 0,
|
|
481
|
+
despair: 0,
|
|
482
|
+
lightSide: 0,
|
|
483
|
+
darkSide: 0,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
const sumResults = (results, options) => {
|
|
352
488
|
const sums = results.reduce((acc, curr) => ({
|
|
353
489
|
successes: acc.successes + curr.successes,
|
|
354
490
|
failures: acc.failures + curr.failures,
|
|
@@ -356,6 +492,8 @@ const sumResults = (results) => {
|
|
|
356
492
|
threats: acc.threats + curr.threats,
|
|
357
493
|
triumphs: acc.triumphs + curr.triumphs,
|
|
358
494
|
despair: acc.despair + curr.despair,
|
|
495
|
+
lightSide: acc.lightSide + (curr.lightSide || 0),
|
|
496
|
+
darkSide: acc.darkSide + (curr.darkSide || 0),
|
|
359
497
|
}), {
|
|
360
498
|
successes: 0,
|
|
361
499
|
failures: 0,
|
|
@@ -363,8 +501,9 @@ const sumResults = (results) => {
|
|
|
363
501
|
threats: 0,
|
|
364
502
|
triumphs: 0,
|
|
365
503
|
despair: 0,
|
|
504
|
+
lightSide: 0,
|
|
505
|
+
darkSide: 0,
|
|
366
506
|
});
|
|
367
|
-
// Calculate net successes/failures
|
|
368
507
|
let netSuccesses = 0;
|
|
369
508
|
let netFailures = 0;
|
|
370
509
|
if (sums.successes === sums.failures) {
|
|
@@ -377,24 +516,27 @@ const sumResults = (results) => {
|
|
|
377
516
|
else {
|
|
378
517
|
netFailures = sums.failures - sums.successes;
|
|
379
518
|
}
|
|
380
|
-
|
|
519
|
+
const result = {
|
|
381
520
|
successes: netSuccesses,
|
|
382
521
|
failures: netFailures,
|
|
383
522
|
advantages: sums.advantages,
|
|
384
523
|
threats: sums.threats,
|
|
385
524
|
triumphs: sums.triumphs,
|
|
386
525
|
despair: sums.despair,
|
|
526
|
+
lightSide: sums.lightSide,
|
|
527
|
+
darkSide: sums.darkSide,
|
|
387
528
|
};
|
|
529
|
+
return result;
|
|
388
530
|
};
|
|
389
|
-
const roll = (pool) => {
|
|
390
|
-
var _a, _b, _c, _d, _e, _f;
|
|
391
|
-
// Initialize all dice counts to 0 if undefined
|
|
531
|
+
const roll = (pool, options) => {
|
|
532
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
392
533
|
const boostCount = (_a = pool.boostDice) !== null && _a !== void 0 ? _a : 0;
|
|
393
534
|
const abilityCount = (_b = pool.abilityDice) !== null && _b !== void 0 ? _b : 0;
|
|
394
535
|
const proficiencyCount = (_c = pool.proficiencyDice) !== null && _c !== void 0 ? _c : 0;
|
|
395
536
|
const setBackCount = (_d = pool.setBackDice) !== null && _d !== void 0 ? _d : 0;
|
|
396
537
|
const difficultyCount = (_e = pool.difficultyDice) !== null && _e !== void 0 ? _e : 0;
|
|
397
538
|
const challengeCount = (_f = pool.challengeDice) !== null && _f !== void 0 ? _f : 0;
|
|
539
|
+
const forceCount = (_g = pool.forceDice) !== null && _g !== void 0 ? _g : 0;
|
|
398
540
|
// Ensure all dice counts are non-negative
|
|
399
541
|
const sanitizedPool = {
|
|
400
542
|
boostDice: Math.max(0, boostCount),
|
|
@@ -403,6 +545,7 @@ const roll = (pool) => {
|
|
|
403
545
|
setBackDice: Math.max(0, setBackCount),
|
|
404
546
|
difficultyDice: Math.max(0, difficultyCount),
|
|
405
547
|
challengeDice: Math.max(0, challengeCount),
|
|
548
|
+
forceDice: Math.max(0, forceCount),
|
|
406
549
|
};
|
|
407
550
|
const detailedResults = [];
|
|
408
551
|
// Roll boost dice
|
|
@@ -459,9 +602,32 @@ const roll = (pool) => {
|
|
|
459
602
|
result: challengeDieResult(roll),
|
|
460
603
|
});
|
|
461
604
|
}
|
|
605
|
+
// Roll force dice
|
|
606
|
+
for (let i = 0; i < sanitizedPool.forceDice; i++) {
|
|
607
|
+
const roll = rollDie(12);
|
|
608
|
+
detailedResults.push({
|
|
609
|
+
type: "force",
|
|
610
|
+
roll,
|
|
611
|
+
result: forceDieResult(roll),
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
const summary = sumResults(detailedResults.map((r) => r.result));
|
|
615
|
+
if (options === null || options === void 0 ? void 0 : options.hints) {
|
|
616
|
+
const applicableHints = hints_1.hints.filter((hint) => {
|
|
617
|
+
const { cost } = hint;
|
|
618
|
+
return Object.entries(cost).some(([symbol, required]) => {
|
|
619
|
+
const summaryKey = (symbol.toLowerCase() + "s");
|
|
620
|
+
const value = summary[summaryKey];
|
|
621
|
+
if (typeof value !== "number")
|
|
622
|
+
return false;
|
|
623
|
+
return required <= value;
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
summary.hints = applicableHints.map((hint) => `${(0, hints_1.hintCostDisplayText)(hint)} - ${hint.description}`);
|
|
627
|
+
}
|
|
462
628
|
return {
|
|
463
629
|
results: detailedResults,
|
|
464
|
-
summary:
|
|
630
|
+
summary: summary,
|
|
465
631
|
};
|
|
466
632
|
};
|
|
467
633
|
exports.roll = roll;
|
package/dist/hints.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Symbol } from "./types";
|
|
2
|
+
export type CostType = {
|
|
3
|
+
[key in Symbol]?: number;
|
|
4
|
+
};
|
|
5
|
+
type Hint = {
|
|
6
|
+
description: string;
|
|
7
|
+
cost: CostType;
|
|
8
|
+
};
|
|
9
|
+
export declare const hints: Hint[];
|
|
10
|
+
export declare function hintCostDisplayText(hint: Hint): string;
|
|
11
|
+
export {};
|
package/dist/hints.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hints = void 0;
|
|
4
|
+
exports.hintCostDisplayText = hintCostDisplayText;
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
// 1 advantage or 1 triumph
|
|
7
|
+
const recoverOneStrain = "Recover one strain (may be applied more than once).";
|
|
8
|
+
const addBoostDieToActiveAlly = "Add a boost die to the next allied active character's check.";
|
|
9
|
+
const noticeImportantPoint = "Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.";
|
|
10
|
+
const inflictCriticalInjury = "Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).";
|
|
11
|
+
const activateWeaponQuality = "Activate a weapon quality (Advantage cost may vary).";
|
|
12
|
+
// 2 advantage or 1 triumph
|
|
13
|
+
const performManeuver = "Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.";
|
|
14
|
+
const addSetbackDie = "Add a setback die to the targeted character's next check.";
|
|
15
|
+
const addBoostDieToAnyAlly = "Add a boost die to any allied character's next check, including that of the active character.";
|
|
16
|
+
// 3 advantage or 1 triumph
|
|
17
|
+
const negateEnemy = "Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.";
|
|
18
|
+
const ignoreEnvironment = "Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.";
|
|
19
|
+
const disableOpponent = "When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.";
|
|
20
|
+
const gainDefense = "Gain + 1 melee or ranged defense until the end of the active character's next turn.";
|
|
21
|
+
const dropWeapon = "Force the target to drop a melee or ranged weapon they are wielding.";
|
|
22
|
+
// 1 triumph
|
|
23
|
+
const upgradeDifficultyTargetedCharacter = "Upgrade the difficulty of the targeted character's next check.";
|
|
24
|
+
const doSomethingVital = "Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.";
|
|
25
|
+
const upgradeAnyAllyCheck = "Upgrade any allied character's next check, including that of the current active character.";
|
|
26
|
+
// 2 triumph
|
|
27
|
+
const destroyEquipment = "When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.";
|
|
28
|
+
// 1 threat or 1 despair
|
|
29
|
+
const sufferStrain = "The active character suffers 1 strain.";
|
|
30
|
+
const loseManeuverBenefit = "The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.";
|
|
31
|
+
// 2 threat or 1 despair
|
|
32
|
+
const freeManeuver = "An opponent may immediately perform one free maneuver in response to the active character's check.";
|
|
33
|
+
const addBoostDieToTargetedCharacter = "Add a boost die to the targeted character's next check.";
|
|
34
|
+
const sufferSetback = "The active character or an allied character suffers a setback die on their next action.";
|
|
35
|
+
// 3 threat or 1 despair
|
|
36
|
+
const fallProne = "The active character falls prone.";
|
|
37
|
+
const gainSignificantAdvantage = "The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.";
|
|
38
|
+
// 1 despair
|
|
39
|
+
const outOfAmmo = "The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.";
|
|
40
|
+
const upgradeDifficultyAlliedCharacter = "Upgrade the difficulty of an allied character's next check, including that of the current active character.";
|
|
41
|
+
const damagedItem = "The tool or melee weapon the character is using becomes damaged.";
|
|
42
|
+
exports.hints = [
|
|
43
|
+
// 1 advantage or 1 triumph
|
|
44
|
+
{
|
|
45
|
+
description: recoverOneStrain,
|
|
46
|
+
cost: {
|
|
47
|
+
[types_1.SYMBOLS.ADVANTAGE]: 1,
|
|
48
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
description: addBoostDieToActiveAlly,
|
|
53
|
+
cost: {
|
|
54
|
+
[types_1.SYMBOLS.ADVANTAGE]: 1,
|
|
55
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
description: noticeImportantPoint,
|
|
60
|
+
cost: {
|
|
61
|
+
[types_1.SYMBOLS.ADVANTAGE]: 1,
|
|
62
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
description: inflictCriticalInjury,
|
|
67
|
+
cost: {
|
|
68
|
+
[types_1.SYMBOLS.ADVANTAGE]: 1,
|
|
69
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
description: activateWeaponQuality,
|
|
74
|
+
cost: {
|
|
75
|
+
[types_1.SYMBOLS.ADVANTAGE]: 1,
|
|
76
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
// 2 advantage or 1 triumph
|
|
80
|
+
{
|
|
81
|
+
description: performManeuver,
|
|
82
|
+
cost: {
|
|
83
|
+
[types_1.SYMBOLS.ADVANTAGE]: 2,
|
|
84
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
description: addSetbackDie,
|
|
89
|
+
cost: {
|
|
90
|
+
[types_1.SYMBOLS.ADVANTAGE]: 2,
|
|
91
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
description: addBoostDieToAnyAlly,
|
|
96
|
+
cost: {
|
|
97
|
+
[types_1.SYMBOLS.ADVANTAGE]: 2,
|
|
98
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
// 3 advantage or 1 triumph
|
|
102
|
+
{
|
|
103
|
+
description: negateEnemy,
|
|
104
|
+
cost: {
|
|
105
|
+
[types_1.SYMBOLS.ADVANTAGE]: 3,
|
|
106
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
description: ignoreEnvironment,
|
|
111
|
+
cost: {
|
|
112
|
+
[types_1.SYMBOLS.ADVANTAGE]: 3,
|
|
113
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
description: disableOpponent,
|
|
118
|
+
cost: {
|
|
119
|
+
[types_1.SYMBOLS.ADVANTAGE]: 3,
|
|
120
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
description: gainDefense,
|
|
125
|
+
cost: {
|
|
126
|
+
[types_1.SYMBOLS.ADVANTAGE]: 3,
|
|
127
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
description: dropWeapon,
|
|
132
|
+
cost: {
|
|
133
|
+
[types_1.SYMBOLS.ADVANTAGE]: 3,
|
|
134
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
// 1 triumph
|
|
138
|
+
{
|
|
139
|
+
description: upgradeDifficultyTargetedCharacter,
|
|
140
|
+
cost: {
|
|
141
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
description: doSomethingVital,
|
|
146
|
+
cost: {
|
|
147
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
description: upgradeAnyAllyCheck,
|
|
152
|
+
cost: {
|
|
153
|
+
[types_1.SYMBOLS.TRIUMPH]: 1,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
// 2 triumph
|
|
157
|
+
{
|
|
158
|
+
description: destroyEquipment,
|
|
159
|
+
cost: {
|
|
160
|
+
[types_1.SYMBOLS.TRIUMPH]: 2,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
// 1 threat or 1 despair
|
|
164
|
+
{
|
|
165
|
+
description: sufferStrain,
|
|
166
|
+
cost: {
|
|
167
|
+
[types_1.SYMBOLS.THREAT]: 1,
|
|
168
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
description: loseManeuverBenefit,
|
|
173
|
+
cost: {
|
|
174
|
+
[types_1.SYMBOLS.THREAT]: 1,
|
|
175
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
// 2 threat or 1 despair
|
|
179
|
+
{
|
|
180
|
+
description: freeManeuver,
|
|
181
|
+
cost: {
|
|
182
|
+
[types_1.SYMBOLS.THREAT]: 2,
|
|
183
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
description: addBoostDieToTargetedCharacter,
|
|
188
|
+
cost: {
|
|
189
|
+
[types_1.SYMBOLS.THREAT]: 1,
|
|
190
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
description: sufferSetback,
|
|
195
|
+
cost: {
|
|
196
|
+
[types_1.SYMBOLS.THREAT]: 2,
|
|
197
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
// 3 threat or 1 despair
|
|
201
|
+
{
|
|
202
|
+
description: fallProne,
|
|
203
|
+
cost: {
|
|
204
|
+
[types_1.SYMBOLS.THREAT]: 3,
|
|
205
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
description: gainSignificantAdvantage,
|
|
210
|
+
cost: {
|
|
211
|
+
[types_1.SYMBOLS.THREAT]: 3,
|
|
212
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
// 1 despair
|
|
216
|
+
{
|
|
217
|
+
description: outOfAmmo,
|
|
218
|
+
cost: {
|
|
219
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
description: upgradeDifficultyAlliedCharacter,
|
|
224
|
+
cost: {
|
|
225
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
description: damagedItem,
|
|
230
|
+
cost: {
|
|
231
|
+
[types_1.SYMBOLS.DESPAIR]: 1,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
function hintCostDisplayText(hint) {
|
|
236
|
+
if (!hint.cost || Object.keys(hint.cost).length === 0) {
|
|
237
|
+
return "No cost";
|
|
238
|
+
}
|
|
239
|
+
const parts = Object.entries(hint.cost)
|
|
240
|
+
.filter(([_, count]) => count && count > 0)
|
|
241
|
+
.map(([symbol, count]) => {
|
|
242
|
+
const symbolName = symbol.charAt(0) + symbol.toLowerCase().slice(1);
|
|
243
|
+
return `${count} ${symbolName}${count > 1 ? "(s)" : ""}`;
|
|
244
|
+
});
|
|
245
|
+
return parts.length > 0 ? parts.join(" or ") : "No cost";
|
|
246
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type DicePool = {
|
|
|
5
5
|
setBackDice?: number;
|
|
6
6
|
difficultyDice?: number;
|
|
7
7
|
challengeDice?: number;
|
|
8
|
+
forceDice?: number;
|
|
8
9
|
};
|
|
9
10
|
export type DiceResult = {
|
|
10
11
|
successes: number;
|
|
@@ -13,8 +14,11 @@ export type DiceResult = {
|
|
|
13
14
|
threats: number;
|
|
14
15
|
triumphs: number;
|
|
15
16
|
despair: number;
|
|
17
|
+
lightSide: number;
|
|
18
|
+
darkSide: number;
|
|
19
|
+
hints?: string[];
|
|
16
20
|
};
|
|
17
|
-
export type DieType = "boost" | "ability" | "proficiency" | "setback" | "difficulty" | "challenge";
|
|
21
|
+
export type DieType = "boost" | "ability" | "proficiency" | "setback" | "difficulty" | "challenge" | "force";
|
|
18
22
|
export type DetailedDieResult = {
|
|
19
23
|
type: DieType;
|
|
20
24
|
roll: number;
|
|
@@ -24,3 +28,17 @@ export type RollResult = {
|
|
|
24
28
|
results: DetailedDieResult[];
|
|
25
29
|
summary: DiceResult;
|
|
26
30
|
};
|
|
31
|
+
export declare const SYMBOLS: {
|
|
32
|
+
readonly SUCCESS: "SUCCESS";
|
|
33
|
+
readonly FAILURE: "FAILURE";
|
|
34
|
+
readonly ADVANTAGE: "ADVANTAGE";
|
|
35
|
+
readonly THREAT: "THREAT";
|
|
36
|
+
readonly TRIUMPH: "TRIUMPH";
|
|
37
|
+
readonly DESPAIR: "DESPAIR";
|
|
38
|
+
readonly LIGHT: "LIGHT";
|
|
39
|
+
readonly DARK: "DARK";
|
|
40
|
+
};
|
|
41
|
+
export type Symbol = keyof typeof SYMBOLS;
|
|
42
|
+
export type RollOptions = {
|
|
43
|
+
hints?: boolean;
|
|
44
|
+
};
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SYMBOLS = void 0;
|
|
4
|
+
exports.SYMBOLS = {
|
|
5
|
+
SUCCESS: "SUCCESS",
|
|
6
|
+
FAILURE: "FAILURE",
|
|
7
|
+
ADVANTAGE: "ADVANTAGE",
|
|
8
|
+
THREAT: "THREAT",
|
|
9
|
+
TRIUMPH: "TRIUMPH",
|
|
10
|
+
DESPAIR: "DESPAIR",
|
|
11
|
+
LIGHT: "LIGHT",
|
|
12
|
+
DARK: "DARK",
|
|
13
|
+
};
|