comparing fomula

Anyone know of a foundry utility to compare two strings that might be dice formulae to tell which has the lesser deterministic value?
23 Replies
Calego
Calego2y ago
🧵 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 oh i can use dnd5e's simplifyRollFormula for this if the output of simplifyRollFormula is parsable as a Number, I can compare them easily
Calego
Calego2y ago
ok wtf js
No description
Calego
Calego2y ago
oh, i'm dumb. .floor is for rounding I'm looking for .min 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(' + '));
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 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'
Mana
Mana2y ago
.evaluate({min:true, async:false}) doesn't work for you? Or did I misunderstand what you were after?
Calego
Calego2y ago
is that a method on Roll?
Mana
Mana2y ago
Yes.
Calego
Calego2y ago
min would return the minimum possible based on the formula provided?
Mana
Mana2y ago
Yes. It sets the dice to minimum value they'd give instead of randomizing them and returns the result.
Calego
Calego2y ago
gotcha, not quite what i'm looking for I'm really looking to compare two formulas, and use the 'min' one (but only if they're deterministic)
Mana
Mana2y ago
Roll.isDeterministic is a thing It also exists for individual terms. That is available pre-eval
Calego
Calego2y ago
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());
);
}
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());
);
}
Mana
Mana2y ago
Almost, .isDeterministic is a getter. And .evaluate() returns Roll instance, so you'd need to add .total there. Also eval is async unless you tell it to be non-async.
Calego
Calego2y ago
that async:false is being deprecated right? I could probably DIY that actually if isDeterministic is true jk not as easy i expected in js
Mana
Mana2y ago
People keep saying it's not. The requirement for it is, because async is becoming the default. And there's no warning in it that sync option is going away, just that it won't be the default.
Calego
Calego2y ago
goootcha
Mana
Mana2y ago
Anyway, you'd have this:
if (formulaA.isDeterministic && formulaB.isDeterministic) {
spellAttackModFormula.push(
Math.min(formulaA.evaluate({async:false}).total, formulaB.evaluate({async:false}.total));
);
}
if (formulaA.isDeterministic && formulaB.isDeterministic) {
spellAttackModFormula.push(
Math.min(formulaA.evaluate({async:false}).total, formulaB.evaluate({async:false}.total));
);
}
Calego
Calego2y ago
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
Mana
Mana2y ago
I'd favor whichever makes the intent of the code clearer.
Calego
Calego2y ago
// 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))
);
}
}
// 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 @manaflower
Leo The League Lion
@calego gave vote LeaguePoints™ to @manaflower (#15 • 203)
Calego
Calego2y ago
🎉
No description
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Calego
Calego2y ago
External constraint, could be a simple formula like "+1 +1 +2"