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

Cannot bring a attribute with formula below it's formulated result via modifiers. #91

Closed
ratacat opened this issue Jun 24, 2019 · 1 comment

Comments

@ratacat
Copy link
Contributor

ratacat commented Jun 24, 2019

In Character.js#getMaxAttribute

getMaxAttribute(attr) {
    if (!this.hasAttribute(attr)) {
      throw new RangeError(`Character does not have attribute [${attr}]`);
    }

    const attribute = this.attributes.get(attr);
    const currentVal = this.effects.evaluateAttribute(attribute);

    if (!attribute.formula) {
      return currentVal;
    }

    const { formula } = attribute;

    const requiredValues = formula.requires.map(
      reqAttr => this.getMaxAttribute(reqAttr)
    );

    return formula.evaluate.apply(formula, [attribute, this, currentVal, ...requiredValues]);
  }

evaluateAttribute (where modifiers are applied) is happening before the formula calculation. Coincidently, an attribute's value can never be lowered below the level calculated by the formula when using modifiers. For instance, having a calculated attribute called dodge, that requires reflexes, dexterity. With a certain set of stats, it has a base value of 7. If you were to apply this modifier on a stun effect to it.

      attributes: {
          dodge: function(current){
            return current * 0;
          }

      }

getMaxAttribute('dodge') will still return a value of 7. Seems like it would be better to calculate the formula first, and then evaluateAttribute? Maybe there's repercussions of that I'm not seeing?

@shawncplus
Copy link
Member

shawncplus commented Jun 24, 2019

Let's assume we have a computed "speed" attribute with the formula: (dex * 2).

Evaluate first:

dex: 5
dex effect of +2 dex
evaluate:  (5 + 2) = 7
formulate: (7 * 2) = 14

Formulate first:

dex: 5
dex effect of +2 dex
formulate: (5 * 2)  = 10
evaluate:  (10 + 2) = 12

That's the difference. But it's kind of irrelevant to the actual heart of the problem.

Using an effect like stunned to try to zero out a value is a dangerous game. Effects do not have priorities which means that even if your stunned effect modifier worked to zero out the value another effect could come along and just add +10 to it. Which, if the character is stunned, doesn't make much sense that they're stunned but still have 10 dodge.

Stunned in this case is a modal state which should be its own separate attribute and its on/off state should be used in the dodge formula. Then you can do something like:

fn: function (character, dodge, dexterity, stunned) {
  return stunned ? 0 : (dexterity * 2) + dodge;
}

Attribute formulas are supposed to be ran after effects are evaluated for the reason that a computed attribute is defined by its formula, the formula is the ultimate source of truth on the value.

I'd say the real takeaway from this is that the attribute documentation needs a section on modal character states like stunned. And also making it absolutely clear that effect attribute modifiers should not use multiplication for this exact reason.

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

No branches or pull requests

2 participants