<commit_before>import { formatNumber, formatThousands } from 'common/format';
import SPELLS from 'common/SPELLS';
import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events, { DamageEvent } from 'parser/core/Events';
import BoringSpellValueText from 'parser/ui/BoringSpellValueText';
import Statistic from 'parser/ui/Statistic';
import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY';
import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER';

class DampenHarm extends Analyzer {
  hitsReduced = 0;
  damageReduced = 0;
  constructor(options: Options) {
    super(options);
    if (!this.selectedCombatant.hasTalent(SPELLS.DAMPEN_HARM_TALENT.id)) {
      this.active = false;
      return;
    }
    this.addEventListener(Events.damage.to(SELECTED_PLAYER), this.damageReduction);
  }

  damageReduction(event: DamageEvent) {
    if (event.ability.guid !== SPELLS.STAGGER_TAKEN.id) {
      if (this.selectedCombatant.hasBuff(SPELLS.DAMPEN_HARM_TALENT.id)) {
        this.hitsReduced += 1;
        const h = event.amount || 0;
        const a = event.absorbed || 0;
        const o = event.overkill || 0;
        // TODO: ACTUAL MAX HP TRACKING
        // event.maxHitPoints is insufficient as many events such as SPELL_ABSORBED are missing it and Keg of the Heavens is cursed.
        const maxHP = event.maxHitPoints || 0;
        const hitSize = h + a + o;
        if (maxHP > 0) {
          let drdh = 0;
          // given 1 - u / h = 0.2 + 0.3 * u, where u = hit size after all other dr effecs, h = current max hp
          // the following can be then produced algebraically:
          if (hitSize >= maxHP / 2) {
            drdh = 0.5;
          } else {
            drdh = 0.6 - 0.5 * Math.sqrt(0.64 - (6 * hitSize) / (5 * maxHP));
          }
          this.damageReduced += hitSize / (1 - drdh) - hitSize;
        }
      }
    }
  }

  statistic() {
    return (
      <Statistic
        position={STATISTIC_ORDER.OPTIONAL()}
        size="flexible"
        category={STATISTIC_CATEGORY.TALENTS}
      >
        <BoringSpellValueText spellId={SPELLS.DAMPEN_HARM_TALENT.id}>
          {formatNumber(this.hitsReduced)} hits were reduced for a total of{' '}
          {formatThousands(this.damageReduced)} damage reduced.
        </BoringSpellValueText>
      </Statistic>
    );
  }
}

export default DampenHarm;<commit_msg>Removed nested if, added more accurate solution for max HP tracking, but still not guaranteed to be correct.<commit_after>import { formatNumber, formatThousands } from 'common/format';
import SPELLS from 'common/SPELLS';
import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events, { DamageEvent } from 'parser/core/Events';
import BoringSpellValueText from 'parser/ui/BoringSpellValueText';
import Statistic from 'parser/ui/Statistic';
import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY';
import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER';

class DampenHarm extends Analyzer {
  hitsReduced = 0;
  damageReduced = 0;
  skip = 0;
  currentMaxHP = 0;

  constructor(options: Options) {
    super(options);
    if (!this.selectedCombatant.hasTalent(SPELLS.DAMPEN_HARM_TALENT.id)) {
      this.active = false;
      return;
    }
    this.addEventListener(Events.damage.to(SELECTED_PLAYER), this.updateMaxHP);
    this.addEventListener(Events.resourcechange.by(SELECTED_PLAYER), this.updateMaxHP);
    this.addEventListener(Events.drain.by(SELECTED_PLAYER), this.updateMaxHP);
    this.addEventListener(Events.damage.to(SELECTED_PLAYER), this.damageReduction);
  }

  damageReduction(event: DamageEvent) {
    if (event.ability.guid === SPELLS.STAGGER_TAKEN.id) {
      return;
    }
    if (this.selectedCombatant.hasBuff(SPELLS.DAMPEN_HARM_TALENT.id)) {
      this.hitsReduced += 1;
      const h = event.amount || 0;
      const a = event.absorbed || 0;
      const o = event.overkill || 0;
      // TODO: ACTUAL MAX HP TRACKING
      // event.maxHitPoints is insufficient as many events such as SPELL_ABSORBED are missing it and Keg of the Heavens is cursed.
      const maxHP = event.maxHitPoints || this.currentMaxHP;
      const hitSize = h + a + o;
      let drdh = 0;
      // given 1 - u / h = 0.2 + 0.3 * u, where u = hit size after all other dr effecs, h = current max hp
      // the following can be then produced algebraically:
      if (hitSize >= maxHP / 2) {
        drdh = 0.5;
      } else {
        drdh = 0.6 - 0.5 * Math.sqrt(0.64 - (6 * hitSize) / (5 * maxHP));
      }
      this.damageReduced += hitSize / (1 - drdh) - hitSize;
    }
  }

  updateMaxHP(event: any) {
    this.currentMaxHP = event.maxHitPoints || this.currentMaxHP;
    console.log(event);
  }

  statistic() {
    return (
      <Statistic
        position={STATISTIC_ORDER.OPTIONAL()}
        size="flexible"
        category={STATISTIC_CATEGORY.TALENTS}
      >
        <BoringSpellValueText spellId={SPELLS.DAMPEN_HARM_TALENT.id}>
          {formatNumber(this.hitsReduced)} hits were reduced for a total of{' '}
          {formatThousands(this.damageReduced)} damage reduced.
        </BoringSpellValueText>
      </Statistic>
    );
  }
}

export default DampenHarm;
{'fraction_non_alphanumeric': 0.11171240819482026, 'fraction_numerical': 0.010436799381522999, 'mean_word_length': 2.888054094665665, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3929422', 'n_tokens_mistral': 1777, 'n_tokens_neox': 1729, 'n_words': 400}