comparing fomula

CCalego1/15/2023
Anyone know of a foundry utility to compare two strings that might be dice formulae to tell which has the lesser deterministic value?
CCalego1/15/2023
🧵
CCalego1/15/2023
use case:
I have two strings that
- might just be numbers ('3' and '4')
- might be simple formula ('3 + 3' and '4')
- might be nonDeterministic formula ('3 + 1d4' and '4')

I want to know:
- if both are deterministic formula, what is the Floor of their values
- if they aren't deterministic, I'll do nothing with either value
CCalego1/15/2023
oh i can use dnd5e's simplifyRollFormula for this

if the output of simplifyRollFormula is parsable as a Number, I can compare them easily
CCalego1/15/2023
ok wtf js
CCalego1/15/2023
oh, i'm dumb. .floor is for rounding
I'm looking for .min
CCalego1/15/2023
this is definitely excessive...

    const { abilities, attributes, bonuses, details } = this.actor.system;

    let spellAttackModFormula = [
      new Intl.NumberFormat('en-US', {
        signDisplay: 'exceptZero',
      })
        .format((abilities[attributes.spellcasting || 'int']?.mod ?? 0) + attributes.prof)
        .toString(),
    ];

    // apply the bonuses if they are equivalent
    if (bonuses.msak.attack === bonuses.rsak.attack) {
      spellAttackModFormula.push(bonuses.msak.attack);
      // apply the lesser deterministic bonus
    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {
      const lesserBonus = Math.min(
        dnd5e.dice.simplifyRollFormula(bonuses.msak.attack),
        dnd5e.dice.simplifyRollFormula(bonuses.rsak.attack)
      );

      // if lesserBonus is a number, push it to the spellAttackModFormula
      if (!Number.isNaN(lesserBonus)) {
        spellAttackModFormula.push(lesserBonus);
      }
    }
    sheetData.spellAttackMod =
      spellAttackModFormula.length === 1
        ? spellAttackModFormula[0]
        : dnd5e.dice.simplifyRollFormula(spellAttackModFormula.join(' + '));


BUT
it does do what I was looking for and covers all the edge cases I can think of
CCalego1/15/2023
Most of the time I know of, if there's a bonus, it'll be adding to both msak and rsak to represent a global increase

but the data does support disparate mods, in which case, applying the lesser one is 'safe' to this display of 'spell attack modifier'
MMana1/15/2023
.evaluate({min:true, async:false}) doesn't work for you?
MMana1/15/2023
Or did I misunderstand what you were after?
CCalego1/15/2023
is that a method on Roll?
MMana1/15/2023
Yes.
CCalego1/15/2023
min would return the minimum possible based on the formula provided?
MMana1/15/2023
Yes. It sets the dice to minimum value they'd give instead of randomizing them and returns the result.
CCalego1/15/2023
gotcha, not quite what i'm looking for
CCalego1/15/2023
I'm really looking to compare two formulas, and use the 'min' one
CCalego1/15/2023
(but only if they're deterministic)
MMana1/15/2023
Roll.isDeterministic is a thing
MMana1/15/2023
It also exists for individual terms.
MMana1/15/2023
That is available pre-eval
CCalego1/15/2023
so the alternative to using the dnd5e simplifyRollFormula would look something like :
const formulaA = new Roll(bonuses.msak.attack);
const formulaB = new Roll(bonuses.rsak.attack);

if (formulaA.isDeterministic() && formulaB.isDeterministic()) {
  spellAttackModFormula.push(
    Math.min(formulaA.evaluate(), formulaB.evaluate());
  );
}
MMana1/15/2023
Almost, .isDeterministic is a getter.
And .evaluate() returns Roll instance, so you'd need to add .total there.
MMana1/15/2023
Also eval is async unless you tell it to be non-async.
CCalego1/15/2023
that async:false is being deprecated right?
CCalego1/15/2023
I could probably DIY that actually if isDeterministic is true jk not as easy i expected in js
MMana1/15/2023
People keep saying it's not. The requirement for it is, because async is becoming the default.
MMana1/15/2023
And there's no warning in it that sync option is going away, just that it won't be the default.
CCalego1/15/2023
goootcha
MMana1/15/2023
Anyway, you'd have this:
if (formulaA.isDeterministic && formulaB.isDeterministic) {
  spellAttackModFormula.push(
    Math.min(formulaA.evaluate({async:false}).total, formulaB.evaluate({async:false}.total));
  );
}
CCalego1/15/2023
so then the question i have is 'is the overhead of creating two Rolls to compare these strings greater than or less than using simplifyRollFormula?'

odds are, less than, simplifyRollFormula is a heavy function now that I look closer
MMana1/15/2023
I'd favor whichever makes the intent of the code clearer.
CCalego1/15/2023
    // apply the bonuses if they are equivalent
    if (bonuses.msak.attack === bonuses.rsak.attack) {
      spellAttackModFormula.push(bonuses.msak.attack);
    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {
      const formulaA = new Roll(bonuses.msak.attack);
      const formulaB = new Roll(bonuses.rsak.attack);

      // apply the lesser deterministic bonus
      if (formulaA.isDeterministic && formulaB.isDeterministic) {
        spellAttackModFormula.push(
          Math.min(formulaA.evaluate({ async: false }).total, formulaB.evaluate({ async: false }.total))
        );
      }
    }


suspect this will never be clear 😛 but this is a solidly simpler solution and doesn't rely on 5e code

thanks @Mana
LTLLLeo The League Lion1/15/2023
@Calego gave :vote: LeaguePoints™ to @Mana (#15 • 203)
CCalego1/15/2023
🎉
UUUnknown User1/15/2023
3 Messages Not Public
Sign In & Join Server To View
CCalego1/15/2023
External constraint, could be a simple formula like "+1 +1 +2"