#Function term returning a dice roll

1 messages · Page 1 of 1 (latest)

bleak pivot
#

Starting a thread to not make this even more confusing.

One failed attempt demonstrated here: #dev-support message

To reiterate the goal: a function that returns a dice roll and that dice roll is VISIBLE to the produced roll.

Current challenges are:

  • Function term does not in fact support non-number return value
  • Function term does not offer a way for a roll rolled in the function handler to persist, only its result.
  • And the function term has no knowledge of the evaluation options to do maximize/minimize as requested while the roll is wholly under the function's control.

This generally seems to mean the function needs to generate the roll but somehow pass its evaluation back to the function term calling it for farther evaluation. Or the called fucntion needs to somehow be able to modify the function term via this which gives it access to it (modifying this.rolls is what gave the third roll so far)

#

My next experiment without any guidance will I guess be to see if adding the new roll as a term instead will work. Tho I believe I need to recreate the formula generation (via .formula) to omit that new term.

#

Though that still fails not matching the eval options, so not sure how to solve that.

topaz raft
#

Doesn't really make sense since dice is a getter, so it should always retrieve all dice terms dynamically. You can ignore the value of Roll#_dice for now, since it's concated, so even if it's empty it shouldn't matter.

bleak pivot
#

Roll.dice however doesn't return the .dice from the terms.

topaz raft
#

Maybe it changed in v13? This is the definition for Roll#dice:

get dice() {
  return this._dice.concat(this.terms.flatMap(t => {
    const dice = [];
    dice.push(...(t.dice ?? []));
    if ( t instanceof DiceTerm ) dice.push(t);
    return dice;
  }));
}
#

dice.push(...(t.dice ?? [])); will add the dice from the terms, no?

bleak pivot
#

So one would hope, yet

#

We might have an override there actually, I need to check that.

topaz raft
#

Yeah, like I said, it doesn't make sense

bleak pivot
#

Ah, yes, our roll had override for v11 and prior problems.

#

And that was it. Need to clean up the old hacky fixes.

#

Okay, it's starting to work better. A lot of hacky code tho.

#

This is the function the function term calls.

function sizeRollFn(count, sides, target, initial) {
  /** @type {Die[]|NumericTerm[]} */
  const [rt] = sizeRoll(count, sides, target, initial);

  this.terms.push(rt.formula);

  if (rt instanceof foundry.dice.terms.Die) {
    const roll = Roll.defaultImplementation.fromTerms([rt]);
    roll.options.final = true;
    this.rolls.push(roll);
    return 0; // The roll can not be evaluated here due to lacking eval opts.
  }
  // NumericTerm
  else {
    return rt.number;
  }
}
#

And this is the function term override

/**
 * Function Term override to support sizeRoll
 */
export class FunctionTermPF extends CONFIG.Dice.termTypes.FunctionTerm {
  /** @override */
  get expression() {
    // Evaluated sizeRoll has extra term to store the roll in
    if (this._evaluated && this.fn === "sizeRoll") {
      const terms = [...this.terms];
      terms.pop(); // Remove the result
      return `sizeRoll(${terms.join(",")})`;
    }
    return super.expression;
  }

  /** @override */
  get isDeterministic() {
    if (this.fn === "sizeRoll") return false; // sizeRoll is never deterministic
    return super.isDeterministic;
  }

  /** @override */
  _evaluateSync(options = {}) {
    super._evaluateSync(options);
    if (this.fn === "sizeRoll") {
      const result = this.rolls.at(-1);
      result.evaluateSync(options);
      this.result = result.total;
    }
    return this;
  }

  /** @override */
  async _evaluateAsync(options = {}) {
    await super._evaluateAsync(options);
    if (this.fn === "sizeRoll") {
      const result = this.rolls.at(-1);
      await result.evaluate(options);
      this.result = result.total;
    }
    return this;
  }
}
#

Now I just need to figure out why chat messages don't show the dice with this when I click on them and it might be fully solved.

#

Looks like something is converting the function term to die term with corrupt data.

topaz raft
#

For chat messages, that's where _dice is used

bleak pivot
#

The test for me is making the function term generate 3d6, but the chat message's roll has 1d6 with empty results array.

#

The roll in the chat message has empty _dice, still, but the dice getter shows the corrupt die.

#

Whatever transforms the function term into a die term anyway?

topaz raft
#

I would call roll.toJSON() and take a look at the output to see if anything looks suspect

#

For chat messages the roll is serialised with toJSON and then deserialised when the chat message is initialised with Roll.fromJSON (which calls Roll.fromData)

#

So the problem is somewhere in that serialise/deserialise pipeline

bleak pivot
#

The toJSON() looks correct

#

But calling toMessage() on that same roll..

#

We have no parsing overrides.

topaz raft
#

Seems it's being deserialised as a Die instead of a FunctionTerm?

bleak pivot
#

Which gave me an idea and it solved that.

  CONFIG.Dice.termTypes.FunctionTerm = pf1.dice.terms.base.FunctionTermPF;
+ CONFIG.Dice.termTypes.FunctionTermPF = pf1.dice.terms.base.FunctionTermPF;
#

So unknown terms are shunted to dice I guess?

topaz raft
#

Yeah

#

You could have toJSON report its class as FunctionTerm I suppose

#

And then it will be instantiated as a FunctionTermPF again anyway due to the override

bleak pivot
#

I think I'll go that way instead. Slightly cleaner looking and the aliasing is more in context.

bleak pivot
#

Okay, it's pretty good now. Needed to just propagate the flavor to the result and few tweaks.

Still for best QoL the function wouldn't be shown in the chat card like that, but it's not required for it to function.

Thanks for the assistance, @topaz raft