@yipe/dice 0.4.0 → 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/CHANGELOG.md +18 -3
- package/dist/builder/index.cjs +106 -0
- package/dist/builder/index.cjs.map +1 -1
- package/dist/builder/index.d.cts +52 -2
- package/dist/builder/index.d.ts +52 -2
- package/dist/builder/index.js +105 -1
- package/dist/builder/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,15 +5,30 @@ All notable changes to this project are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.5.0]
|
|
9
9
|
|
|
10
10
|
Pushes damage-attribution / provenance and D&D-probability logic that the
|
|
11
11
|
consuming app (dprcalc) had hand-rolled over PMF internals down into the
|
|
12
|
-
library, so the provenance model and dice math stay owned here
|
|
13
|
-
|
|
12
|
+
library, so the provenance model and dice math stay owned here, and adds a
|
|
13
|
+
**composable scale node** so a scaled/rounded sub-roll can nest inside a larger
|
|
14
|
+
damage payload (per-damage-type resistance / immunity / vulnerability). All
|
|
15
|
+
additive except the Elemental-Adept bounce fix noted below.
|
|
14
16
|
|
|
15
17
|
### Added
|
|
16
18
|
|
|
19
|
+
- **`RollBuilder.scaleResult(numerator, denominator = 1, rounding = 'floor')`** —
|
|
20
|
+
wraps a builder in a composable `scale` AST node that scales its resolved PMF
|
|
21
|
+
by `numerator / denominator` with the given rounding. Unlike the old
|
|
22
|
+
`.half()` wrapper, a scaled builder composes: it survives `sumRolls(...)`
|
|
23
|
+
instead of being dropped on a flat-config merge, so a per-type resisted or
|
|
24
|
+
doubled sub-roll keeps its own scaling inside a larger hit/crit payload. The
|
|
25
|
+
rendered expression reflects it — `denominator === 1 → "N * (child)"`,
|
|
26
|
+
`numerator === 1 → "(child) // D"`, general → `"(child) * N // D"`. `.half()`
|
|
27
|
+
is now `scaleResult(1, 2, 'floor')`.
|
|
28
|
+
- **`sumRolls(parts: RollBuilder[])`** — additive factory whose `toAST()` is an
|
|
29
|
+
`add` node over each part's AST, letting scaled and plain children sit side by
|
|
30
|
+
side without the flat `.plus()` merge collapsing them. `toExpression()` joins
|
|
31
|
+
the parts with ` + ` and `toPMF()` convolves them.
|
|
17
32
|
- **`PMF.applyHitFrequency(frequency)`** — provenance-preserving mass
|
|
18
33
|
redistribution for effects that only occur with some probability (conditional
|
|
19
34
|
attacks, on-hit riders, sub-one AoE fractions): scales every hit bin (damage
|
package/dist/builder/index.cjs
CHANGED
|
@@ -4094,6 +4094,15 @@ var RollBuilder = class _RollBuilder {
|
|
|
4094
4094
|
half() {
|
|
4095
4095
|
return new HalfRollBuilder(this);
|
|
4096
4096
|
}
|
|
4097
|
+
/**
|
|
4098
|
+
* Scale this roll's result by `numerator / denominator`, rounding each outcome.
|
|
4099
|
+
* A general, composable form of {@link half} — used to model damage-type resistance
|
|
4100
|
+
* (`scaleResult(1, 2)` → `(expr) // 2`) and vulnerability (`scaleResult(2)` → `2 * (expr)`).
|
|
4101
|
+
* Compose several of these (and plain rolls) into one payload with {@link sumRolls}.
|
|
4102
|
+
*/
|
|
4103
|
+
scaleResult(numerator, denominator = 1, rounding = "floor") {
|
|
4104
|
+
return new ScaleRollBuilder(this, numerator, denominator, rounding);
|
|
4105
|
+
}
|
|
4097
4106
|
// Create a "max of N rolls" version of this roll for crit damage with keep operations
|
|
4098
4107
|
maxOf(count) {
|
|
4099
4108
|
return new MaxOfRollBuilder(this, count);
|
|
@@ -4148,6 +4157,50 @@ var HalfRollBuilder = class _HalfRollBuilder extends RollBuilder {
|
|
|
4148
4157
|
return new _HalfRollBuilder(this.innerRoll.copy());
|
|
4149
4158
|
}
|
|
4150
4159
|
};
|
|
4160
|
+
var ScaleRollBuilder = class _ScaleRollBuilder extends RollBuilder {
|
|
4161
|
+
constructor(innerRoll, numerator, denominator = 1, rounding = "floor") {
|
|
4162
|
+
super(0);
|
|
4163
|
+
this.innerRoll = innerRoll;
|
|
4164
|
+
this.numerator = numerator;
|
|
4165
|
+
this.denominator = denominator;
|
|
4166
|
+
this.rounding = rounding;
|
|
4167
|
+
}
|
|
4168
|
+
hasHiddenState() {
|
|
4169
|
+
return this.innerRoll.hasHiddenState();
|
|
4170
|
+
}
|
|
4171
|
+
get lastConfig() {
|
|
4172
|
+
return this.innerRoll.lastConfig;
|
|
4173
|
+
}
|
|
4174
|
+
getSubRollConfigs() {
|
|
4175
|
+
return this.innerRoll.getSubRollConfigs();
|
|
4176
|
+
}
|
|
4177
|
+
toExpression() {
|
|
4178
|
+
const inner = this.innerRoll.toExpression();
|
|
4179
|
+
if (this.denominator === 1) return `${this.numerator} * (${inner})`;
|
|
4180
|
+
if (this.numerator === 1) return `(${inner}) // ${this.denominator}`;
|
|
4181
|
+
return `(${inner}) * ${this.numerator} // ${this.denominator}`;
|
|
4182
|
+
}
|
|
4183
|
+
toAST() {
|
|
4184
|
+
return {
|
|
4185
|
+
type: "scale",
|
|
4186
|
+
numerator: this.numerator,
|
|
4187
|
+
denominator: this.denominator,
|
|
4188
|
+
rounding: this.rounding,
|
|
4189
|
+
child: this.innerRoll.toAST()
|
|
4190
|
+
};
|
|
4191
|
+
}
|
|
4192
|
+
toPMF(eps = 0) {
|
|
4193
|
+
return pmfFromRollBuilder(this, eps);
|
|
4194
|
+
}
|
|
4195
|
+
copy() {
|
|
4196
|
+
return new _ScaleRollBuilder(
|
|
4197
|
+
this.innerRoll.copy(),
|
|
4198
|
+
this.numerator,
|
|
4199
|
+
this.denominator,
|
|
4200
|
+
this.rounding
|
|
4201
|
+
);
|
|
4202
|
+
}
|
|
4203
|
+
};
|
|
4151
4204
|
var MaxOfRollBuilder = class _MaxOfRollBuilder extends RollBuilder {
|
|
4152
4205
|
constructor(innerRoll, count, diceCount, diceSides) {
|
|
4153
4206
|
super(0);
|
|
@@ -4446,6 +4499,49 @@ var PooledRollBuilder = class _PooledRollBuilder extends RollBuilder {
|
|
|
4446
4499
|
return new _PooledRollBuilder(sumNode, newExpr);
|
|
4447
4500
|
}
|
|
4448
4501
|
};
|
|
4502
|
+
var CompositeSumRollBuilder = class _CompositeSumRollBuilder extends RollBuilder {
|
|
4503
|
+
constructor(parts) {
|
|
4504
|
+
super(0);
|
|
4505
|
+
this.parts = parts;
|
|
4506
|
+
}
|
|
4507
|
+
hasHiddenState() {
|
|
4508
|
+
return true;
|
|
4509
|
+
}
|
|
4510
|
+
getSubRollConfigs() {
|
|
4511
|
+
return [];
|
|
4512
|
+
}
|
|
4513
|
+
toAST() {
|
|
4514
|
+
return {
|
|
4515
|
+
type: "add",
|
|
4516
|
+
children: this.parts.map((p) => ({
|
|
4517
|
+
node: p.toAST(),
|
|
4518
|
+
sign: 1
|
|
4519
|
+
}))
|
|
4520
|
+
};
|
|
4521
|
+
}
|
|
4522
|
+
toExpression() {
|
|
4523
|
+
const exprs = this.parts.map((p) => p.toExpression()).filter((e) => e && e !== "0");
|
|
4524
|
+
if (exprs.length === 0) return "0";
|
|
4525
|
+
let result = exprs[0];
|
|
4526
|
+
for (let i = 1; i < exprs.length; i++) {
|
|
4527
|
+
const e = exprs[i];
|
|
4528
|
+
result += e.startsWith("-") ? ` - ${e.substring(1)}` : ` + ${e}`;
|
|
4529
|
+
}
|
|
4530
|
+
return result.replace(/\+ -/g, "-");
|
|
4531
|
+
}
|
|
4532
|
+
toPMF(eps = 0) {
|
|
4533
|
+
return pmfFromRollBuilder(this, eps);
|
|
4534
|
+
}
|
|
4535
|
+
copy() {
|
|
4536
|
+
return new _CompositeSumRollBuilder(this.parts.map((p) => p.copy()));
|
|
4537
|
+
}
|
|
4538
|
+
};
|
|
4539
|
+
function sumRolls(parts) {
|
|
4540
|
+
const meaningful = parts.filter((p) => p !== void 0);
|
|
4541
|
+
if (meaningful.length === 0) return new RollBuilder(0);
|
|
4542
|
+
if (meaningful.length === 1) return meaningful[0];
|
|
4543
|
+
return new CompositeSumRollBuilder(meaningful);
|
|
4544
|
+
}
|
|
4449
4545
|
|
|
4450
4546
|
// src/builder/factory.ts
|
|
4451
4547
|
var rollFn = (count, sidesOrDie, modifier) => {
|
|
@@ -4676,6 +4772,11 @@ function resolve(node, eps = defaultEps) {
|
|
|
4676
4772
|
if (count === 1) return childPMF;
|
|
4677
4773
|
return computeMaxOfPMF(childPMF, count, eps);
|
|
4678
4774
|
}
|
|
4775
|
+
case "scale": {
|
|
4776
|
+
const childPMF = resolve(node.child, eps);
|
|
4777
|
+
const denom = node.denominator === 0 ? 1 : node.denominator;
|
|
4778
|
+
return childPMF.scaleDamage(node.numerator / denom, node.rounding);
|
|
4779
|
+
}
|
|
4679
4780
|
}
|
|
4680
4781
|
})();
|
|
4681
4782
|
builderPMFCache.set(cacheKey, result);
|
|
@@ -4747,6 +4848,7 @@ function findDie(node) {
|
|
|
4747
4848
|
case "d20Roll":
|
|
4748
4849
|
case "half":
|
|
4749
4850
|
case "maxOf":
|
|
4851
|
+
case "scale":
|
|
4750
4852
|
return findDie(node.child);
|
|
4751
4853
|
case "keep":
|
|
4752
4854
|
return findDie(node.child.child);
|
|
@@ -4931,6 +5033,8 @@ function getASTSignature(node) {
|
|
|
4931
5033
|
return `half{ch:${getASTSignature(node.child)}}`;
|
|
4932
5034
|
case "maxOf":
|
|
4933
5035
|
return `maxOf{c:${node.count},ch:${getASTSignature(node.child)}}`;
|
|
5036
|
+
case "scale":
|
|
5037
|
+
return `scale{n:${node.numerator},d:${node.denominator},r:${node.rounding},ch:${getASTSignature(node.child)}}`;
|
|
4934
5038
|
case "add": {
|
|
4935
5039
|
let constantValue = 0;
|
|
4936
5040
|
const otherChildrenSigs = [];
|
|
@@ -5378,6 +5482,7 @@ exports.ParsedRollBuilder = ParsedRollBuilder;
|
|
|
5378
5482
|
exports.PooledRollBuilder = PooledRollBuilder;
|
|
5379
5483
|
exports.RollBuilder = RollBuilder;
|
|
5380
5484
|
exports.SaveBuilder = SaveBuilder;
|
|
5485
|
+
exports.ScaleRollBuilder = ScaleRollBuilder;
|
|
5381
5486
|
exports.builderPMFCache = builderPMFCache;
|
|
5382
5487
|
exports.d = d;
|
|
5383
5488
|
exports.d10 = d10;
|
|
@@ -5391,5 +5496,6 @@ exports.defaultConfig = defaultConfig;
|
|
|
5391
5496
|
exports.flat = flat;
|
|
5392
5497
|
exports.hd20 = hd20;
|
|
5393
5498
|
exports.roll = roll;
|
|
5499
|
+
exports.sumRolls = sumRolls;
|
|
5394
5500
|
//# sourceMappingURL=index.cjs.map
|
|
5395
5501
|
//# sourceMappingURL=index.cjs.map
|