Paragon: give class 12 intrinsic AP and SP scaling from stats

Stock 3.3.5 hardcodes per-class stat -> AP/SP formulas in
Player::UpdateAttackPowerAndDamage and Unit::SpellBase{Damage,Healing}BonusDone,
so class 12 fell into the default branches and ended up with 0 AP and 0 SP
regardless of STR / AGI / INT / SPI. The character sheet, combat log, and
ability damage all reflected this, and Mental Quickness-style AP->SP plumbing
silently no-oped on Paragon characters.

Add Paragon-specific branches in core (no PlayerScript hooks - those caused
SIGSEGVs when the new mid-list enum entry shifted later hook ordinals and
broke vtable dispatch):

- StatSystem.cpp: melee and ranged AP = level*2 + STR + AGI - 20, mirroring
  the formula the UI patch already advertises in tooltips.
- Unit.cpp:       intrinsic SP    = level*2 + INT + SPI - 20 (clamped >=0),
  added symmetrically to SpellBaseDamageBonusDone and
  SpellBaseHealingBonusDone so the single advertised Spell Power value the
  character sheet renders matches what spells actually use in combat.

Drop the now-unused UnitDefines.h include in Paragon_SC.cpp - it was only
needed by the AP PlayerScript hook that was rolled back in favor of the
core change.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Docker Build
2026-05-09 20:39:23 -04:00
parent 34cc87a5f9
commit 8abd40f217
3 changed files with 40 additions and 1 deletions
@@ -385,6 +385,13 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
break;
}
}
else if (getClass() == CLASS_PARAGON)
{
// Fractured class 12: same hybrid curve as requested for Paragon UI
// (level*2 + AGI + STR - 20). Implemented in core so we do not rely
// on PlayerScript hooks in this hot path.
val2 = level * 2.0f + GetStat(STAT_AGILITY) + GetStat(STAT_STRENGTH) - 20.0f;
}
else
{
val2 = GetStat(STAT_AGILITY) - 10.0f;
@@ -481,6 +488,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
break;
}
}
else if (getClass() == CLASS_PARAGON)
{
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
}
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
{
val2 = GetStat(STAT_STRENGTH) - 10.0f;