Zakarik / foundry-mm3

5 stars 3 forks source link

Incorrect Calculation of Injuries #64

Closed Twalord closed 5 months ago

Twalord commented 5 months ago

Hi, I have been testing out the system and found an issue in how characters automatically receive injuries when comparing it against the M&M 3e rules.

When performing an attack with a damage effect on a target, the target should make a toughness check to resist receiving an injury, becoming dazed, staggered or even incapacitated. See Damage Resistance Check here for comparison: https://www.d20herosrd.com/6-powers/effects/effect-descriptions/damage-attack/

Currently, the target roles the toughness check against the base defense value set in the attack, for toughness typically 15. If the role is a fail, the target receives additional injuries equal to the attack damage.

This is incorrect behavior, the attack damage should add to the difficulty of the toughness check to resist the injuries and not the number of injuries itself. Typically, a character can receive only a single injury from an attack.

I tracked down this behavior in the code and found it in the function rollVs in https://github.com/Zakarik/foundry-mm3/blob/main/module/helpers/common.mjs#L2057

To fix the toughness check DC: The DC for the damage resist check needs to also include the attacks damage both in the calculation and in the display. Calculation: https://github.com/Zakarik/foundry-mm3/blob/main/module/helpers/common.mjs#L2077 Display: https://github.com/Zakarik/foundry-mm3/blob/main/module/helpers/common.mjs#L2091

I tested the change with this dirty fix and it showed the correct behavior in the game.

//Inserted damage of attacker via Number(dataAtk.dmgechec.v1)
  const dataAtk2 = data.atk;
  let damageVal = Number(dataAtk2.dmgechec.v1);
  let toRoll = mod === 0 ? `${optDices.dices} + ${score}` : `${optDices.dices} + ${score} + ${mod}`;

  const save = new Roll(toRoll);
  save.evaluate({async:false});

  const typeAtk = data?.typeAtk ?? false;
  const saveTotal = Number(save.total);
  const saveDices = saveTotal-score;
  const isCritique = saveDices === optDices.critique ? true : false;
  //Added damageVal to vs
  const margeBrut = (vs+damageVal)-saveTotal;
  const hasMarge = margeBrut >= 0 && !isCritique ? true : false;
  const marge = margeBrut >= 0 && !isCritique ? Math.floor(margeBrut / 5)+1 : false;
  let isSuccess = false;

  if(isCritique) isSuccess = true;
  else if(margeBrut < 0) isSuccess = true;

  const pRollSave = {
    flavor:name === "" ? " - " : `${name}`,
    tooltip:await save.getTooltip(),
    formula:mod === 0 ? `${optDices.formula} + ${score}` : `${optDices.formula} + ${score} + ${mod}`,
    result:save.total,
    isCritique:isCritique,
    /Added damageVal to vs
    vs:vs+damageVal,
    isSuccess:isSuccess,
    hasMarge:hasMarge,
    resultMarge:marge,
    successOrFail:'fail',
  };

To fix the numbers of injuries I also tested a dirty fix that removes the damage value from the calculation.

//Set injuries (blessure) to always increase by one instead of by damage value
      if(marge === 1) {
        blessures[`system.blessure`] = blessure+1;
      } else if(marge === 2) {
        blessures[`system.blessure`] = blessure+1;
        listEtats.push(allEtats.find(eta => eta.id === 'dazed'));
      } else if(marge === 3 && !hasStatus(actor, 'chanceling')) {
        blessures[`system.blessure`] = blessure+1;
        listEtats.push(allEtats.find(eta => eta.id === 'chanceling'));
      } else if(marge >= 3) {
        listEtats.push(allEtats.find(eta => eta.id === 'neutralized'));
      }

It should be noted that this removes the usage of dataAtk.dmgechec.v2 and dataAtk.dmgechec.v3.

This should align the behavior of the game with the game rules. I made these changes from my understanding, as M&M is a relatively complex game, I might have misunderstood the rules.

Twalord commented 5 months ago

After testing around a bit more, I found that the first code snippet breaks affliction type attacks, which should use the base value, typically 10, plus the rank of the affliction ability as the DC, according to https://www.d20herosrd.com/6-powers/effects/effect-descriptions/affliction-attack/

Zakarik commented 5 months ago

I confess I didn't really understand.

I did some more tests and checked the book.

The roll to be made is against a DC of 15 + rank of the effect, which is currently the case, as the screenshots show.

image image

The target only suffers one wound per attack, but can suffer additional effects depending on the degree of failure.

Twalord commented 5 months ago

Ah those screenshots really helped me understand it.

From the wording in the role book I had assumed that the damage value would be used to increase the Toughness check against an injury but in your implementation the effect value is used instead.

So if there is not supposed to by any additional effect from an attack the damage value can just be left at 1 so it can cause up to 1 injury.

Thank you for clarifying. I will close this issue as there is nothing wrong with your code I just misunderstood these fields.