mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-10 20:07:37 +00:00
feat(spell): count set bonuses in GetSpellBonusHealing
Set-bonus spells are applied server-side as auras the client never sees as buffs or known spells, so the derived healing sum missed them — Lawbringer (3) is "Increase Healing 31" (9317), Judgement (3) is 57 (18037). Add a pass that counts the equipped members of each set from the item record's set id (OFF_ITEMSTATS_ITEM_SET), reads ItemSet.dbc's bonus spells and member thresholds, and runs every met bonus through the same aura decoder — the rule the item tooltip's set-bonus lines use at 0x52DFB9. The Ironclad (aura 199) armor conversion stays on UNIT_FIELD_RESISTANCES[0]: the server's SpellBaseHealingBonusDone uses GetArmor(), the full total, even though the talent text says "Armor from items". Refs #135
This commit is contained in:
+4
-1
@@ -21617,8 +21617,11 @@ GetSpellBonusHealing() -- your +Healing
|
||||
> Turtle customs) and exact — e.g. Spiritual Guidance 5/5 with 182 Spirit
|
||||
> adds `int(182 × 25 / 100) = 45`.
|
||||
>
|
||||
> Set bonuses count: a bonus whose piece count your equipped gear meets
|
||||
> (for example Lawbringer's 3-piece +31 Healing) is included.
|
||||
>
|
||||
> Residual: assumes talent ranks supersede (only the learned rank is known)
|
||||
> and misses set-bonus healing granted via a set-completion spell.
|
||||
> and ignores a set's profession-skill requirement.
|
||||
|
||||
### `GetCritChance()` / `GetRangedCritChance()`
|
||||
|
||||
|
||||
@@ -53,8 +53,12 @@
|
||||
// +15%/rank SpellMod), so an 18-point gap leaked into healing when that pure
|
||||
// +damage buff was gained. Reading aura 175 directly (above) sidesteps it.
|
||||
//
|
||||
// 3. Set bonuses — the bonus spells of every equipped set whose member
|
||||
// count is met (ItemSet.dbc, the same rule the tooltip's set-bonus
|
||||
// lines use), decoded through the same aura walk.
|
||||
//
|
||||
// Residual: assumes talent ranks supersede (only the learned rank is known —
|
||||
// otherwise summed) and misses set-bonus healing granted via a set spell.
|
||||
// otherwise summed) and ignores a set's profession-skill requirement.
|
||||
|
||||
#include "Game.h"
|
||||
#include "Offsets.h"
|
||||
@@ -185,11 +189,52 @@ void AddSpellHealingAuras(long &total, int spellID, int32_t spirit,
|
||||
}
|
||||
}
|
||||
|
||||
// Set bonuses the equipped gear has earned. The engine's own set-bonus lines
|
||||
// (the item tooltip, 0x52DFB9..) count how many of the set's members the
|
||||
// player has equipped and light a bonus whose member count (ItemSet.dbc
|
||||
// `+0x8C`) is met; the server applies the same bonus spells as auras. Those
|
||||
// auras are neither buffs nor known spells, so this is the only pass that
|
||||
// sees them — Lawbringer (3) is "Increase Healing 31", Judgement (3) is 57.
|
||||
// A set member's record names its set (`OFF_ITEMSTATS_ITEM_SET`), so the
|
||||
// equipped count per set is the equipped members' count.
|
||||
constexpr int kEquipSlots = 19;
|
||||
|
||||
void AddSetBonusHealing(long &total, int32_t spirit, int32_t armor) {
|
||||
struct Worn { uint32_t setID; int count; };
|
||||
Worn worn[kEquipSlots];
|
||||
int sets = 0;
|
||||
for (int slot = 1; slot <= kEquipSlots; ++slot) {
|
||||
const int itemID = Item::ID::FromCGItem(Item::Location::ResolveEquipmentSlot(slot));
|
||||
const uint8_t *record = itemID > 0 ? Item::PeekRecord(static_cast<uint32_t>(itemID)) : nullptr;
|
||||
const uint32_t setID = record ? Game::Read<uint32_t>(record, Offsets::OFF_ITEMSTATS_ITEM_SET) : 0;
|
||||
if (setID == 0)
|
||||
continue;
|
||||
int s = 0;
|
||||
while (s < sets && worn[s].setID != setID)
|
||||
++s;
|
||||
if (s == sets)
|
||||
worn[sets++] = {setID, 0};
|
||||
++worn[s].count;
|
||||
}
|
||||
for (int s = 0; s < sets; ++s) {
|
||||
const uint8_t *set = DBC::Record(Offsets::VAR_ITEMSET_RECORDS, Offsets::VAR_ITEMSET_COUNT,
|
||||
worn[s].setID);
|
||||
if (set == nullptr)
|
||||
continue;
|
||||
auto spells = Game::Ptr<const uint32_t>(set, Offsets::OFF_ITEMSET_SPELL_IDS);
|
||||
auto needed = Game::Ptr<const uint32_t>(set, Offsets::OFF_ITEMSET_THRESHOLDS);
|
||||
for (int i = 0; i < Offsets::ITEMSET_MAX_BONUSES; ++i)
|
||||
if (spells[i] != 0 && needed[i] <= static_cast<uint32_t>(worn[s].count))
|
||||
AddSpellHealingAuras(total, static_cast<int>(spells[i]), spirit, armor,
|
||||
/*requirePassive=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
long ComputeHealing() {
|
||||
long total = 0;
|
||||
|
||||
// Items — flat +healing via the shared StatAccum engine.
|
||||
for (int slot = 1; slot <= 19; ++slot)
|
||||
for (int slot = 1; slot <= kEquipSlots; ++slot)
|
||||
total += ItemFlatHealing(Item::Location::ResolveEquipmentSlot(slot));
|
||||
|
||||
// Player Spirit / Armor for the aura-175 / aura-199 conversions.
|
||||
@@ -199,6 +244,8 @@ long ComputeHealing() {
|
||||
const int32_t armor = desc ? Game::Read<int32_t>(
|
||||
desc, Offsets::OFF_UNIT_FIELD_RESISTANCE_ARMOR) : 0;
|
||||
|
||||
AddSetBonusHealing(total, spirit, armor);
|
||||
|
||||
// Active buffs — flat healing + Spirit/Armor conversions, one pass.
|
||||
auto *table = reinterpret_cast<const uint8_t *>(
|
||||
static_cast<uintptr_t>(Offsets::VAR_PLAYER_BUFF_TABLE));
|
||||
|
||||
Reference in New Issue
Block a user