@yipe/dice 0.2.15 → 0.2.16

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.
@@ -2671,6 +2671,9 @@ var RollBuilder = class _RollBuilder {
2671
2671
  alwaysHits() {
2672
2672
  return new AlwaysHitBuilder(this);
2673
2673
  }
2674
+ alwaysCrits() {
2675
+ return new AlwaysCritBuilder(this);
2676
+ }
2674
2677
  copy() {
2675
2678
  return new this.constructor(this.getSubRollConfigs());
2676
2679
  }
@@ -2962,7 +2965,7 @@ var MaxOfRollBuilder = class _MaxOfRollBuilder extends RollBuilder {
2962
2965
  child: sumChild
2963
2966
  };
2964
2967
  }
2965
- } catch (e) {
2968
+ } catch {
2966
2969
  }
2967
2970
  throw new Error(
2968
2971
  `MaxOfRollBuilder.toAST(): Unsupported innerRoll configuration`
@@ -2997,6 +3000,9 @@ var AlwaysHitBuilder = class _AlwaysHitBuilder extends RollBuilder {
2997
3000
  const newConfig = { critThreshold };
2998
3001
  return new _AlwaysHitBuilder(this, newConfig);
2999
3002
  }
3003
+ alwaysCrits() {
3004
+ return new AlwaysCritBuilder(this, void 0, true);
3005
+ }
3000
3006
  // Legacy expressions
3001
3007
  toExpression() {
3002
3008
  const configs = this.getSubRollConfigs();
@@ -3014,23 +3020,28 @@ var AlwaysHitBuilder = class _AlwaysHitBuilder extends RollBuilder {
3014
3020
  return new _AlwaysHitBuilder(baseCopy, newConfig);
3015
3021
  }
3016
3022
  };
3017
- var AlwaysCritBuilder = class extends RollBuilder {
3018
- constructor(baseRoll, attackConfig) {
3023
+ var AlwaysCritBuilder = class _AlwaysCritBuilder extends RollBuilder {
3024
+ constructor(baseRoll, attackConfig, fromAlwaysHit = false) {
3019
3025
  super(baseRoll.getSubRollConfigs());
3020
3026
  __publicField(this, "attackConfig");
3027
+ __publicField(this, "fromAlwaysHit");
3021
3028
  if (attackConfig) {
3022
3029
  this.attackConfig = { ...attackConfig };
3023
3030
  } else {
3024
3031
  this.attackConfig = { critThreshold: 20 };
3025
3032
  }
3033
+ this.fromAlwaysHit = fromAlwaysHit || baseRoll instanceof AlwaysHitBuilder;
3034
+ }
3035
+ onHit(...args) {
3036
+ const damageRoll = RollBuilder.fromArgs(...args);
3037
+ return new AttackBuilder(this, damageRoll);
3026
3038
  }
3027
3039
  get critThreshold() {
3028
3040
  return this.attackConfig.critThreshold;
3029
3041
  }
3030
- // TODO - move this to AC Builder… or if we create a DC builder that has critOn, throw an error?
3031
3042
  critOn(critThreshold) {
3032
- const newConfig = { critThreshold };
3033
- return new AlwaysHitBuilder(this, newConfig);
3043
+ const newConfig = { critThreshold, ac: this.attackConfig.ac };
3044
+ return new _AlwaysCritBuilder(this, newConfig, this.fromAlwaysHit);
3034
3045
  }
3035
3046
  // Legacy expressions
3036
3047
  toExpression() {
@@ -3045,8 +3056,8 @@ var AlwaysCritBuilder = class extends RollBuilder {
3045
3056
  copy() {
3046
3057
  const baseCopy = new RollBuilder(this.getSubRollConfigs());
3047
3058
  const critThreshold = this.critThreshold;
3048
- const newConfig = { critThreshold };
3049
- return new AlwaysHitBuilder(baseCopy, newConfig);
3059
+ const newConfig = { critThreshold, ac: this.attackConfig.ac };
3060
+ return new _AlwaysCritBuilder(baseCopy, newConfig, this.fromAlwaysHit);
3050
3061
  }
3051
3062
  };
3052
3063
 
@@ -3582,9 +3593,9 @@ var AttackBuilder = class _AttackBuilder {
3582
3593
  crit = this.hitEffect?.copy().doubleDice() ?? RollBuilder.fromArgs(0);
3583
3594
  }
3584
3595
  const critThreshold = this.check.critThreshold;
3585
- if (critThreshold < 15 || critThreshold > 20) {
3596
+ if (critThreshold < 1 || critThreshold > 20) {
3586
3597
  throw new Error(
3587
- `Invalid crit threshold: ${critThreshold}. Must be between 15 and 20.`
3598
+ `Invalid crit threshold: ${critThreshold}. Must be between 1 and 20.`
3588
3599
  );
3589
3600
  }
3590
3601
  if (critThreshold === 20) {
@@ -3601,13 +3612,34 @@ var AttackBuilder = class _AttackBuilder {
3601
3612
  return `${checkPart} * ${effectPart}`;
3602
3613
  }
3603
3614
  resolveProbabilities(check, eps = 0) {
3604
- if (check instanceof AlwaysCritBuilder) {
3605
- return { pSuccess: 1, pHit: 0, pCrit: 1, pMiss: 0 };
3606
- }
3607
3615
  const rollType = check.rollType;
3608
3616
  const rerollOne = check.baseReroll > 0;
3609
3617
  const critThreshold = check.critThreshold;
3610
3618
  const d202 = d20RollPMF(rollType, rerollOne);
3619
+ if (check instanceof AlwaysCritBuilder) {
3620
+ if (check.fromAlwaysHit) {
3621
+ return { pSuccess: 1, pHit: 0, pCrit: 1, pMiss: 0 };
3622
+ }
3623
+ const ac2 = check.attackConfig.ac ?? 0;
3624
+ const staticMod2 = this.check.modifier;
3625
+ const bonusDicePMFs2 = this.check.getBonusDicePMFs(this.check, eps);
3626
+ const bonusPMF2 = bonusDicePMFs2.length ? PMF.convolveMany(bonusDicePMFs2, eps) : PMF.delta(0, eps);
3627
+ let pcrit2 = 0;
3628
+ let pmiss2 = 0;
3629
+ for (const [r, rec] of d202) {
3630
+ const pr = typeof rec === "number" ? rec : rec.p;
3631
+ if (pr <= 0) continue;
3632
+ if (r === 1) {
3633
+ pmiss2 += pr;
3634
+ continue;
3635
+ }
3636
+ const need = ac2 - staticMod2 - r;
3637
+ const pBonusHit = bonusPMF2.tailProbGE(need);
3638
+ pcrit2 += pr * pBonusHit;
3639
+ pmiss2 += pr * (1 - pBonusHit);
3640
+ }
3641
+ return { pSuccess: pcrit2, pHit: 0, pCrit: pcrit2, pMiss: pmiss2 };
3642
+ }
3611
3643
  if (check instanceof AlwaysHitBuilder) {
3612
3644
  let pCrit = 0;
3613
3645
  for (const [r, rec] of d202) {
@@ -3629,14 +3661,14 @@ var AttackBuilder = class _AttackBuilder {
3629
3661
  for (const [r, rec] of d202) {
3630
3662
  const pr = typeof rec === "number" ? rec : rec.p;
3631
3663
  if (pr <= 0) continue;
3632
- if (r >= critThreshold) {
3633
- pcrit += pr;
3634
- continue;
3635
- }
3636
3664
  if (r === 1) {
3637
3665
  pmiss += pr;
3638
3666
  continue;
3639
3667
  }
3668
+ if (r >= critThreshold) {
3669
+ pcrit += pr;
3670
+ continue;
3671
+ }
3640
3672
  const need = ac - staticMod - r;
3641
3673
  const pBonusHit = bonusPMF.tailProbGE(need);
3642
3674
  phit += pr * pBonusHit;
@@ -3717,6 +3749,16 @@ var ACBuilder = class _ACBuilder extends RollBuilder {
3717
3749
  };
3718
3750
  return new _ACBuilder(this, this.attackConfig.ac, newConfig);
3719
3751
  }
3752
+ alwaysCrits() {
3753
+ return new AlwaysCritBuilder(
3754
+ this,
3755
+ {
3756
+ critThreshold: this.attackConfig.critThreshold,
3757
+ ac: this.attackConfig.ac
3758
+ },
3759
+ false
3760
+ );
3761
+ }
3720
3762
  // Legacy expressions
3721
3763
  toExpression() {
3722
3764
  const configs = this.getSubRollConfigs();