@yipe/dice 0.2.12 → 0.2.15

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.
@@ -1,4 +1,4 @@
1
- import { P as PMF, i as DiceQuery, L as LRUCache } from '../pmf-D1p2Re-J.cjs';
1
+ import { P as PMF, C as CritConfig, i as DiceQuery, L as LRUCache } from '../pmf-CYaEbY7m.cjs';
2
2
 
3
3
  type ExpressionNode = DieNode | ConstantNode | SumNode | AddNode | KeepNode | D20RollNode | HalfNode | MaxOfNode;
4
4
  type DieNode = {
@@ -138,6 +138,7 @@ declare class RollBuilder {
138
138
  addRoll(count?: number): RollBuilder;
139
139
  scaleDice(scale: number): RollBuilder;
140
140
  doubleDice(): RollBuilder;
141
+ alwaysHits(): AlwaysHitBuilder;
141
142
  copy(): RollBuilder;
142
143
  d4: () => RollBuilder;
143
144
  d6: () => RollBuilder;
@@ -182,19 +183,42 @@ declare class MaxOfRollBuilder extends RollBuilder {
182
183
  get lastConfig(): any;
183
184
  getSubRollConfigs(): readonly RollConfig[];
184
185
  toExpression(): string;
185
- private findDieInAST;
186
186
  toAST(): ExpressionNode;
187
187
  toPMF(eps?: number): PMF;
188
188
  copy(): MaxOfRollBuilder;
189
189
  }
190
+ declare class AlwaysHitBuilder extends RollBuilder {
191
+ readonly attackConfig: CritConfig;
192
+ constructor(baseRoll: RollBuilder, attackConfig?: CritConfig);
193
+ onHit(val: number): AttackBuilder;
194
+ onHit(val: RollBuilder): AttackBuilder;
195
+ onHit(count: number, die: RollBuilder): AttackBuilder;
196
+ onHit(count: number, sides: number): AttackBuilder;
197
+ onHit(count: number, die: RollBuilder, modifier: number): AttackBuilder;
198
+ onHit(count: number, sides: number, modifier: number): AttackBuilder;
199
+ get critThreshold(): number;
200
+ critOn(critThreshold: number): AlwaysHitBuilder;
201
+ toExpression(): string;
202
+ toPMF(): PMF;
203
+ copy(): AlwaysHitBuilder;
204
+ }
205
+ declare class AlwaysCritBuilder extends RollBuilder {
206
+ readonly attackConfig: CritConfig;
207
+ constructor(baseRoll: RollBuilder, attackConfig?: CritConfig);
208
+ get critThreshold(): number;
209
+ critOn(critThreshold: number): AlwaysHitBuilder;
210
+ toExpression(): string;
211
+ toPMF(): PMF;
212
+ copy(): AlwaysHitBuilder;
213
+ }
190
214
 
191
215
  type ActionEffect = RollBuilder;
192
216
  declare class AttackBuilder implements CheckBuilder {
193
- readonly check: ACBuilder;
217
+ readonly check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder;
194
218
  private readonly hitEffect?;
195
219
  private readonly critEffect?;
196
220
  private readonly missEffect?;
197
- constructor(check: ACBuilder, hitEffect?: ActionEffect, critEffect?: ActionEffect | null, missEffect?: ActionEffect);
221
+ constructor(check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder, hitEffect?: ActionEffect, critEffect?: ActionEffect | null, missEffect?: ActionEffect);
198
222
  onCrit(val: number): AttackBuilder;
199
223
  onCrit(val: RollBuilder): AttackBuilder;
200
224
  onCrit(count: number, die: RollBuilder): AttackBuilder;
@@ -209,7 +233,7 @@ declare class AttackBuilder implements CheckBuilder {
209
233
  onMiss(count: number, sides: number, modifier: number): AttackBuilder;
210
234
  noCrit(): AttackBuilder;
211
235
  toExpression(): string;
212
- resolveProbabilities(check: ACBuilder, eps?: number): {
236
+ resolveProbabilities(check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder, eps?: number): {
213
237
  pSuccess: number;
214
238
  pHit: number;
215
239
  pCrit: number;
@@ -299,4 +323,4 @@ declare const flat: (n: number) => RollBuilder;
299
323
  declare const roll: RollFactory;
300
324
  declare const builderPMFCache: LRUCache<string, PMF>;
301
325
 
302
- export { ACBuilder, type AttackConfig, type AttackResolution, type CheckBuilder, DCBuilder, HalfRollBuilder, type KeepMode, MaxOfRollBuilder, type Resolution, RollBuilder, type RollConfig, type RollFactory, type RollType, SaveBuilder, type SaveOutcome, type SaveResolution, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
326
+ export { ACBuilder, AlwaysCritBuilder, AlwaysHitBuilder, type AttackConfig, type AttackResolution, type CheckBuilder, DCBuilder, HalfRollBuilder, type KeepMode, MaxOfRollBuilder, type Resolution, RollBuilder, type RollConfig, type RollFactory, type RollType, SaveBuilder, type SaveOutcome, type SaveResolution, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
@@ -1,4 +1,4 @@
1
- import { P as PMF, i as DiceQuery, L as LRUCache } from '../pmf-D1p2Re-J.js';
1
+ import { P as PMF, C as CritConfig, i as DiceQuery, L as LRUCache } from '../pmf-CYaEbY7m.js';
2
2
 
3
3
  type ExpressionNode = DieNode | ConstantNode | SumNode | AddNode | KeepNode | D20RollNode | HalfNode | MaxOfNode;
4
4
  type DieNode = {
@@ -138,6 +138,7 @@ declare class RollBuilder {
138
138
  addRoll(count?: number): RollBuilder;
139
139
  scaleDice(scale: number): RollBuilder;
140
140
  doubleDice(): RollBuilder;
141
+ alwaysHits(): AlwaysHitBuilder;
141
142
  copy(): RollBuilder;
142
143
  d4: () => RollBuilder;
143
144
  d6: () => RollBuilder;
@@ -182,19 +183,42 @@ declare class MaxOfRollBuilder extends RollBuilder {
182
183
  get lastConfig(): any;
183
184
  getSubRollConfigs(): readonly RollConfig[];
184
185
  toExpression(): string;
185
- private findDieInAST;
186
186
  toAST(): ExpressionNode;
187
187
  toPMF(eps?: number): PMF;
188
188
  copy(): MaxOfRollBuilder;
189
189
  }
190
+ declare class AlwaysHitBuilder extends RollBuilder {
191
+ readonly attackConfig: CritConfig;
192
+ constructor(baseRoll: RollBuilder, attackConfig?: CritConfig);
193
+ onHit(val: number): AttackBuilder;
194
+ onHit(val: RollBuilder): AttackBuilder;
195
+ onHit(count: number, die: RollBuilder): AttackBuilder;
196
+ onHit(count: number, sides: number): AttackBuilder;
197
+ onHit(count: number, die: RollBuilder, modifier: number): AttackBuilder;
198
+ onHit(count: number, sides: number, modifier: number): AttackBuilder;
199
+ get critThreshold(): number;
200
+ critOn(critThreshold: number): AlwaysHitBuilder;
201
+ toExpression(): string;
202
+ toPMF(): PMF;
203
+ copy(): AlwaysHitBuilder;
204
+ }
205
+ declare class AlwaysCritBuilder extends RollBuilder {
206
+ readonly attackConfig: CritConfig;
207
+ constructor(baseRoll: RollBuilder, attackConfig?: CritConfig);
208
+ get critThreshold(): number;
209
+ critOn(critThreshold: number): AlwaysHitBuilder;
210
+ toExpression(): string;
211
+ toPMF(): PMF;
212
+ copy(): AlwaysHitBuilder;
213
+ }
190
214
 
191
215
  type ActionEffect = RollBuilder;
192
216
  declare class AttackBuilder implements CheckBuilder {
193
- readonly check: ACBuilder;
217
+ readonly check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder;
194
218
  private readonly hitEffect?;
195
219
  private readonly critEffect?;
196
220
  private readonly missEffect?;
197
- constructor(check: ACBuilder, hitEffect?: ActionEffect, critEffect?: ActionEffect | null, missEffect?: ActionEffect);
221
+ constructor(check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder, hitEffect?: ActionEffect, critEffect?: ActionEffect | null, missEffect?: ActionEffect);
198
222
  onCrit(val: number): AttackBuilder;
199
223
  onCrit(val: RollBuilder): AttackBuilder;
200
224
  onCrit(count: number, die: RollBuilder): AttackBuilder;
@@ -209,7 +233,7 @@ declare class AttackBuilder implements CheckBuilder {
209
233
  onMiss(count: number, sides: number, modifier: number): AttackBuilder;
210
234
  noCrit(): AttackBuilder;
211
235
  toExpression(): string;
212
- resolveProbabilities(check: ACBuilder, eps?: number): {
236
+ resolveProbabilities(check: ACBuilder | AlwaysHitBuilder | AlwaysCritBuilder, eps?: number): {
213
237
  pSuccess: number;
214
238
  pHit: number;
215
239
  pCrit: number;
@@ -299,4 +323,4 @@ declare const flat: (n: number) => RollBuilder;
299
323
  declare const roll: RollFactory;
300
324
  declare const builderPMFCache: LRUCache<string, PMF>;
301
325
 
302
- export { ACBuilder, type AttackConfig, type AttackResolution, type CheckBuilder, DCBuilder, HalfRollBuilder, type KeepMode, MaxOfRollBuilder, type Resolution, RollBuilder, type RollConfig, type RollFactory, type RollType, SaveBuilder, type SaveOutcome, type SaveResolution, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
326
+ export { ACBuilder, AlwaysCritBuilder, AlwaysHitBuilder, type AttackConfig, type AttackResolution, type CheckBuilder, DCBuilder, HalfRollBuilder, type KeepMode, MaxOfRollBuilder, type Resolution, RollBuilder, type RollConfig, type RollFactory, type RollType, SaveBuilder, type SaveOutcome, type SaveResolution, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
@@ -2657,14 +2657,6 @@ var RollBuilder = class _RollBuilder {
2657
2657
  const scaleInt = Math.floor(scale);
2658
2658
  if (scaleInt !== scale) throw new Error("Scale must be an integer");
2659
2659
  if (scaleInt <= 0) throw new Error("Scale must be > 0");
2660
- if (scaleInt > 1) {
2661
- const configs = this.getSubRollConfigs();
2662
- if (configs.length === 1 && configs[0].keep && configs[0].count === 1) {
2663
- const config = configs[0];
2664
- const newConfig = { ...config, count: scaleInt };
2665
- return new _RollBuilder([newConfig]);
2666
- }
2667
- }
2668
2660
  const newConfigs = this.getSubRollConfigs().map((config) => {
2669
2661
  if (!config.sides || config.sides <= 0) return config;
2670
2662
  return { ...config, count: config.count * scaleInt };
@@ -2674,6 +2666,9 @@ var RollBuilder = class _RollBuilder {
2674
2666
  doubleDice() {
2675
2667
  return this.scaleDice(2);
2676
2668
  }
2669
+ alwaysHits() {
2670
+ return new AlwaysHitBuilder(this);
2671
+ }
2677
2672
  copy() {
2678
2673
  return new this.constructor(this.getSubRollConfigs());
2679
2674
  }
@@ -2937,17 +2932,6 @@ var MaxOfRollBuilder = class _MaxOfRollBuilder extends RollBuilder {
2937
2932
  }
2938
2933
  return `max${this.count}(?d?)`;
2939
2934
  }
2940
- findDieInAST(node) {
2941
- if (node.type === "die") return node;
2942
- if (node.child) return this.findDieInAST(node.child);
2943
- if (node.children) {
2944
- for (const child of node.children) {
2945
- const result = this.findDieInAST(child.node || child);
2946
- if (result) return result;
2947
- }
2948
- }
2949
- return null;
2950
- }
2951
2935
  toAST() {
2952
2936
  if (this.diceCount && this.diceSides) {
2953
2937
  const sumChild = {
@@ -2989,6 +2973,80 @@ var MaxOfRollBuilder = class _MaxOfRollBuilder extends RollBuilder {
2989
2973
  return new _MaxOfRollBuilder(this.innerRoll.copy(), this.count);
2990
2974
  }
2991
2975
  };
2976
+ var AlwaysHitBuilder = class _AlwaysHitBuilder extends RollBuilder {
2977
+ constructor(baseRoll, attackConfig) {
2978
+ super(baseRoll.getSubRollConfigs());
2979
+ __publicField(this, "attackConfig");
2980
+ if (attackConfig) {
2981
+ this.attackConfig = { ...attackConfig };
2982
+ } else {
2983
+ this.attackConfig = { critThreshold: 20 };
2984
+ }
2985
+ }
2986
+ onHit(...args) {
2987
+ const damageRoll = RollBuilder.fromArgs(...args);
2988
+ return new AttackBuilder(this, damageRoll);
2989
+ }
2990
+ get critThreshold() {
2991
+ return this.attackConfig.critThreshold;
2992
+ }
2993
+ // TODO - move this to AC Builder… or if we create a DC builder that has critOn, throw an error?
2994
+ critOn(critThreshold) {
2995
+ const newConfig = { critThreshold };
2996
+ return new _AlwaysHitBuilder(this, newConfig);
2997
+ }
2998
+ // Legacy expressions
2999
+ toExpression() {
3000
+ const configs = this.getSubRollConfigs();
3001
+ return new RollBuilder(configs).toExpression();
3002
+ }
3003
+ toPMF() {
3004
+ const rollType = this.rollType;
3005
+ const rerollOne = this.baseReroll > 0;
3006
+ return d20RollPMF(rollType, rerollOne);
3007
+ }
3008
+ copy() {
3009
+ const baseCopy = new RollBuilder(this.getSubRollConfigs());
3010
+ const critThreshold = this.critThreshold;
3011
+ const newConfig = { critThreshold };
3012
+ return new _AlwaysHitBuilder(baseCopy, newConfig);
3013
+ }
3014
+ };
3015
+ var AlwaysCritBuilder = class extends RollBuilder {
3016
+ constructor(baseRoll, attackConfig) {
3017
+ super(baseRoll.getSubRollConfigs());
3018
+ __publicField(this, "attackConfig");
3019
+ if (attackConfig) {
3020
+ this.attackConfig = { ...attackConfig };
3021
+ } else {
3022
+ this.attackConfig = { critThreshold: 20 };
3023
+ }
3024
+ }
3025
+ get critThreshold() {
3026
+ return this.attackConfig.critThreshold;
3027
+ }
3028
+ // TODO - move this to AC Builder… or if we create a DC builder that has critOn, throw an error?
3029
+ critOn(critThreshold) {
3030
+ const newConfig = { critThreshold };
3031
+ return new AlwaysHitBuilder(this, newConfig);
3032
+ }
3033
+ // Legacy expressions
3034
+ toExpression() {
3035
+ const configs = this.getSubRollConfigs();
3036
+ return new RollBuilder(configs).toExpression();
3037
+ }
3038
+ toPMF() {
3039
+ const rollType = this.rollType;
3040
+ const rerollOne = this.baseReroll > 0;
3041
+ return d20RollPMF(rollType, rerollOne);
3042
+ }
3043
+ copy() {
3044
+ const baseCopy = new RollBuilder(this.getSubRollConfigs());
3045
+ const critThreshold = this.critThreshold;
3046
+ const newConfig = { critThreshold };
3047
+ return new AlwaysHitBuilder(baseCopy, newConfig);
3048
+ }
3049
+ };
2992
3050
 
2993
3051
  // src/builder/factory.ts
2994
3052
  var rollFn = (count, sidesOrDie, modifier) => {
@@ -3080,7 +3138,18 @@ function astFromRollConfigs(configs) {
3080
3138
  const baseCount = Math.max(1, Math.floor(Math.abs(count || 1)));
3081
3139
  const trials = Math.max(1, Math.floor(cfg.keep.total));
3082
3140
  const k = Math.max(0, Math.floor(cfg.keep.count));
3083
- if (trials === baseCount) {
3141
+ if (k === 1 && cfg.keep.mode === "highest") {
3142
+ const perTrial = {
3143
+ type: "sum",
3144
+ count: baseCount,
3145
+ child: node
3146
+ };
3147
+ if (trials === 1) {
3148
+ node = perTrial;
3149
+ } else {
3150
+ node = { type: "maxOf", count: trials, child: perTrial };
3151
+ }
3152
+ } else if (trials === baseCount) {
3084
3153
  const base = { type: "sum", count: trials, child: node };
3085
3154
  node = {
3086
3155
  type: "keep",
@@ -3096,8 +3165,6 @@ function astFromRollConfigs(configs) {
3096
3165
  };
3097
3166
  if (trials === 1) {
3098
3167
  node = perTrial;
3099
- } else if (k === 1 && cfg.keep.mode === "highest") {
3100
- node = { type: "maxOf", count: trials, child: perTrial };
3101
3168
  } else {
3102
3169
  const trialPool = {
3103
3170
  type: "sum",
@@ -3532,11 +3599,25 @@ var AttackBuilder = class _AttackBuilder {
3532
3599
  return `${checkPart} * ${effectPart}`;
3533
3600
  }
3534
3601
  resolveProbabilities(check, eps = 0) {
3535
- const ac = check.attackConfig.ac;
3602
+ if (check instanceof AlwaysCritBuilder) {
3603
+ return { pSuccess: 1, pHit: 0, pCrit: 1, pMiss: 0 };
3604
+ }
3536
3605
  const rollType = check.rollType;
3537
3606
  const rerollOne = check.baseReroll > 0;
3538
3607
  const critThreshold = check.critThreshold;
3539
3608
  const d202 = d20RollPMF(rollType, rerollOne);
3609
+ if (check instanceof AlwaysHitBuilder) {
3610
+ let pCrit = 0;
3611
+ for (const [r, rec] of d202) {
3612
+ const pr = typeof rec === "number" ? rec : rec.p;
3613
+ if (pr <= 0) continue;
3614
+ if (r >= critThreshold) pCrit += pr;
3615
+ }
3616
+ const pHit = 1 - pCrit;
3617
+ const pMiss = 0;
3618
+ return { pSuccess: 1, pHit, pCrit, pMiss };
3619
+ }
3620
+ const ac = check.attackConfig.ac;
3540
3621
  const staticMod = this.check.modifier;
3541
3622
  const bonusDicePMFs = this.check.getBonusDicePMFs(this.check, eps);
3542
3623
  const bonusPMF = bonusDicePMFs.length ? PMF.convolveMany(bonusDicePMFs, eps) : PMF.delta(0, eps);
@@ -3821,6 +3902,6 @@ RollBuilder.prototype.dc = function(saveDC) {
3821
3902
  return new DCBuilder(this).dc(saveDC);
3822
3903
  };
3823
3904
 
3824
- export { ACBuilder, DCBuilder, HalfRollBuilder, MaxOfRollBuilder, RollBuilder, SaveBuilder, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
3905
+ export { ACBuilder, AlwaysCritBuilder, AlwaysHitBuilder, DCBuilder, HalfRollBuilder, MaxOfRollBuilder, RollBuilder, SaveBuilder, builderPMFCache, d, d10, d100, d12, d20, d4, d6, d8, defaultConfig, flat, hd20, roll };
3825
3906
  //# sourceMappingURL=index.js.map
3826
3907
  //# sourceMappingURL=index.js.map