Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for searching nested dice #31

Merged
merged 3 commits into from Sep 18, 2023
Merged

Conversation

eturino
Copy link
Contributor

@eturino eturino commented Sep 18, 2023

fixes damage rolls in PF2e not being triggered. #28

For each roll we’ll not only look if the term is a Die but also see if the non-die term answers to term.dice, in which case we’ll recursively look for the dice in there.

This solves issues in the cases where we have special Roll types that don’t conform usual pattern of a straight formula.

An example is a damage roll in Pathfinder 2e (or spell damage, or crit…) where without this option enabled, unfulfilled-rolls will not be able to act on them.

Also adding .history to gitignore to avoid issues with VS Code history plugin.

fixes damage rolls in PF2e not being triggered. foundryvtt#28

Adds an optional configuration to search for nested dice. With it is turned on, for each `roll` we’ll not only look if the term is a `Die` but also see if the non-die term answers to `term.dice`, in which case we’ll recursively look for the dice in there.

This solves issues in the cases where we have special Roll types that don’t conform usual pattern of a straight formula.

An example is a damage roll in Pathfinder 2e (or spell damage, or crit…) where without this option enabled, `unfulfilled-rolls` will not be able to act on them.

Also adding `.history` to gitignore to avoid issues with VS Code history plugin.
* @param {RollTerm[]} terms Terms of the Roll instance
* @param {object} config The unfulfilled-rolls.diceSettings configuration
* @returns {FulfillableTerm[]} An array of identified terms
* @private
*/
function _identifyFulfillableTerms(terms, config) {
const toFulfill = [];
for ( const [i, term] of terms.entries() ) {
const diceTerms = terms.flatMap(t => _diceFromRollTerm(t, !!config.searchNestedDice));
Copy link
Contributor

@aaclayton aaclayton Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is right, we need to iterate over dice terms and recursively handle terms which contain inner dice.

This implementation fully iterates first, however, to create const diceTerms rather than recursively evaluating terms as we go. This results in us iterating over all terms twice, instead of just once.

A better way to do this will be something like this:

function function _identifyFulfillableTerms(terms, config, toFulfill=[]) {
  for ( const term of diceTerms ) {
    if ( !(term instanceof Die) ) continue;
    if ( this._fulfilled?.length > 0 ) continue; // already fulfilled
    const method = config[`d${term.faces}`];
    if ( !method || (method === "fvtt") ) continue;
    toFulfill.push({term, method, terms, index: toFullfill.length-1});

    // Recursively identify inner terms
    if ( "dice" in term ) {
      _identifyFulfillableTerms(term.dice, config, toFulfill);
    }
  }
  return toFulfill;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

happy to change that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to avoid modifying the interface of this function though, I think it'll probably be better to make the extraction inside, avoiding exposing toFulfill as an argument. I'll change the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a private function, change whatever you need to change to have the cleanest implementation.

@@ -18,6 +18,14 @@
{{/each}}
</section>

<section>
<div class="form-group">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this should be a setting. Feels to me like this should just be the default behavior. Do you have use cases in mind where the user would not want to identify inner terms as fulfillable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I added this as an opt-in so that the exceptional behaviour would be executed only in pf2e and potentially other cases, to prevent from potential issues in other systems that I had not encountered. If you are happy to make this the default behaviour, I'll gladly make it so.

@aaclayton
Copy link
Contributor

Thanks for the contribution @eturino. I have a few comments for you to consider!

- avoid opt-in behaviour, make this the default behaviour all the time
- avoid double iterations.
@eturino
Copy link
Contributor Author

eturino commented Sep 18, 2023

@aaclayton went with your suggestions, fixing some issues. Please have a look.

By making the 2 internal private functions for identifyTerm() and for running the extraction, we could extend this in the future with new behaviour as needed.

if ( !method || (method === "fvtt") ) continue;
toFulfill.push({term, method, index: i});
if ( method && (method !== "fvtt") ) {
fulfillableTerms.push({term, method, index});
Copy link
Contributor

@aaclayton aaclayton Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code generally looks good, but ...

I think it's a problem that we would end up with multiple elements in fulfillableTerms with the same index. We need to create a unique name for the HTML element which allows us to identify which user input result belongs to which term. As currently designed we could end up with, for example, two different d6 terms each with index: 0 which would result in the same name.

I have not tested this, but I think you would replicate the issue with something like:

/roll 1d6 + {1d6, 1d6}kh + (1d6 + 3)

You would end up with 3 different d6 terms all with index: 0

Probably we should just use the actual index position in fulfillableTerms as the simplest solution. Do you understand what I am highlighting with this concern?"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes indeed. This wasn't an issue in my original approach because of the double loop. I'll fix in a bit.

Copy link
Contributor Author

@eturino eturino Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went with using as index the length of the array before pushing. That way we keep the index property of the fulfillable terms objects, and avoid depending on the order of the array for identification. I can see a future where we would want to allow the user to opt-in to sort the dice by type when exposed to the user for example (all d10s together, then all d12s…), which would mean reordering the elements of the array. Better to not depend on that order for identification.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works for me!

less changes than removing the index altogether and relying on the order of the array
@aaclayton aaclayton self-requested a review September 18, 2023 17:56
Copy link
Contributor

@aaclayton aaclayton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, thank you @eturino!

@aaclayton aaclayton merged commit fb00a53 into foundryvtt:master Sep 18, 2023
@eturino eturino deleted the nested-dice branch September 19, 2023 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants