@swrpg-online/dice 1.1.0 → 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 +31 -42
- package/dist/dice.d.ts +2 -2
- package/dist/dice.js +20 -6
- package/dist/hints.d.ts +11 -0
- package/dist/hints.js +246 -0
- package/dist/types.d.ts +15 -0
- 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) {
|
|
@@ -16,25 +15,6 @@ function parseDiceNotation(input) {
|
|
|
16
15
|
challengeDice: 0,
|
|
17
16
|
forceDice: 0,
|
|
18
17
|
};
|
|
19
|
-
// function getImagePath(type: string): string {
|
|
20
|
-
// const basePath = path.join(__dirname, 'images');
|
|
21
|
-
// switch (type) {
|
|
22
|
-
// case 'successes':
|
|
23
|
-
// return path.join(basePath, 'success.svg'); // Adjust path and extension as needed
|
|
24
|
-
// case 'failures':
|
|
25
|
-
// return path.join(basePath, 'failure.svg');
|
|
26
|
-
// case 'advantages':
|
|
27
|
-
// return path.join(basePath, 'advantage.svg');
|
|
28
|
-
// case 'threats':
|
|
29
|
-
// return path.join(basePath, 'threat.svg');
|
|
30
|
-
// case 'triumphs':
|
|
31
|
-
// return path.join(basePath, 'triumph.svg');
|
|
32
|
-
// case 'despair':
|
|
33
|
-
// return path.join(basePath, 'despair.svg');
|
|
34
|
-
// default:
|
|
35
|
-
// return '';
|
|
36
|
-
// }
|
|
37
|
-
// }
|
|
38
18
|
const parts = input.toLowerCase().trim().split(" ");
|
|
39
19
|
for (const part of parts) {
|
|
40
20
|
const count = parseInt(part);
|
|
@@ -99,30 +79,38 @@ function parseDiceNotation(input) {
|
|
|
99
79
|
}
|
|
100
80
|
return pool;
|
|
101
81
|
}
|
|
102
|
-
|
|
103
|
-
const
|
|
82
|
+
const formatResult = (result) => {
|
|
83
|
+
const effects = [];
|
|
104
84
|
if (result.summary.successes > 0)
|
|
105
|
-
|
|
85
|
+
effects.push(`${result.summary.successes} Success(es)`);
|
|
106
86
|
if (result.summary.failures > 0)
|
|
107
|
-
|
|
87
|
+
effects.push(`${result.summary.failures} Failure(s)`);
|
|
108
88
|
if (result.summary.advantages > 0)
|
|
109
|
-
|
|
89
|
+
effects.push(`${result.summary.advantages} Advantage(s)`);
|
|
110
90
|
if (result.summary.threats > 0)
|
|
111
|
-
|
|
91
|
+
effects.push(`${result.summary.threats} Threat(s)`);
|
|
112
92
|
if (result.summary.triumphs > 0)
|
|
113
|
-
|
|
93
|
+
effects.push(`${result.summary.triumphs} Triumph(s)`);
|
|
114
94
|
if (result.summary.despair > 0)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return
|
|
121
|
-
}
|
|
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;
|
|
122
103
|
const main = () => {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
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:
|
|
126
114
|
- y/pro = Yellow / Proficiency
|
|
127
115
|
- g/a = Green / Ability
|
|
128
116
|
- b/boo = Blue / Boost
|
|
@@ -130,12 +118,13 @@ const main = () => {
|
|
|
130
118
|
- p/diff = Purple / Difficulty
|
|
131
119
|
- blk/k/sb/s = Black / Setback
|
|
132
120
|
- w/f = White/Force
|
|
133
|
-
|
|
121
|
+
Options:
|
|
122
|
+
--hints Show possible actions based on roll results`);
|
|
134
123
|
process.exit(1);
|
|
135
124
|
}
|
|
136
|
-
const pool = parseDiceNotation(
|
|
137
|
-
const result = (0, dice_1.roll)(pool);
|
|
138
|
-
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));
|
|
139
128
|
};
|
|
140
129
|
exports.main = main;
|
|
141
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) {
|
|
@@ -483,7 +484,7 @@ const forceDieResult = (roll) => {
|
|
|
483
484
|
};
|
|
484
485
|
}
|
|
485
486
|
};
|
|
486
|
-
const sumResults = (results) => {
|
|
487
|
+
const sumResults = (results, options) => {
|
|
487
488
|
const sums = results.reduce((acc, curr) => ({
|
|
488
489
|
successes: acc.successes + curr.successes,
|
|
489
490
|
failures: acc.failures + curr.failures,
|
|
@@ -503,7 +504,6 @@ const sumResults = (results) => {
|
|
|
503
504
|
lightSide: 0,
|
|
504
505
|
darkSide: 0,
|
|
505
506
|
});
|
|
506
|
-
// Calculate net successes/failures
|
|
507
507
|
let netSuccesses = 0;
|
|
508
508
|
let netFailures = 0;
|
|
509
509
|
if (sums.successes === sums.failures) {
|
|
@@ -516,7 +516,7 @@ const sumResults = (results) => {
|
|
|
516
516
|
else {
|
|
517
517
|
netFailures = sums.failures - sums.successes;
|
|
518
518
|
}
|
|
519
|
-
|
|
519
|
+
const result = {
|
|
520
520
|
successes: netSuccesses,
|
|
521
521
|
failures: netFailures,
|
|
522
522
|
advantages: sums.advantages,
|
|
@@ -526,10 +526,10 @@ const sumResults = (results) => {
|
|
|
526
526
|
lightSide: sums.lightSide,
|
|
527
527
|
darkSide: sums.darkSide,
|
|
528
528
|
};
|
|
529
|
+
return result;
|
|
529
530
|
};
|
|
530
|
-
const roll = (pool) => {
|
|
531
|
+
const roll = (pool, options) => {
|
|
531
532
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
532
|
-
// Initialize all dice counts to 0 if undefined
|
|
533
533
|
const boostCount = (_a = pool.boostDice) !== null && _a !== void 0 ? _a : 0;
|
|
534
534
|
const abilityCount = (_b = pool.abilityDice) !== null && _b !== void 0 ? _b : 0;
|
|
535
535
|
const proficiencyCount = (_c = pool.proficiencyDice) !== null && _c !== void 0 ? _c : 0;
|
|
@@ -611,9 +611,23 @@ const roll = (pool) => {
|
|
|
611
611
|
result: forceDieResult(roll),
|
|
612
612
|
});
|
|
613
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
|
+
}
|
|
614
628
|
return {
|
|
615
629
|
results: detailedResults,
|
|
616
|
-
summary:
|
|
630
|
+
summary: summary,
|
|
617
631
|
};
|
|
618
632
|
};
|
|
619
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
|
@@ -16,6 +16,7 @@ export type DiceResult = {
|
|
|
16
16
|
despair: number;
|
|
17
17
|
lightSide: number;
|
|
18
18
|
darkSide: number;
|
|
19
|
+
hints?: string[];
|
|
19
20
|
};
|
|
20
21
|
export type DieType = "boost" | "ability" | "proficiency" | "setback" | "difficulty" | "challenge" | "force";
|
|
21
22
|
export type DetailedDieResult = {
|
|
@@ -27,3 +28,17 @@ export type RollResult = {
|
|
|
27
28
|
results: DetailedDieResult[];
|
|
28
29
|
summary: DiceResult;
|
|
29
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
|
+
};
|