@swrpg-online/dice 0.5.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/LICENSE +21 -0
- package/README.md +43 -0
- package/coverage/clover.xml +113 -0
- package/coverage/coverage-final.json +4 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/dice.ts.html +817 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/index.ts.html +109 -0
- package/coverage/lcov-report/pools.ts.html +253 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov.info +246 -0
- package/dist/dice.d.ts +2 -0
- package/dist/dice.js +229 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10 -0
- package/dist/pools.d.ts +32 -0
- package/dist/pools.js +53 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.js +2 -0
- package/jest.config.js +7 -0
- package/package.json +27 -0
- package/src/dice.js +229 -0
- package/src/dice.ts +244 -0
- package/src/index.ts +8 -0
- package/src/pools.ts +56 -0
- package/src/types.js +2 -0
- package/src/types.ts +30 -0
- package/tests/dice.test.ts +351 -0
- package/tests/pools.test.ts +86 -0
- package/tsconfig.json +14 -0
package/dist/pools.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DicePool } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a basic skill check dice pool
|
|
4
|
+
* @param ability Number of ability (green) dice
|
|
5
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
6
|
+
* @returns DicePool configured for a basic skill check
|
|
7
|
+
*/
|
|
8
|
+
export declare const createSkillCheck: (ability: number, proficiency: number) => DicePool;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a combat check dice pool with optional boost die
|
|
11
|
+
* @param ability Number of ability (green) dice
|
|
12
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
13
|
+
* @param boost Number of boost (blue) dice
|
|
14
|
+
* @returns DicePool configured for a combat check
|
|
15
|
+
*/
|
|
16
|
+
export declare const createCombatCheck: (ability: number, proficiency: number, boost?: number) => DicePool;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an opposed check dice pool
|
|
19
|
+
* @param ability Number of ability (green) dice
|
|
20
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
21
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
22
|
+
* @param challenge Number of challenge (red) dice
|
|
23
|
+
* @returns DicePool configured for an opposed check
|
|
24
|
+
*/
|
|
25
|
+
export declare const createOpposedCheck: (ability: number, proficiency: number, difficulty: number, challenge?: number) => DicePool;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a difficulty check dice pool
|
|
28
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
29
|
+
* @param challenge Number of challenge (red) dice
|
|
30
|
+
* @returns DicePool configured for a pure difficulty check
|
|
31
|
+
*/
|
|
32
|
+
export declare const createDifficultyPool: (difficulty: number, challenge?: number) => DicePool;
|
package/dist/pools.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDifficultyPool = exports.createOpposedCheck = exports.createCombatCheck = exports.createSkillCheck = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a basic skill check dice pool
|
|
6
|
+
* @param ability Number of ability (green) dice
|
|
7
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
8
|
+
* @returns DicePool configured for a basic skill check
|
|
9
|
+
*/
|
|
10
|
+
const createSkillCheck = (ability, proficiency) => ({
|
|
11
|
+
abilityDice: Math.max(0, ability),
|
|
12
|
+
proficiencyDice: Math.max(0, proficiency)
|
|
13
|
+
});
|
|
14
|
+
exports.createSkillCheck = createSkillCheck;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a combat check dice pool with optional boost die
|
|
17
|
+
* @param ability Number of ability (green) dice
|
|
18
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
19
|
+
* @param boost Number of boost (blue) dice
|
|
20
|
+
* @returns DicePool configured for a combat check
|
|
21
|
+
*/
|
|
22
|
+
const createCombatCheck = (ability, proficiency, boost = 0) => ({
|
|
23
|
+
abilityDice: Math.max(0, ability),
|
|
24
|
+
proficiencyDice: Math.max(0, proficiency),
|
|
25
|
+
boostDice: Math.max(0, boost)
|
|
26
|
+
});
|
|
27
|
+
exports.createCombatCheck = createCombatCheck;
|
|
28
|
+
/**
|
|
29
|
+
* Creates an opposed check dice pool
|
|
30
|
+
* @param ability Number of ability (green) dice
|
|
31
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
32
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
33
|
+
* @param challenge Number of challenge (red) dice
|
|
34
|
+
* @returns DicePool configured for an opposed check
|
|
35
|
+
*/
|
|
36
|
+
const createOpposedCheck = (ability, proficiency, difficulty, challenge = 0) => ({
|
|
37
|
+
abilityDice: Math.max(0, ability),
|
|
38
|
+
proficiencyDice: Math.max(0, proficiency),
|
|
39
|
+
difficultyDice: Math.max(0, difficulty),
|
|
40
|
+
challengeDice: Math.max(0, challenge)
|
|
41
|
+
});
|
|
42
|
+
exports.createOpposedCheck = createOpposedCheck;
|
|
43
|
+
/**
|
|
44
|
+
* Creates a difficulty check dice pool
|
|
45
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
46
|
+
* @param challenge Number of challenge (red) dice
|
|
47
|
+
* @returns DicePool configured for a pure difficulty check
|
|
48
|
+
*/
|
|
49
|
+
const createDifficultyPool = (difficulty, challenge = 0) => ({
|
|
50
|
+
difficultyDice: Math.max(0, difficulty),
|
|
51
|
+
challengeDice: Math.max(0, challenge)
|
|
52
|
+
});
|
|
53
|
+
exports.createDifficultyPool = createDifficultyPool;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type DicePool = {
|
|
2
|
+
boostDice?: number;
|
|
3
|
+
abilityDice?: number;
|
|
4
|
+
proficiencyDice?: number;
|
|
5
|
+
setBackDice?: number;
|
|
6
|
+
difficultyDice?: number;
|
|
7
|
+
challengeDice?: number;
|
|
8
|
+
};
|
|
9
|
+
export type DiceResult = {
|
|
10
|
+
successes: number;
|
|
11
|
+
failures: number;
|
|
12
|
+
advantages: number;
|
|
13
|
+
threats: number;
|
|
14
|
+
triumphs: number;
|
|
15
|
+
despair: number;
|
|
16
|
+
};
|
|
17
|
+
export type DieType = 'boost' | 'ability' | 'proficiency' | 'setback' | 'difficulty' | 'challenge';
|
|
18
|
+
export type DetailedDieResult = {
|
|
19
|
+
type: DieType;
|
|
20
|
+
roll: number;
|
|
21
|
+
result: DiceResult;
|
|
22
|
+
};
|
|
23
|
+
export type RollResult = {
|
|
24
|
+
results: DetailedDieResult[];
|
|
25
|
+
summary: DiceResult;
|
|
26
|
+
};
|
package/dist/types.js
ADDED
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@swrpg-online/dice",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "A TypeScript library for simulating Star Wars RPG narrative dice rolls.",
|
|
5
|
+
"main": "jest.config.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"test": "tests"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "npx jest --verbose"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "Chris Pan",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@types/jest": "^29.5.14",
|
|
17
|
+
"@types/node": "^22.10.0",
|
|
18
|
+
"jest": "^29.7.0",
|
|
19
|
+
"ts-jest": "^29.2.5",
|
|
20
|
+
"typescript": "^5.7.2"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/swrpg-online/dice"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/dice.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.roll = void 0;
|
|
4
|
+
var rollDie = function (sides) { return Math.floor(Math.random() * sides) + 1; };
|
|
5
|
+
var boostDieResult = function (roll) {
|
|
6
|
+
switch (roll) {
|
|
7
|
+
case 3:
|
|
8
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
9
|
+
case 4:
|
|
10
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
11
|
+
case 5:
|
|
12
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
13
|
+
case 6:
|
|
14
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
15
|
+
default:
|
|
16
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var setBackDieResult = function (roll) {
|
|
20
|
+
switch (roll) {
|
|
21
|
+
case 3:
|
|
22
|
+
case 4:
|
|
23
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
24
|
+
case 5:
|
|
25
|
+
case 6:
|
|
26
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
27
|
+
default:
|
|
28
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var abilityDieResult = function (roll) {
|
|
32
|
+
switch (roll) {
|
|
33
|
+
case 2:
|
|
34
|
+
case 3:
|
|
35
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
36
|
+
case 4:
|
|
37
|
+
return { successes: 2, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
38
|
+
case 5:
|
|
39
|
+
case 6:
|
|
40
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
41
|
+
case 7:
|
|
42
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
43
|
+
case 8:
|
|
44
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
45
|
+
default:
|
|
46
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var difficultyDieResult = function (roll) {
|
|
50
|
+
switch (roll) {
|
|
51
|
+
case 2:
|
|
52
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
53
|
+
case 3:
|
|
54
|
+
return { successes: 0, failures: 2, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
55
|
+
case 4:
|
|
56
|
+
case 5:
|
|
57
|
+
case 6:
|
|
58
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
59
|
+
case 7:
|
|
60
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 2, triumphs: 0, despair: 0 };
|
|
61
|
+
case 8:
|
|
62
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
63
|
+
default:
|
|
64
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var proficiencyDieResult = function (roll) {
|
|
68
|
+
switch (roll) {
|
|
69
|
+
case 2:
|
|
70
|
+
case 3:
|
|
71
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
72
|
+
case 4:
|
|
73
|
+
case 5:
|
|
74
|
+
return { successes: 2, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
75
|
+
case 6:
|
|
76
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
77
|
+
case 7:
|
|
78
|
+
case 8:
|
|
79
|
+
case 9:
|
|
80
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
81
|
+
case 10:
|
|
82
|
+
case 11:
|
|
83
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
84
|
+
case 12:
|
|
85
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 1, despair: 0 };
|
|
86
|
+
default:
|
|
87
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var challengeDieResult = function (roll) {
|
|
91
|
+
switch (roll) {
|
|
92
|
+
case 2:
|
|
93
|
+
case 3:
|
|
94
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
95
|
+
case 4:
|
|
96
|
+
case 5:
|
|
97
|
+
return { successes: 0, failures: 2, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
98
|
+
case 6:
|
|
99
|
+
case 7:
|
|
100
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
101
|
+
case 8:
|
|
102
|
+
case 9:
|
|
103
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
104
|
+
case 10:
|
|
105
|
+
case 11:
|
|
106
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 2, triumphs: 0, despair: 0 };
|
|
107
|
+
case 12:
|
|
108
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 1 };
|
|
109
|
+
default:
|
|
110
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var sumResults = function (results) {
|
|
114
|
+
var sums = results.reduce(function (acc, curr) { return ({
|
|
115
|
+
successes: acc.successes + curr.successes,
|
|
116
|
+
failures: acc.failures + curr.failures,
|
|
117
|
+
advantages: acc.advantages + curr.advantages,
|
|
118
|
+
threats: acc.threats + curr.threats,
|
|
119
|
+
triumphs: acc.triumphs + curr.triumphs,
|
|
120
|
+
despair: acc.despair + curr.despair
|
|
121
|
+
}); }, {
|
|
122
|
+
successes: 0,
|
|
123
|
+
failures: 0,
|
|
124
|
+
advantages: 0,
|
|
125
|
+
threats: 0,
|
|
126
|
+
triumphs: 0,
|
|
127
|
+
despair: 0
|
|
128
|
+
});
|
|
129
|
+
// Calculate net successes/failures
|
|
130
|
+
var netSuccesses = 0;
|
|
131
|
+
var netFailures = 0;
|
|
132
|
+
if (sums.successes === sums.failures) {
|
|
133
|
+
netSuccesses = 0;
|
|
134
|
+
netFailures = 0;
|
|
135
|
+
}
|
|
136
|
+
else if (sums.successes > sums.failures) {
|
|
137
|
+
netSuccesses = sums.successes - sums.failures;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
netFailures = sums.failures - sums.successes;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
successes: netSuccesses,
|
|
144
|
+
failures: netFailures,
|
|
145
|
+
advantages: sums.advantages,
|
|
146
|
+
threats: sums.threats,
|
|
147
|
+
triumphs: sums.triumphs,
|
|
148
|
+
despair: sums.despair
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
var roll = function (pool) {
|
|
152
|
+
var _a, _b, _c, _d, _e, _f;
|
|
153
|
+
// Initialize all dice counts to 0 if undefined
|
|
154
|
+
var boostCount = (_a = pool.boostDice) !== null && _a !== void 0 ? _a : 0;
|
|
155
|
+
var abilityCount = (_b = pool.abilityDice) !== null && _b !== void 0 ? _b : 0;
|
|
156
|
+
var proficiencyCount = (_c = pool.proficiencyDice) !== null && _c !== void 0 ? _c : 0;
|
|
157
|
+
var setBackCount = (_d = pool.setBackDice) !== null && _d !== void 0 ? _d : 0;
|
|
158
|
+
var difficultyCount = (_e = pool.difficultyDice) !== null && _e !== void 0 ? _e : 0;
|
|
159
|
+
var challengeCount = (_f = pool.challengeDice) !== null && _f !== void 0 ? _f : 0;
|
|
160
|
+
// Ensure all dice counts are non-negative
|
|
161
|
+
var sanitizedPool = {
|
|
162
|
+
boostDice: Math.max(0, boostCount),
|
|
163
|
+
abilityDice: Math.max(0, abilityCount),
|
|
164
|
+
proficiencyDice: Math.max(0, proficiencyCount),
|
|
165
|
+
setBackDice: Math.max(0, setBackCount),
|
|
166
|
+
difficultyDice: Math.max(0, difficultyCount),
|
|
167
|
+
challengeDice: Math.max(0, challengeCount)
|
|
168
|
+
};
|
|
169
|
+
var detailedResults = [];
|
|
170
|
+
// Roll boost dice
|
|
171
|
+
for (var i = 0; i < sanitizedPool.boostDice; i++) {
|
|
172
|
+
var roll_1 = rollDie(6);
|
|
173
|
+
detailedResults.push({
|
|
174
|
+
type: 'boost',
|
|
175
|
+
roll: roll_1,
|
|
176
|
+
result: boostDieResult(roll_1)
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Roll ability dice
|
|
180
|
+
for (var i = 0; i < sanitizedPool.abilityDice; i++) {
|
|
181
|
+
var roll_2 = rollDie(8);
|
|
182
|
+
detailedResults.push({
|
|
183
|
+
type: 'ability',
|
|
184
|
+
roll: roll_2,
|
|
185
|
+
result: abilityDieResult(roll_2)
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// Roll proficiency dice
|
|
189
|
+
for (var i = 0; i < sanitizedPool.proficiencyDice; i++) {
|
|
190
|
+
var roll_3 = rollDie(12);
|
|
191
|
+
detailedResults.push({
|
|
192
|
+
type: 'proficiency',
|
|
193
|
+
roll: roll_3,
|
|
194
|
+
result: proficiencyDieResult(roll_3)
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Roll setback dice
|
|
198
|
+
for (var i = 0; i < sanitizedPool.setBackDice; i++) {
|
|
199
|
+
var roll_4 = rollDie(6);
|
|
200
|
+
detailedResults.push({
|
|
201
|
+
type: 'setback',
|
|
202
|
+
roll: roll_4,
|
|
203
|
+
result: setBackDieResult(roll_4)
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
// Roll difficulty dice
|
|
207
|
+
for (var i = 0; i < sanitizedPool.difficultyDice; i++) {
|
|
208
|
+
var roll_5 = rollDie(8);
|
|
209
|
+
detailedResults.push({
|
|
210
|
+
type: 'difficulty',
|
|
211
|
+
roll: roll_5,
|
|
212
|
+
result: difficultyDieResult(roll_5)
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Roll challenge dice
|
|
216
|
+
for (var i = 0; i < sanitizedPool.challengeDice; i++) {
|
|
217
|
+
var roll_6 = rollDie(12);
|
|
218
|
+
detailedResults.push({
|
|
219
|
+
type: 'challenge',
|
|
220
|
+
roll: roll_6,
|
|
221
|
+
result: challengeDieResult(roll_6)
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
results: detailedResults,
|
|
226
|
+
summary: sumResults(detailedResults.map(function (r) { return r.result; }))
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
exports.roll = roll;
|
package/src/dice.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { DicePool, RollResult, DiceResult, DetailedDieResult } from './types';
|
|
2
|
+
|
|
3
|
+
const rollDie = (sides: number): number => Math.floor(Math.random() * sides) + 1;
|
|
4
|
+
|
|
5
|
+
const boostDieResult = (roll: number): DiceResult => {
|
|
6
|
+
switch (roll) {
|
|
7
|
+
case 3:
|
|
8
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
9
|
+
case 4:
|
|
10
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
11
|
+
case 5:
|
|
12
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
13
|
+
case 6:
|
|
14
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
15
|
+
default:
|
|
16
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const setBackDieResult = (roll: number): DiceResult => {
|
|
21
|
+
switch (roll) {
|
|
22
|
+
case 3:
|
|
23
|
+
case 4:
|
|
24
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
25
|
+
case 5:
|
|
26
|
+
case 6:
|
|
27
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
28
|
+
default:
|
|
29
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const abilityDieResult = (roll: number): DiceResult => {
|
|
34
|
+
switch (roll) {
|
|
35
|
+
case 2:
|
|
36
|
+
case 3:
|
|
37
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
38
|
+
case 4:
|
|
39
|
+
return { successes: 2, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
40
|
+
case 5:
|
|
41
|
+
case 6:
|
|
42
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
43
|
+
case 7:
|
|
44
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
45
|
+
case 8:
|
|
46
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
47
|
+
default:
|
|
48
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const difficultyDieResult = (roll: number): DiceResult => {
|
|
53
|
+
switch (roll) {
|
|
54
|
+
case 2:
|
|
55
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
56
|
+
case 3:
|
|
57
|
+
return { successes: 0, failures: 2, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
58
|
+
case 4:
|
|
59
|
+
case 5:
|
|
60
|
+
case 6:
|
|
61
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
62
|
+
case 7:
|
|
63
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 2, triumphs: 0, despair: 0 };
|
|
64
|
+
case 8:
|
|
65
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
66
|
+
default:
|
|
67
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const proficiencyDieResult = (roll: number): DiceResult => {
|
|
72
|
+
switch (roll) {
|
|
73
|
+
case 2:
|
|
74
|
+
case 3:
|
|
75
|
+
return { successes: 1, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
76
|
+
case 4:
|
|
77
|
+
case 5:
|
|
78
|
+
return { successes: 2, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
79
|
+
case 6:
|
|
80
|
+
return { successes: 0, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
81
|
+
case 7:
|
|
82
|
+
case 8:
|
|
83
|
+
case 9:
|
|
84
|
+
return { successes: 1, failures: 0, advantages: 1, threats: 0, triumphs: 0, despair: 0 };
|
|
85
|
+
case 10:
|
|
86
|
+
case 11:
|
|
87
|
+
return { successes: 0, failures: 0, advantages: 2, threats: 0, triumphs: 0, despair: 0 };
|
|
88
|
+
case 12:
|
|
89
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 1, despair: 0 };
|
|
90
|
+
default:
|
|
91
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const challengeDieResult = (roll: number): DiceResult => {
|
|
96
|
+
switch (roll) {
|
|
97
|
+
case 2:
|
|
98
|
+
case 3:
|
|
99
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
100
|
+
case 4:
|
|
101
|
+
case 5:
|
|
102
|
+
return { successes: 0, failures: 2, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
103
|
+
case 6:
|
|
104
|
+
case 7:
|
|
105
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
106
|
+
case 8:
|
|
107
|
+
case 9:
|
|
108
|
+
return { successes: 0, failures: 1, advantages: 0, threats: 1, triumphs: 0, despair: 0 };
|
|
109
|
+
case 10:
|
|
110
|
+
case 11:
|
|
111
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 2, triumphs: 0, despair: 0 };
|
|
112
|
+
case 12:
|
|
113
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 1 };
|
|
114
|
+
default:
|
|
115
|
+
return { successes: 0, failures: 0, advantages: 0, threats: 0, triumphs: 0, despair: 0 };
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const sumResults = (results: DiceResult[]): DiceResult => {
|
|
120
|
+
const sums = results.reduce((acc, curr) => ({
|
|
121
|
+
successes: acc.successes + curr.successes,
|
|
122
|
+
failures: acc.failures + curr.failures,
|
|
123
|
+
advantages: acc.advantages + curr.advantages,
|
|
124
|
+
threats: acc.threats + curr.threats,
|
|
125
|
+
triumphs: acc.triumphs + curr.triumphs,
|
|
126
|
+
despair: acc.despair + curr.despair
|
|
127
|
+
}), {
|
|
128
|
+
successes: 0,
|
|
129
|
+
failures: 0,
|
|
130
|
+
advantages: 0,
|
|
131
|
+
threats: 0,
|
|
132
|
+
triumphs: 0,
|
|
133
|
+
despair: 0
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Calculate net successes/failures
|
|
137
|
+
let netSuccesses = 0;
|
|
138
|
+
let netFailures = 0;
|
|
139
|
+
|
|
140
|
+
if (sums.successes === sums.failures) {
|
|
141
|
+
netSuccesses = 0;
|
|
142
|
+
netFailures = 0;
|
|
143
|
+
} else if (sums.successes > sums.failures) {
|
|
144
|
+
netSuccesses = sums.successes - sums.failures;
|
|
145
|
+
} else {
|
|
146
|
+
netFailures = sums.failures - sums.successes;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
successes: netSuccesses,
|
|
151
|
+
failures: netFailures,
|
|
152
|
+
advantages: sums.advantages,
|
|
153
|
+
threats: sums.threats,
|
|
154
|
+
triumphs: sums.triumphs,
|
|
155
|
+
despair: sums.despair
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const roll = (pool: DicePool): RollResult => {
|
|
160
|
+
// Initialize all dice counts to 0 if undefined
|
|
161
|
+
const boostCount = pool.boostDice ?? 0;
|
|
162
|
+
const abilityCount = pool.abilityDice ?? 0;
|
|
163
|
+
const proficiencyCount = pool.proficiencyDice ?? 0;
|
|
164
|
+
const setBackCount = pool.setBackDice ?? 0;
|
|
165
|
+
const difficultyCount = pool.difficultyDice ?? 0;
|
|
166
|
+
const challengeCount = pool.challengeDice ?? 0;
|
|
167
|
+
|
|
168
|
+
// Ensure all dice counts are non-negative
|
|
169
|
+
const sanitizedPool = {
|
|
170
|
+
boostDice: Math.max(0, boostCount),
|
|
171
|
+
abilityDice: Math.max(0, abilityCount),
|
|
172
|
+
proficiencyDice: Math.max(0, proficiencyCount),
|
|
173
|
+
setBackDice: Math.max(0, setBackCount),
|
|
174
|
+
difficultyDice: Math.max(0, difficultyCount),
|
|
175
|
+
challengeDice: Math.max(0, challengeCount)
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const detailedResults: DetailedDieResult[] = [];
|
|
179
|
+
|
|
180
|
+
// Roll boost dice
|
|
181
|
+
for (let i = 0; i < sanitizedPool.boostDice; i++) {
|
|
182
|
+
const roll = rollDie(6);
|
|
183
|
+
detailedResults.push({
|
|
184
|
+
type: 'boost',
|
|
185
|
+
roll,
|
|
186
|
+
result: boostDieResult(roll)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Roll ability dice
|
|
191
|
+
for (let i = 0; i < sanitizedPool.abilityDice; i++) {
|
|
192
|
+
const roll = rollDie(8);
|
|
193
|
+
detailedResults.push({
|
|
194
|
+
type: 'ability',
|
|
195
|
+
roll,
|
|
196
|
+
result: abilityDieResult(roll)
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Roll proficiency dice
|
|
201
|
+
for (let i = 0; i < sanitizedPool.proficiencyDice; i++) {
|
|
202
|
+
const roll = rollDie(12);
|
|
203
|
+
detailedResults.push({
|
|
204
|
+
type: 'proficiency',
|
|
205
|
+
roll,
|
|
206
|
+
result: proficiencyDieResult(roll)
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Roll setback dice
|
|
211
|
+
for (let i = 0; i < sanitizedPool.setBackDice; i++) {
|
|
212
|
+
const roll = rollDie(6);
|
|
213
|
+
detailedResults.push({
|
|
214
|
+
type: 'setback',
|
|
215
|
+
roll,
|
|
216
|
+
result: setBackDieResult(roll)
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Roll difficulty dice
|
|
221
|
+
for (let i = 0; i < sanitizedPool.difficultyDice; i++) {
|
|
222
|
+
const roll = rollDie(8);
|
|
223
|
+
detailedResults.push({
|
|
224
|
+
type: 'difficulty',
|
|
225
|
+
roll,
|
|
226
|
+
result: difficultyDieResult(roll)
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Roll challenge dice
|
|
231
|
+
for (let i = 0; i < sanitizedPool.challengeDice; i++) {
|
|
232
|
+
const roll = rollDie(12);
|
|
233
|
+
detailedResults.push({
|
|
234
|
+
type: 'challenge',
|
|
235
|
+
roll,
|
|
236
|
+
result: challengeDieResult(roll)
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
results: detailedResults,
|
|
242
|
+
summary: sumResults(detailedResults.map(r => r.result))
|
|
243
|
+
};
|
|
244
|
+
};
|
package/src/index.ts
ADDED
package/src/pools.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DicePool } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a basic skill check dice pool
|
|
5
|
+
* @param ability Number of ability (green) dice
|
|
6
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
7
|
+
* @returns DicePool configured for a basic skill check
|
|
8
|
+
*/
|
|
9
|
+
export const createSkillCheck = (ability: number, proficiency: number): DicePool => ({
|
|
10
|
+
abilityDice: Math.max(0, ability),
|
|
11
|
+
proficiencyDice: Math.max(0, proficiency)
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates a combat check dice pool with optional boost die
|
|
16
|
+
* @param ability Number of ability (green) dice
|
|
17
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
18
|
+
* @param boost Number of boost (blue) dice
|
|
19
|
+
* @returns DicePool configured for a combat check
|
|
20
|
+
*/
|
|
21
|
+
export const createCombatCheck = (ability: number, proficiency: number, boost: number = 0): DicePool => ({
|
|
22
|
+
abilityDice: Math.max(0, ability),
|
|
23
|
+
proficiencyDice: Math.max(0, proficiency),
|
|
24
|
+
boostDice: Math.max(0, boost)
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates an opposed check dice pool
|
|
29
|
+
* @param ability Number of ability (green) dice
|
|
30
|
+
* @param proficiency Number of proficiency (yellow) dice
|
|
31
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
32
|
+
* @param challenge Number of challenge (red) dice
|
|
33
|
+
* @returns DicePool configured for an opposed check
|
|
34
|
+
*/
|
|
35
|
+
export const createOpposedCheck = (
|
|
36
|
+
ability: number,
|
|
37
|
+
proficiency: number,
|
|
38
|
+
difficulty: number,
|
|
39
|
+
challenge: number = 0
|
|
40
|
+
): DicePool => ({
|
|
41
|
+
abilityDice: Math.max(0, ability),
|
|
42
|
+
proficiencyDice: Math.max(0, proficiency),
|
|
43
|
+
difficultyDice: Math.max(0, difficulty),
|
|
44
|
+
challengeDice: Math.max(0, challenge)
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates a difficulty check dice pool
|
|
49
|
+
* @param difficulty Number of difficulty (purple) dice
|
|
50
|
+
* @param challenge Number of challenge (red) dice
|
|
51
|
+
* @returns DicePool configured for a pure difficulty check
|
|
52
|
+
*/
|
|
53
|
+
export const createDifficultyPool = (difficulty: number, challenge: number = 0): DicePool => ({
|
|
54
|
+
difficultyDice: Math.max(0, difficulty),
|
|
55
|
+
challengeDice: Math.max(0, challenge)
|
|
56
|
+
});
|