Core/Units: moved base stats handling into a own class
This commit is contained in:
1 parent
c1c7dc5ef9
commit
af40c9404b
22 files changed
+628
-600
No files matched your search
@@ -631,7 +631,15 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE]));
|
||||
|
||||
SetCanModifyStats(true);
|
||||
UpdateAllStats();
|
||||
|
||||
UpdateMaxHealth();
|
||||
UpdateAttackPowerAndDamage();
|
||||
UpdateAttackPowerAndDamage(true);
|
||||
|
||||
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
|
||||
UpdateMaxPower(PowerType(i));
|
||||
|
||||
UpdateAllResistances();
|
||||
}
|
||||
|
||||
// checked and error show at loading templates
|
||||
|
||||
@@ -194,8 +194,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
|
||||
bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr, bool updateLevel = true);
|
||||
|
||||
bool UpdateStats(StatType stat) override;
|
||||
bool UpdateAllStats() override;
|
||||
void UpdateResistances(uint32 school) override;
|
||||
void UpdateArmor() override;
|
||||
void UpdateMaxHealth() override;
|
||||
|
||||
@@ -380,7 +380,7 @@ bool Minion::IsWarlockMinion() const
|
||||
Guardian::Guardian(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject) : Minion(properties, owner, isWorldObject)
|
||||
, m_bonusSpellDamage(0)
|
||||
{
|
||||
memset(m_statFromOwner, 0, sizeof(float)*MAX_STATS);
|
||||
memset(m_statFromOwner, 0, sizeof(float)*AsUnderlyingType(StatType::Max));
|
||||
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
|
||||
if (properties && SummonTitle(properties->Title) == SummonTitle::Pet)
|
||||
{
|
||||
|
||||
@@ -119,8 +119,6 @@ class TC_GAME_API Guardian : public Minion
|
||||
bool InitStatsForLevel(uint8 level);
|
||||
void InitSummon() override;
|
||||
|
||||
bool UpdateStats(StatType stat) override;
|
||||
bool UpdateAllStats() override;
|
||||
void UpdateResistances(uint32 school) override;
|
||||
void UpdateArmor() override;
|
||||
void UpdateMaxHealth() override;
|
||||
@@ -129,11 +127,11 @@ class TC_GAME_API Guardian : public Minion
|
||||
void UpdateDamagePhysical(WeaponAttackType attType) override;
|
||||
|
||||
int32 GetBonusDamage() const { return m_bonusSpellDamage; }
|
||||
float GetBonusStatFromOwner(StatType stat) const { return m_statFromOwner[stat]; }
|
||||
float GetBonusStatFromOwner(StatType stat) const { return m_statFromOwner[AsUnderlyingType(stat)]; }
|
||||
void SetBonusDamage(int32 damage);
|
||||
protected:
|
||||
int32 m_bonusSpellDamage;
|
||||
float m_statFromOwner[MAX_STATS];
|
||||
float m_statFromOwner[AsUnderlyingType(StatType::Max)];
|
||||
};
|
||||
|
||||
class TC_GAME_API Puppet : public Minion
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Stats.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
#include "Group.h"
|
||||
@@ -296,7 +297,6 @@ bool Pet::LoadPetData(Player* owner, uint32 petEntry, uint32 petnumber, bool cur
|
||||
}
|
||||
|
||||
CleanupActionBar(); // remove unknown spells from action bar after load
|
||||
UpdateAllStats();
|
||||
SetFullHealth(); // Set full health and mana after pet scaling auras has been applied
|
||||
|
||||
if (IsHunterPet())
|
||||
@@ -773,25 +773,27 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
if (pInfo->armor > 0)
|
||||
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
||||
|
||||
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
|
||||
SetCreateStat(StatType(stat), float(pInfo->stats[stat]));
|
||||
for (StatType stat : AllStats)
|
||||
GetStats().SetBaseStatValue(stat, pInfo->stats[AsUnderlyingType(stat)]);
|
||||
}
|
||||
else // not exist in DB, use some default fake data
|
||||
{
|
||||
// remove elite bonuses included in DB values
|
||||
// remove elite bonuses included in DB values
|
||||
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(petlevel, cinfo->unit_class);
|
||||
CreatureBaseStats const* baseStats = sObjectMgr->GetCreatureBaseStats(petlevel, cinfo->unit_class);
|
||||
float healthmod = _GetHealthMod(cinfo->rank);
|
||||
uint32 basehp = stats->GenerateHealth(cinfo);
|
||||
uint32 basehp = baseStats->GenerateHealth(cinfo);
|
||||
uint32 health = uint32(basehp * healthmod);
|
||||
|
||||
SetCreateHealth(health);
|
||||
SetCreateMana(stats->BaseMana);
|
||||
SetCreateStat(STAT_STRENGTH, 22);
|
||||
SetCreateStat(STAT_AGILITY, 22);
|
||||
SetCreateStat(STAT_STAMINA, 25);
|
||||
SetCreateStat(STAT_INTELLECT, 28);
|
||||
SetCreateStat(STAT_SPIRIT, 27);
|
||||
SetCreateMana(baseStats->BaseMana);
|
||||
|
||||
Stats& stats = GetStats();
|
||||
stats.SetBaseStatValue(StatType::Strength, 22);
|
||||
stats.SetBaseStatValue(StatType::Agility, 22);
|
||||
stats.SetBaseStatValue(StatType::Stamina, 25);
|
||||
stats.SetBaseStatValue(StatType::Intellect, 28);
|
||||
stats.SetBaseStatValue(StatType::Spirit, 27);
|
||||
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
@@ -897,7 +899,6 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier / 14);
|
||||
|
||||
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor)
|
||||
SetStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina)
|
||||
if (!HasAura(58877)) // Spirit Hunt
|
||||
AddAura(58877, this);
|
||||
if (!HasAura(61783)) // Feral Pet Scaling
|
||||
@@ -998,8 +999,6 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAllStats();
|
||||
|
||||
SetFullHealth();
|
||||
SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
|
||||
return true;
|
||||
@@ -1876,7 +1875,7 @@ void Pet::CastPetAura(PetAura const* aura)
|
||||
args.TriggerFlags = TRIGGERED_FULL_MASK;
|
||||
|
||||
if (auraId == 35696) // Demonic Knowledge
|
||||
args.AddSpellMod(SPELLVALUE_BASE_POINT0, CalculatePct(aura->GetDamage(), GetStat(STAT_STAMINA) + GetStat(STAT_INTELLECT)));
|
||||
args.AddSpellMod(SPELLVALUE_BASE_POINT0, CalculatePct(aura->GetDamage(), GetStat(StatType::Stamina) + GetStat(StatType::Intellect)));
|
||||
|
||||
CastSpell(this, auraId, args);
|
||||
}
|
||||
|
||||
@@ -1231,10 +1231,7 @@ void Player::Update(uint32 p_time)
|
||||
if (m_petScalingSynchTimer.Passed())
|
||||
{
|
||||
if (pet)
|
||||
{
|
||||
pet->UpdatePetScalingAuras();
|
||||
pet->UpdateAllStats();
|
||||
}
|
||||
|
||||
m_petScalingSynchTimer.Reset(1000);
|
||||
}
|
||||
@@ -2232,8 +2229,8 @@ void Player::GiveLevel(uint8 level)
|
||||
packet.PowerDelta[4] = 0;
|
||||
packet.PowerDelta[5] = 0;
|
||||
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
packet.StatDelta[i] = int32(info.stats[i]) - GetCreateStat(StatType(i));
|
||||
for (StatType stat : AllStats)
|
||||
packet.StatDelta[AsUnderlyingType(stat)] = int32(info.stats[AsUnderlyingType(stat)]) - GetStats().GetBaseStatValue(stat);
|
||||
|
||||
SendDirectMessage(packet.Write());
|
||||
|
||||
@@ -2248,9 +2245,9 @@ void Player::GiveLevel(uint8 level)
|
||||
|
||||
UpdateSkillsForLevel();
|
||||
|
||||
// save base values (bonuses already included in stored stats
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
SetCreateStat(StatType(i), info.stats[i]);
|
||||
// save base values (bonuses already included in stored stats)
|
||||
for (StatType stat : AllStats)
|
||||
GetStats().SetBaseStatValue(stat, info.stats[AsUnderlyingType(stat)]);
|
||||
|
||||
SetCreateHealth(basehp);
|
||||
SetCreateMana(basemana);
|
||||
@@ -2259,7 +2256,8 @@ void Player::GiveLevel(uint8 level)
|
||||
InitTaxiNodesForLevel();
|
||||
InitGlyphsForLevel();
|
||||
|
||||
UpdateAllStats();
|
||||
UpdateAllRatings();
|
||||
UpdateAllResistances();
|
||||
|
||||
_ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms
|
||||
|
||||
@@ -2378,21 +2376,14 @@ void Player::InitStatsForLevel(bool reapplyMods)
|
||||
SetObjectScale(1.0f);
|
||||
|
||||
// save base values (bonuses already included in stored stats
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
SetCreateStat(StatType(i), info.stats[i]);
|
||||
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
SetStat(StatType(i), info.stats[i]);
|
||||
for (StatType stat : AllStats)
|
||||
GetStats().SetBaseStatValue(stat, info.stats[AsUnderlyingType(stat)]);
|
||||
|
||||
SetCreateHealth(basehp);
|
||||
|
||||
//set create powers
|
||||
SetCreateMana(basemana);
|
||||
|
||||
SetArmor(int32(m_createStats[STAT_AGILITY]*2));
|
||||
|
||||
InitStatBuffMods();
|
||||
|
||||
//reset rating fields values
|
||||
for (uint16 index = PLAYER_FIELD_COMBAT_RATING_1; index < PLAYER_FIELD_COMBAT_RATING_1 + MAX_COMBAT_RATING; ++index)
|
||||
SetUInt32Value(index, 0);
|
||||
@@ -2451,8 +2442,6 @@ void Player::InitStatsForLevel(bool reapplyMods)
|
||||
// Dodge percentage
|
||||
SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0f);
|
||||
|
||||
// set armor (resistance 0) to original value (create_agility*2)
|
||||
SetArmor(int32(m_createStats[STAT_AGILITY]*2));
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
|
||||
// set other resistance to original value (0)
|
||||
@@ -4875,8 +4864,8 @@ float Player::GetMeleeCritFromAgility() const
|
||||
if (critBase == nullptr || critRatio == nullptr)
|
||||
return 0.0f;
|
||||
|
||||
float crit = critBase->base + GetStat(STAT_AGILITY)*critRatio->ratio;
|
||||
return crit*100.0f;
|
||||
float crit = critBase->base + GetStat(StatType::Agility) * critRatio->ratio;
|
||||
return crit * 100.0f;
|
||||
}
|
||||
|
||||
void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) const
|
||||
@@ -4934,8 +4923,8 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) cons
|
||||
if (!dodgeRatio || playerClass > MAX_CLASSES)
|
||||
return;
|
||||
|
||||
float baseAgility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + AsUnderlyingType(STAT_AGILITY)), BASE_PCT);
|
||||
float bonusAgility = GetStat(STAT_AGILITY) - baseAgility;
|
||||
int32 baseAgility = GetStats().GetBaseStatValue(StatType::Agility);
|
||||
int32 bonusAgility = GetStat(StatType::Agility) - baseAgility;
|
||||
|
||||
// calculate diminishing (green in char screen) and non-diminishing (white) contribution
|
||||
diminishing = 100.0f * bonusAgility * dodgeRatio->ratio * critToDodge[playerClass -1 ];
|
||||
@@ -4955,7 +4944,7 @@ float Player::GetSpellCritFromIntellect() const
|
||||
if (critBase == nullptr || critRatio == nullptr)
|
||||
return 0.0f;
|
||||
|
||||
float crit = critBase->base + GetStat(STAT_INTELLECT) * critRatio->ratio;
|
||||
float crit = critBase->base + GetStat(StatType::Intellect) * critRatio->ratio;
|
||||
return crit * 100.0f;
|
||||
}
|
||||
|
||||
@@ -7464,24 +7453,34 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
|
||||
break;
|
||||
case ITEM_MOD_AGILITY: // modify agility
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Agility, val);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Agility, val);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH: //modify strength
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Strength, val);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Strength, val);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT: //modify intellect
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Intellect, val);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Intellect, val);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT: //modify spirit
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Spirit, val);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Spirit, val);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA: //modify stamina
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Stamina, val);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Stamina, val);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply);
|
||||
@@ -12646,24 +12645,34 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply)
|
||||
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, -removeValue, apply);
|
||||
break;
|
||||
case ITEM_MOD_AGILITY:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, -removeValue, apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
if (apply)
|
||||
GetStats().RemoveBaseStatModifier(StatType::Agility, removeValue);
|
||||
else
|
||||
GetStats().AddBaseStatModifier(StatType::Agility, removeValue);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, -removeValue, apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
if (apply)
|
||||
GetStats().RemoveBaseStatModifier(StatType::Strength, removeValue);
|
||||
else
|
||||
GetStats().AddBaseStatModifier(StatType::Strength, removeValue);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, -removeValue, apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
if (apply)
|
||||
GetStats().RemoveBaseStatModifier(StatType::Intellect, removeValue);
|
||||
else
|
||||
GetStats().AddBaseStatModifier(StatType::Intellect, removeValue);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, -removeValue, apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
if (apply)
|
||||
GetStats().RemoveBaseStatModifier(StatType::Spirit, removeValue);
|
||||
else
|
||||
GetStats().AddBaseStatModifier(StatType::Spirit, removeValue);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, -removeValue, apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
if (apply)
|
||||
GetStats().RemoveBaseStatModifier(StatType::Stamina, removeValue);
|
||||
else
|
||||
GetStats().AddBaseStatModifier(StatType::Stamina, removeValue);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, -int32(removeValue), apply);
|
||||
@@ -12762,24 +12771,34 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply)
|
||||
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, addValue, apply);
|
||||
break;
|
||||
case ITEM_MOD_AGILITY:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, addValue, apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Agility, addValue);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Agility, addValue);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, addValue, apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Strength, addValue);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Strength, addValue);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, addValue, apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Intellect, addValue);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Intellect, addValue);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, addValue, apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Spirit, addValue);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Spirit, addValue);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA:
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, addValue, apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Spirit, addValue);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Spirit, addValue);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, int32(addValue), apply);
|
||||
@@ -13042,28 +13061,38 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
break;
|
||||
case ITEM_MOD_AGILITY:
|
||||
TC_LOG_DEBUG("entities.player.items", "+ %u AGILITY", enchant_amount);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Agility, enchant_amount);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Agility, enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH:
|
||||
TC_LOG_DEBUG("entities.player.items", "+ %u STRENGTH", enchant_amount);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Strength, enchant_amount);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Strength, enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT:
|
||||
TC_LOG_DEBUG("entities.player.items", "+ %u INTELLECT", enchant_amount);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Intellect, enchant_amount);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Intellect, enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT:
|
||||
TC_LOG_DEBUG("entities.player.items", "+ %u SPIRIT", enchant_amount);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Spirit, enchant_amount);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Spirit, enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA:
|
||||
TC_LOG_DEBUG("entities.player.items", "+ %u STAMINA", enchant_amount);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
if (apply)
|
||||
GetStats().AddBaseStatModifier(StatType::Stamina, enchant_amount);
|
||||
else
|
||||
GetStats().RemoveBaseStatModifier(StatType::Stamina, enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
|
||||
@@ -17157,7 +17186,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
|
||||
//apply all stat bonuses from items and auras
|
||||
SetCanModifyStats(true);
|
||||
UpdateAllStats();
|
||||
UpdateAllRatings();
|
||||
UpdateAllResistances();
|
||||
|
||||
// restore remembered power/health values (but not more max values)
|
||||
SetHealth(savedHealth);
|
||||
@@ -20002,8 +20032,8 @@ void Player::_SaveStats(CharacterDatabaseTransaction& trans) const
|
||||
for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
|
||||
stmt->setUInt32(index++, GetMaxPower(PowerType(i)));
|
||||
|
||||
for (uint8 i = 0; i < MAX_STATS; ++i)
|
||||
stmt->setUInt32(index++, GetStat(StatType(i)));
|
||||
for (StatType stat : AllStats)
|
||||
stmt->setUInt32(index++, GetStat(stat));
|
||||
|
||||
for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
stmt->setUInt32(index++, GetResistance(SpellSchools(i)));
|
||||
@@ -20028,9 +20058,9 @@ void Player::outDebugValues() const
|
||||
return;
|
||||
|
||||
TC_LOG_DEBUG("entities.unit", "HP is: \t\t\t%u\t\tMP is: \t\t\t%u", GetMaxHealth(), GetMaxPower(POWER_MANA));
|
||||
TC_LOG_DEBUG("entities.unit", "AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f", GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
|
||||
TC_LOG_DEBUG("entities.unit", "INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f", GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT));
|
||||
TC_LOG_DEBUG("entities.unit", "STAMINA is: \t\t%f", GetStat(STAT_STAMINA));
|
||||
TC_LOG_DEBUG("entities.unit", "AGILITY is: \t\t%i\t\tSTRENGTH is: \t\t%i", GetStat(StatType::Agility), GetStat(StatType::Strength));
|
||||
TC_LOG_DEBUG("entities.unit", "INTELLECT is: \t\t%i\t\tSPIRIT is: \t\t%i", GetStat(StatType::Intellect), GetStat(StatType::Spirit));
|
||||
TC_LOG_DEBUG("entities.unit", "STAMINA is: \t\t%i", GetStat(StatType::Stamina));
|
||||
TC_LOG_DEBUG("entities.unit", "Armor is: \t\t%u\t\tBlock is: \t\t%f", GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE));
|
||||
TC_LOG_DEBUG("entities.unit", "HolyRes is: \t\t%u\t\tFireRes is: \t\t%u", GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE));
|
||||
TC_LOG_DEBUG("entities.unit", "NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u", GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST));
|
||||
@@ -27446,7 +27476,6 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
|
||||
}
|
||||
|
||||
// Update all stats after we have applied pet scaling auras to make sure we have all fields initialized properly
|
||||
pet->UpdateAllStats();
|
||||
pet->SetFullHealth();
|
||||
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
|
||||
|
||||
|
||||
@@ -1742,8 +1742,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
float GetHealthBonusFromStamina();
|
||||
float GetManaBonusFromIntellect();
|
||||
|
||||
bool UpdateStats(StatType stat) override;
|
||||
bool UpdateAllStats() override;
|
||||
void ApplySpellPenetrationBonus(int32 amount, bool apply);
|
||||
void UpdateResistances(uint32 school) override;
|
||||
void UpdateArmor() override;
|
||||
|
||||
@@ -52,8 +52,6 @@ class TC_GAME_API Totem : public Minion
|
||||
void SetTotemDuration(uint32 duration) { m_duration = duration; }
|
||||
TotemType GetTotemType() const { return m_type; }
|
||||
|
||||
bool UpdateStats(StatType /*stat*/) override { return true; }
|
||||
bool UpdateAllStats() override { return true; }
|
||||
void UpdateResistances(uint32 /*school*/) override { }
|
||||
void UpdateArmor() override { }
|
||||
void UpdateMaxHealth() override { }
|
||||
|
||||
@@ -150,9 +150,9 @@ void Unit::UpdatePowerRegeneration(PowerType powerType)
|
||||
baseRegen += powerRegenMod;
|
||||
|
||||
// SpiritRegen = Spirit * GTRegenMpPerSpt * Sqrt(INT) * 5
|
||||
float spiritRegen = GetStat(STAT_SPIRIT) * DBCManager::GetGtOCTRegenMPPerSpirit(getClass(), getLevel());
|
||||
if (GetStat(STAT_INTELLECT) > 0.0f)
|
||||
spiritRegen *= std::sqrt(GetStat(STAT_INTELLECT));
|
||||
float spiritRegen = GetStat(StatType::Spirit) * DBCManager::GetGtOCTRegenMPPerSpirit(getClass(), getLevel());
|
||||
if (GetStat(StatType::Intellect) > 0.0f)
|
||||
spiritRegen *= std::sqrt(GetStat(StatType::Intellect));
|
||||
|
||||
// SPELL_AURA_MOD_POWER_REGEN_PERCENT pct bonus
|
||||
baseRegen *= powerRegenModPct;
|
||||
@@ -224,64 +224,6 @@ void Unit::UpdatePowerRegeneration(PowerType powerType)
|
||||
######## ########
|
||||
#######################################*/
|
||||
|
||||
bool Player::UpdateStats(StatType stat)
|
||||
{
|
||||
if (stat > STAT_SPIRIT)
|
||||
return false;
|
||||
|
||||
// value = ((base_value * base_pct) + total_value) * total_pct
|
||||
float value = GetTotalStatValue(stat);
|
||||
|
||||
SetStat(stat, int32(value));
|
||||
|
||||
switch (stat)
|
||||
{
|
||||
case STAT_AGILITY:
|
||||
UpdateArmor();
|
||||
UpdateAllCritPercentages();
|
||||
UpdateDodgePercentage();
|
||||
break;
|
||||
case STAT_STAMINA:
|
||||
UpdateMaxHealth();
|
||||
break;
|
||||
case STAT_INTELLECT:
|
||||
UpdateMaxPower(POWER_MANA);
|
||||
UpdateAllSpellCritChances();
|
||||
UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
|
||||
break;
|
||||
case STAT_SPIRIT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat == STAT_STRENGTH)
|
||||
UpdateAttackPowerAndDamage(false);
|
||||
else if (stat == STAT_AGILITY)
|
||||
{
|
||||
UpdateAttackPowerAndDamage(false);
|
||||
UpdateAttackPowerAndDamage(true);
|
||||
}
|
||||
|
||||
UpdateSpellDamageAndHealingBonus();
|
||||
UpdatePowerRegeneration(POWER_MANA);
|
||||
|
||||
// Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
|
||||
uint32 mask = 0;
|
||||
AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
|
||||
for (AuraEffectList::const_iterator i = modRatingFromStat.begin(); i != modRatingFromStat.end(); ++i)
|
||||
if (StatType((*i)->GetMiscValueB()) == stat)
|
||||
mask |= (*i)->GetMiscValue();
|
||||
if (mask)
|
||||
{
|
||||
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
if (mask & (1 << rating))
|
||||
ApplyRatingMod(CombatRating(rating), 0, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::ApplySpellPowerBonus(int32 amount, bool apply)
|
||||
{
|
||||
if (HasAuraType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT))
|
||||
@@ -334,37 +276,6 @@ void Player::UpdateSpellHealingPercentTaken()
|
||||
SetFloatValue(PLAYER_FIELD_MOD_HEALING_PCT, TakenTotalMod);
|
||||
}
|
||||
|
||||
bool Player::UpdateAllStats()
|
||||
{
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
float value = GetTotalStatValue(StatType(i));
|
||||
SetStat(StatType(i), int32(value));
|
||||
}
|
||||
|
||||
UpdateArmor();
|
||||
// calls UpdateAttackPowerAndDamage() in UpdateArmor for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
|
||||
UpdateAttackPowerAndDamage(true);
|
||||
UpdateMaxHealth();
|
||||
|
||||
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
|
||||
UpdateMaxPower(PowerType(i));
|
||||
|
||||
UpdateAllRatings();
|
||||
UpdateAllCritPercentages();
|
||||
UpdateAllSpellCritChances();
|
||||
UpdateBlockPercentage();
|
||||
UpdateParryPercentage();
|
||||
UpdateDodgePercentage();
|
||||
UpdateSpellDamageAndHealingBonus();
|
||||
UpdatePowerRegeneration(POWER_MANA);
|
||||
UpdateExpertise(BASE_ATTACK);
|
||||
UpdateExpertise(OFF_ATTACK);
|
||||
UpdateAllResistances();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::ApplySpellPenetrationBonus(int32 amount, bool apply)
|
||||
{
|
||||
ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -amount, apply);
|
||||
@@ -412,7 +323,7 @@ float Player::GetHealthBonusFromStamina()
|
||||
if (gtOCTHpPerStaminaEntry const* hpBase = sGtOCTHpPerStaminaStore.LookupEntry((getClass() - 1) * GT_MAX_LEVEL + getLevel() - 1))
|
||||
ratio = hpBase->ratio;
|
||||
|
||||
float stamina = GetStat(STAT_STAMINA);
|
||||
float stamina = GetStat(StatType::Stamina);
|
||||
float baseStam = std::min(20.0f, stamina);
|
||||
float moreStam = stamina - baseStam;
|
||||
|
||||
@@ -422,7 +333,7 @@ float Player::GetHealthBonusFromStamina()
|
||||
float Player::GetManaBonusFromIntellect()
|
||||
{
|
||||
// Taken from PaperDollFrame.lua - 4.3.4.15595
|
||||
float intellect = GetStat(STAT_INTELLECT);
|
||||
float intellect = GetStat(StatType::Intellect);
|
||||
|
||||
float baseInt = std::min(20.0f, intellect);
|
||||
float moreInt = intellect - baseInt;
|
||||
@@ -479,15 +390,15 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
uint16 index_mult = ranged ? UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER : UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
|
||||
|
||||
if (ranged)
|
||||
val2 = (level + std::max(GetStat(STAT_AGILITY) - 10.0f, 0.0f)) * entry->RangedAttackPowerPerAgility;
|
||||
val2 = (level + std::max(GetStat(StatType::Agility) - 10.0f, 0.0f)) * entry->RangedAttackPowerPerAgility;
|
||||
else
|
||||
{
|
||||
float strengthValue = std::max((GetStat(STAT_STRENGTH) - 10.0f) * entry->AttackPowerPerStrength, 0.0f);
|
||||
float agilityValue = std::max((GetStat(STAT_AGILITY) - 10.0f) * entry->AttackPowerPerAgility, 0.0f);
|
||||
float strengthValue = std::max((GetStat(StatType::Strength) - 10.0f) * entry->AttackPowerPerStrength, 0.0f);
|
||||
float agilityValue = std::max((GetStat(StatType::Agility) - 10.0f) * entry->AttackPowerPerAgility, 0.0f);
|
||||
|
||||
// Druids in Bear and Cat form get two points attack power per agility point
|
||||
if (GetShapeshiftForm() == FORM_BEAR || GetShapeshiftForm() == FORM_CAT)
|
||||
agilityValue = std::max((GetStat(STAT_AGILITY) - 10.0f) * 2, 0.0f);
|
||||
agilityValue = std::max((GetStat(StatType::Agility) - 10.0f) * 2, 0.0f);
|
||||
|
||||
val2 = strengthValue + agilityValue;
|
||||
}
|
||||
@@ -917,8 +828,6 @@ void Player::_ApplyAllStatBonuses()
|
||||
_ApplyAllItemMods();
|
||||
|
||||
SetCanModifyStats(true);
|
||||
|
||||
UpdateAllStats();
|
||||
}
|
||||
|
||||
void Player::_RemoveAllStatBonuses()
|
||||
@@ -929,8 +838,6 @@ void Player::_RemoveAllStatBonuses()
|
||||
_RemoveAllAuraStatMods();
|
||||
|
||||
SetCanModifyStats(true);
|
||||
|
||||
UpdateAllStats();
|
||||
}
|
||||
|
||||
/*#######################################
|
||||
@@ -939,25 +846,6 @@ void Player::_RemoveAllStatBonuses()
|
||||
######## ########
|
||||
#######################################*/
|
||||
|
||||
bool Creature::UpdateStats(StatType /*stat*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Creature::UpdateAllStats()
|
||||
{
|
||||
UpdateMaxHealth();
|
||||
UpdateAttackPowerAndDamage();
|
||||
UpdateAttackPowerAndDamage(true);
|
||||
|
||||
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
|
||||
UpdateMaxPower(PowerType(i));
|
||||
|
||||
UpdateAllResistances();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Creature::UpdateResistances(uint32 school)
|
||||
{
|
||||
if (school > SPELL_SCHOOL_NORMAL)
|
||||
@@ -1096,58 +984,6 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
|
||||
######## ########
|
||||
#######################################*/
|
||||
|
||||
bool Guardian::UpdateStats(StatType stat)
|
||||
{
|
||||
if (stat >= MAX_STATS)
|
||||
return false;
|
||||
|
||||
// value = ((base_value * base_pct) + total_value) * total_pct
|
||||
float value = GetTotalStatValue(stat);
|
||||
//ApplyStatBuffMod(stat, m_statFromOwner[stat], false);
|
||||
float ownersBonus = 0.0f;
|
||||
|
||||
SetStat(stat, int32(value));
|
||||
m_statFromOwner[stat] = ownersBonus;
|
||||
UpdateStatBuffMod(stat);
|
||||
|
||||
switch (stat)
|
||||
{
|
||||
case STAT_STRENGTH:
|
||||
UpdateAttackPowerAndDamage();
|
||||
break;
|
||||
case STAT_AGILITY:
|
||||
UpdateArmor();
|
||||
break;
|
||||
case STAT_STAMINA:
|
||||
UpdateMaxHealth();
|
||||
break;
|
||||
case STAT_INTELLECT:
|
||||
UpdateMaxPower(POWER_MANA);
|
||||
break;
|
||||
case STAT_SPIRIT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Guardian::UpdateAllStats()
|
||||
{
|
||||
UpdateMaxHealth();
|
||||
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
UpdateStats(StatType(i));
|
||||
|
||||
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
|
||||
UpdateMaxPower(PowerType(i));
|
||||
|
||||
UpdateAllResistances();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Guardian::UpdateResistances(uint32 school)
|
||||
{
|
||||
if (school > SPELL_SCHOOL_NORMAL)
|
||||
@@ -1177,7 +1013,7 @@ void Guardian::UpdateArmor()
|
||||
void Guardian::UpdateMaxHealth()
|
||||
{
|
||||
UnitMods unitMod = UNIT_MOD_HEALTH;
|
||||
float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
|
||||
float stamina = GetStat(StatType::Stamina) - GetStats().GetBaseStatValue(StatType::Stamina);
|
||||
float multiplicator = 10.0f;
|
||||
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
|
||||
@@ -1195,7 +1031,7 @@ void Guardian::UpdateMaxPower(PowerType power)
|
||||
|
||||
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + AsUnderlyingType(power));
|
||||
|
||||
float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
|
||||
float addValue = (power == POWER_MANA) ? GetStat(StatType::Intellect) - GetStats().GetBaseStatValue(StatType::Intellect) : 0.0f;
|
||||
float multiplicator = 15.0f;
|
||||
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowerValue(power);
|
||||
@@ -1212,7 +1048,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
|
||||
return;
|
||||
|
||||
float ap_per_strength = 2.0f;
|
||||
float val = GetStat(STAT_STRENGTH) - 20.0f;
|
||||
float val = GetStat(StatType::Strength) - 20.0f;
|
||||
|
||||
val *= ap_per_strength;
|
||||
|
||||
|
||||
@@ -16,4 +16,315 @@
|
||||
*/
|
||||
|
||||
#include "Stats.h"
|
||||
#include "Object.h"
|
||||
#include "Player.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Unit.h"
|
||||
|
||||
Stats::~Stats() = default;
|
||||
|
||||
Stats::Stats(Unit* owner) : _owner(owner), _baseStats({ }), _baseStatModifiers({ }), _basePctMultipliers({ }),
|
||||
_totalModifiers({ }), _totalPctMultipliers({ })
|
||||
{
|
||||
}
|
||||
|
||||
/// Returns the unmodified base value of the specified stat.
|
||||
/// This is the raw stat value that depends on the unit level.
|
||||
/// @param statType The stat which base value will be returned
|
||||
/// @return returns the base value fo the specified stat
|
||||
int32 Stats::GetBaseStatValue(StatType statType) const
|
||||
{
|
||||
return _baseStats[AsUnderlyingType(statType)];
|
||||
}
|
||||
|
||||
/// Sets the unmodified base value of the specified stat and
|
||||
/// updates all bonus calculations afterward. This method is
|
||||
/// meant to be used for initializing level based raw stats
|
||||
/// @param statType The stat which base value will be changed
|
||||
/// @param value The new base value that will be set
|
||||
void Stats::SetBaseStatValue(StatType statType, int32 value)
|
||||
{
|
||||
_baseStats[AsUnderlyingType(statType)] = value;
|
||||
updateStat(statType);
|
||||
}
|
||||
|
||||
/// Adds a modifier on specified stat value. This method is meant
|
||||
/// to be used for applying item and enchantment based bonus effects
|
||||
/// @param statType The stat which modifier value will be changed
|
||||
/// @param value The amount of the modifier that will be applied
|
||||
void Stats::AddBaseStatModifier(StatType statType, int32 value)
|
||||
{
|
||||
_baseStatModifiers[AsUnderlyingType(statType)] += value;
|
||||
updateStat(statType);
|
||||
}
|
||||
|
||||
/// Removes a modifier on specified stat value. This method is meant
|
||||
/// to be used for removing item and enchantment based bonus effects
|
||||
/// @param statType The stat which modifier value will be changed
|
||||
/// @param value The amount of the modifier that will be removed
|
||||
void Stats::RemoveBaseStatModifier(StatType statType, int32 value)
|
||||
{
|
||||
_baseStatModifiers[AsUnderlyingType(statType)] -= value;
|
||||
updateStat(statType);
|
||||
}
|
||||
|
||||
/// Updates the stored base percentage multipliers applied by SPELL_AURA_MOD_PERCENT_STAT.
|
||||
/// This method also applies stacking rules
|
||||
/// @param statType The stat which multiplier value will be updated
|
||||
void Stats::UpdateBaseStatMultiplier(StatType statType)
|
||||
{
|
||||
if (statType == StatType::AllStats)
|
||||
{
|
||||
for (StatType stat : AllStats)
|
||||
{
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_PERCENT_STAT, stat);
|
||||
_basePctMultipliers[AsUnderlyingType(stat)] = multiplier;
|
||||
updateStat(stat);
|
||||
}
|
||||
}
|
||||
else if (statType == StatType::PrimaryStat)
|
||||
{
|
||||
StatType primaryStat = GetPrimaryStat();
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_PERCENT_STAT, primaryStat);
|
||||
_basePctMultipliers[AsUnderlyingType(primaryStat)] = multiplier;
|
||||
updateStat(primaryStat);
|
||||
}
|
||||
else
|
||||
{
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_PERCENT_STAT, statType);
|
||||
_basePctMultipliers[AsUnderlyingType(statType)] = multiplier;
|
||||
updateStat(statType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the stored base modifiers applied by SPELL_AURA_MOD_STAT.
|
||||
/// This method also applies stacking rules
|
||||
/// @param statType The stat which modifier value will be updated
|
||||
void Stats::UpdateTotalStatModifier(StatType statType)
|
||||
{
|
||||
if (statType == StatType::AllStats)
|
||||
{
|
||||
for (StatType stat : AllStats)
|
||||
{
|
||||
int32 modifier = getAuraModifierForStatType(SPELL_AURA_MOD_STAT, stat);
|
||||
_totalModifiers[AsUnderlyingType(stat)] = modifier;
|
||||
updateStat(stat);
|
||||
}
|
||||
}
|
||||
else if (statType == StatType::PrimaryStat)
|
||||
{
|
||||
StatType primaryStat = GetPrimaryStat();
|
||||
int32 modifier = getAuraModifierForStatType(SPELL_AURA_MOD_STAT, primaryStat);
|
||||
_totalModifiers[AsUnderlyingType(primaryStat)] = modifier;
|
||||
updateStat(primaryStat);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 modifier = getAuraModifierForStatType(SPELL_AURA_MOD_STAT, statType);
|
||||
_totalModifiers[AsUnderlyingType(statType)] = modifier;
|
||||
updateStat(statType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the stored total percentage multipliers applied by SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE.
|
||||
/// This method also applies stacking rules
|
||||
/// @param statType The stat which multiplier value will be updated
|
||||
void Stats::UpdateTotalStatMultiplier(StatType statType)
|
||||
{
|
||||
if (statType == StatType::AllStats)
|
||||
{
|
||||
for (StatType stat : AllStats)
|
||||
{
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, stat);
|
||||
_totalPctMultipliers[AsUnderlyingType(stat)] = multiplier;
|
||||
updateStat(stat);
|
||||
}
|
||||
}
|
||||
else if (statType == StatType::PrimaryStat)
|
||||
{
|
||||
StatType primaryStat = GetPrimaryStat();
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, primaryStat);
|
||||
_totalPctMultipliers[AsUnderlyingType(primaryStat)] = multiplier;
|
||||
updateStat(primaryStat);
|
||||
}
|
||||
else
|
||||
{
|
||||
float multiplier = getAuraMultiplierForStatType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, statType);
|
||||
_totalPctMultipliers[AsUnderlyingType(statType)] = multiplier;
|
||||
updateStat(statType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the unit's primary stat type based on its class and specialization
|
||||
/// @return The primarily used stat of the unit
|
||||
StatType Stats::GetPrimaryStat() const
|
||||
{
|
||||
switch (_owner->getClass())
|
||||
{
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
{
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
{
|
||||
uint32 talentTree = player->GetPrimaryTalentTree(player->GetActiveSpec());
|
||||
if (talentTree == TALENT_TREE_WARRIOR_PROTECTION || talentTree == TALENT_TREE_DEATH_KNIGHT_BLOOD)
|
||||
return StatType::Stamina;
|
||||
}
|
||||
return StatType::Strength;
|
||||
}
|
||||
case CLASS_HUNTER:
|
||||
case CLASS_ROGUE:
|
||||
return StatType::Agility;
|
||||
case CLASS_MAGE:
|
||||
case CLASS_WARLOCK:
|
||||
case CLASS_PRIEST:
|
||||
return StatType::Intellect;
|
||||
case CLASS_DRUID:
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
{
|
||||
if (player->GetPrimaryTalentTree(player->GetActiveSpec()) == TALENT_TREE_DRUID_FERAL_COMBAT)
|
||||
{
|
||||
if (player->GetShapeshiftForm() == FORM_BEAR)
|
||||
return StatType::Stamina;
|
||||
|
||||
return StatType::Agility;
|
||||
}
|
||||
}
|
||||
return StatType::Intellect;
|
||||
case CLASS_SHAMAN:
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
if (player->GetPrimaryTalentTree(player->GetActiveSpec()) == TALENT_TREE_SHAMAN_ENHANCEMENT)
|
||||
return StatType::Agility;
|
||||
|
||||
return StatType::Intellect;
|
||||
case CLASS_PALADIN:
|
||||
{
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
{
|
||||
uint32 talentTree = player->GetPrimaryTalentTree(player->GetActiveSpec());
|
||||
if (talentTree == TALENT_TREE_PALADIN_PROTECTION)
|
||||
return StatType::Stamina;
|
||||
|
||||
if (talentTree == TALENT_TREE_PALADIN_HOLY)
|
||||
return StatType::Intellect;
|
||||
}
|
||||
return StatType::Strength;
|
||||
}
|
||||
default:
|
||||
return StatType::Strength;
|
||||
}
|
||||
}
|
||||
|
||||
void Stats::updateStat(StatType statType)
|
||||
{
|
||||
int32 negStatValue = 0;
|
||||
int32 posStatValue = 0;
|
||||
|
||||
// ==== Calculate the base flat value (Level stats and item/enchantment mods)
|
||||
int32 baseStatValue = _baseStats[AsUnderlyingType(statType)];
|
||||
int32 baseModifier = _baseStatModifiers[AsUnderlyingType(statType)];
|
||||
if (baseModifier > 0)
|
||||
posStatValue += baseModifier;
|
||||
else
|
||||
negStatValue += baseModifier;
|
||||
|
||||
int32 flatStatValue = baseStatValue + baseModifier;
|
||||
|
||||
// ==== Calculate the total base value (Base pct multiplier auras)
|
||||
double basePctMultiplier = _basePctMultipliers[AsUnderlyingType(statType)];
|
||||
int32 baseTotalValue = static_cast<int32>(flatStatValue * basePctMultiplier);
|
||||
if (flatStatValue < baseTotalValue)
|
||||
posStatValue += baseTotalValue - flatStatValue;
|
||||
else
|
||||
negStatValue += flatStatValue - baseTotalValue;
|
||||
|
||||
// ==== Calculate the total value (Total value buff auras)
|
||||
int32 totalModifier = _totalModifiers[AsUnderlyingType(statType)];
|
||||
if (totalModifier > 0)
|
||||
posStatValue += totalModifier;
|
||||
else
|
||||
negStatValue += totalModifier;
|
||||
|
||||
int32 totalValue = baseTotalValue + baseModifier;
|
||||
|
||||
// ==== Calculate the total value (Total pct multipliers)
|
||||
double totalPctMultiplier = _totalPctMultipliers[AsUnderlyingType(statType)];
|
||||
int32 statValue = static_cast<int32>(totalValue * totalPctMultiplier);
|
||||
if (totalValue < statValue)
|
||||
posStatValue += statValue - totalValue;
|
||||
else
|
||||
negStatValue += statValue - totalValue;
|
||||
|
||||
// ==== Apply the stats
|
||||
_owner->SetInt32Value(UNIT_FIELD_STAT0 + AsUnderlyingType(statType), statValue);
|
||||
_owner->SetInt32Value(UNIT_FIELD_POSSTAT0 + AsUnderlyingType(statType), posStatValue);
|
||||
_owner->SetInt32Value(UNIT_FIELD_NEGSTAT0 + AsUnderlyingType(statType), negStatValue);
|
||||
|
||||
switch (statType)
|
||||
{
|
||||
case StatType::Strength:
|
||||
_owner->UpdateAttackPowerAndDamage();
|
||||
break;
|
||||
case StatType::Agility:
|
||||
_owner->UpdateAttackPowerAndDamage(false);
|
||||
_owner->UpdateAttackPowerAndDamage(true);
|
||||
_owner->UpdateArmor();
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
{
|
||||
player->UpdateAllCritPercentages();
|
||||
player->UpdateDodgePercentage();
|
||||
}
|
||||
break;
|
||||
case StatType::Stamina:
|
||||
_owner->UpdateMaxHealth();
|
||||
break;
|
||||
case StatType::Intellect:
|
||||
_owner->UpdateMaxPower(POWER_MANA);
|
||||
_owner->UpdatePowerRegeneration(POWER_MANA);
|
||||
if (Player* player = Object::ToPlayer(_owner))
|
||||
{
|
||||
player->UpdateAllSpellCritChances();
|
||||
player->UpdateSpellDamageAndHealingBonus();
|
||||
}
|
||||
break;
|
||||
case StatType::Spirit:
|
||||
_owner->UpdatePowerRegeneration(POWER_MANA);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float Stats::getAuraMultiplierForStatType(AuraType auraType, StatType statType) const
|
||||
{
|
||||
float multiplier = _owner->GetTotalAuraMultiplier(auraType, [&](AuraEffect const* aurEff)
|
||||
{
|
||||
StatType auraStatType = static_cast<StatType>(aurEff->GetMiscValue());
|
||||
if (auraStatType == StatType::AllStats || auraStatType == statType)
|
||||
return true;
|
||||
|
||||
if (auraStatType == StatType::PrimaryStat && statType == GetPrimaryStat())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
int32 Stats::getAuraModifierForStatType(AuraType auraType, StatType statType) const
|
||||
{
|
||||
int32 modifier = _owner->GetTotalAuraModifier(auraType, [&](AuraEffect const* aurEff)
|
||||
{
|
||||
StatType auraStatType = static_cast<StatType>(aurEff->GetMiscValue());
|
||||
if (auraStatType == StatType::AllStats || auraStatType == statType)
|
||||
return true;
|
||||
|
||||
if (auraStatType == StatType::PrimaryStat && statType == GetPrimaryStat())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return modifier;
|
||||
}
|
||||
@@ -19,10 +19,34 @@
|
||||
#define _Stats_h__
|
||||
|
||||
#include "Define.h"
|
||||
#include "Util.h"
|
||||
#include <array>
|
||||
|
||||
class Unit;
|
||||
enum AuraType : uint32;
|
||||
|
||||
class TC_GAME_API //Stats
|
||||
enum class StatType : int8
|
||||
{
|
||||
PrimaryStat = -2,
|
||||
AllStats = -1,
|
||||
Strength = 0,
|
||||
Agility = 1,
|
||||
Stamina = 2,
|
||||
Intellect = 3,
|
||||
Spirit = 4,
|
||||
Max
|
||||
};
|
||||
|
||||
static constexpr std::array<StatType, AsUnderlyingType(StatType::Max)> AllStats =
|
||||
{
|
||||
StatType::Strength,
|
||||
StatType::Agility,
|
||||
StatType::Stamina,
|
||||
StatType::Intellect,
|
||||
StatType::Spirit
|
||||
};
|
||||
|
||||
class TC_GAME_API Stats
|
||||
{
|
||||
public:
|
||||
Stats() = delete;
|
||||
@@ -31,6 +55,31 @@ public:
|
||||
|
||||
~Stats();
|
||||
explicit Stats(Unit* owner);
|
||||
|
||||
int32 GetBaseStatValue(StatType statType) const;
|
||||
void SetBaseStatValue(StatType statType, int32 value);
|
||||
|
||||
void AddBaseStatModifier(StatType statType, int32 value);
|
||||
void RemoveBaseStatModifier(StatType statType, int32 value);
|
||||
|
||||
void UpdateBaseStatMultiplier(StatType statType);
|
||||
void UpdateTotalStatModifier(StatType statType);
|
||||
void UpdateTotalStatMultiplier(StatType statType);
|
||||
|
||||
StatType GetPrimaryStat() const;
|
||||
|
||||
private:
|
||||
Unit* _owner;
|
||||
std::array<int32, AsUnderlyingType(StatType::Max)> _baseStats;
|
||||
std::array<int32, AsUnderlyingType(StatType::Max)> _baseStatModifiers;
|
||||
std::array<double, AsUnderlyingType(StatType::Max)> _basePctMultipliers;
|
||||
std::array<int32, AsUnderlyingType(StatType::Max)> _totalModifiers;
|
||||
std::array<double, AsUnderlyingType(StatType::Max)> _totalPctMultipliers;
|
||||
|
||||
void updateStat(StatType statType);
|
||||
float getAuraMultiplierForStatType(AuraType auraType, StatType statType) const;
|
||||
int32 getAuraModifierForStatType(AuraType auraType, StatType statType) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // _Stats_h__
|
||||
@@ -79,6 +79,7 @@
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellPackets.h"
|
||||
#include "Stats.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
#include "Transport.h"
|
||||
@@ -306,7 +307,8 @@ Unit::Unit(bool isWorldObject) :
|
||||
m_charmer(nullptr), m_charmed(nullptr),
|
||||
i_motionMaster(std::make_unique<MotionMaster>(this)), m_vehicle(nullptr),
|
||||
m_unitTypeMask(UNIT_MASK_NONE), m_isEngaged(false), m_combatManager(this), m_threatManager(this),
|
||||
i_AI(nullptr), m_aiLocked(false), m_spellHistory(std::make_unique<SpellHistory>(this))
|
||||
i_AI(nullptr), m_aiLocked(false), m_spellHistory(std::make_unique<SpellHistory>(this)),
|
||||
_stats(std::make_unique<Stats>(this))
|
||||
{
|
||||
m_objectType |= TYPEMASK_UNIT;
|
||||
m_objectTypeId = TYPEID_UNIT;
|
||||
@@ -348,8 +350,6 @@ Unit::Unit(bool isWorldObject) :
|
||||
m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
|
||||
}
|
||||
|
||||
m_createStats.fill(0.0f);
|
||||
|
||||
m_attacking = nullptr;
|
||||
m_modMeleeHitChance = 0.0f;
|
||||
m_modRangedHitChance = 0.0f;
|
||||
@@ -4807,82 +4807,6 @@ void Unit::UpdateResistanceBuffModsMod(SpellSchools school)
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(school), modNeg);
|
||||
}
|
||||
|
||||
void Unit::InitStatBuffMods()
|
||||
{
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
SetFloatValue(UNIT_FIELD_POSSTAT0+i, 0);
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0);
|
||||
}
|
||||
|
||||
void Unit::UpdateStatBuffMod(StatType stat)
|
||||
{
|
||||
float modPos = 0.0f;
|
||||
float modNeg = 0.0f;
|
||||
float currentValue = 0.0f;
|
||||
float previousValue = 0.0f;
|
||||
|
||||
UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
|
||||
|
||||
// includes value from items and enchantments
|
||||
float baseModValue = GetFlatModifierValue(unitMod, BASE_VALUE);
|
||||
if (IsGuardian())
|
||||
baseModValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
|
||||
|
||||
if (baseModValue >= 0.0f)
|
||||
modPos = baseModValue;
|
||||
else
|
||||
modNeg = baseModValue;
|
||||
|
||||
previousValue = baseModValue;
|
||||
|
||||
// SPELL_AURA_MOD_PERCENT_STAT affects the base_value as well as the create stat
|
||||
previousValue += GetCreateStat(stat);
|
||||
float multiplier = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
currentValue = previousValue * multiplier;
|
||||
if (G3D::fuzzyGe(currentValue, previousValue))
|
||||
modPos += currentValue - previousValue;
|
||||
else
|
||||
modNeg -= previousValue - currentValue;
|
||||
|
||||
// total_value offsets
|
||||
previousValue += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [&](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat)
|
||||
{
|
||||
if (aurEff->GetAmount() > 0)
|
||||
modPos += aurEff->GetAmount();
|
||||
else
|
||||
modNeg += aurEff->GetAmount();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// total_pct multiplier
|
||||
multiplier = GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (!aurEff->GetMiscValueB() || aurEff->GetMiscValueB() & (1 << stat))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
currentValue = previousValue * multiplier;
|
||||
if (G3D::fuzzyGe(currentValue, previousValue))
|
||||
modPos += currentValue - previousValue;
|
||||
else
|
||||
modNeg -= previousValue - currentValue;
|
||||
|
||||
SetFloatValue(UNIT_FIELD_POSSTAT0 + AsUnderlyingType(stat), modPos);
|
||||
SetFloatValue(UNIT_FIELD_NEGSTAT0 + AsUnderlyingType(stat), modNeg);
|
||||
}
|
||||
|
||||
void Unit::_RegisterDynObject(DynamicObject* dynObj)
|
||||
{
|
||||
m_dynObj.push_back(dynObj);
|
||||
@@ -6727,7 +6651,7 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask, bool withSpellP
|
||||
|
||||
// Check if we are ever using mana - PaperDollFrame.lua
|
||||
if (GetPowerIndex(POWER_MANA) != MAX_POWERS)
|
||||
DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect
|
||||
DoneAdvertisedBenefit += std::max(0, int32(GetStat(StatType::Intellect)) - 10); // spellpower from intellect
|
||||
|
||||
// Spell Power bonus from SPELL_AURA_MOD_SPELL_POWER_PCT
|
||||
if (withSpellPowerPctMod)
|
||||
@@ -7315,7 +7239,7 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask, bool withSpell
|
||||
|
||||
// Check if we are ever using mana - PaperDollFrame.lua
|
||||
if (GetPowerIndex(POWER_MANA) != MAX_POWERS)
|
||||
advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect
|
||||
advertisedBenefit += std::max(0, int32(GetStat(StatType::Intellect)) - 10); // spellpower from intellect
|
||||
|
||||
// Spell Power bonus from SPELL_AURA_MOD_SPELL_POWER_PCT
|
||||
if (withSpellPowerPctMod)
|
||||
@@ -8972,13 +8896,6 @@ void Unit::UpdateUnitMod(UnitMods unitMod)
|
||||
|
||||
switch (unitMod)
|
||||
{
|
||||
case UNIT_MOD_STAT_STRENGTH:
|
||||
case UNIT_MOD_STAT_AGILITY:
|
||||
case UNIT_MOD_STAT_STAMINA:
|
||||
case UNIT_MOD_STAT_INTELLECT:
|
||||
case UNIT_MOD_STAT_SPIRIT:
|
||||
UpdateStats(GetStatByAuraGroup(unitMod));
|
||||
break;
|
||||
case UNIT_MOD_ARMOR:
|
||||
UpdateArmor();
|
||||
break;
|
||||
@@ -9101,19 +9018,6 @@ void Unit::UpdateAllDamagePctDoneMods()
|
||||
UpdateDamagePctDoneMods(WeaponAttackType(i));
|
||||
}
|
||||
|
||||
float Unit::GetTotalStatValue(StatType stat) const
|
||||
{
|
||||
UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
|
||||
|
||||
// value = ((base_value * base_pct) + total_value) * total_pct
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateStat(stat);
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float Unit::GetTotalAuraModValue(UnitMods unitMod) const
|
||||
{
|
||||
if (unitMod >= UNIT_MOD_END)
|
||||
@@ -9150,25 +9054,6 @@ SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
|
||||
return school;
|
||||
}
|
||||
|
||||
StatType Unit::GetStatByAuraGroup(UnitMods unitMod) const
|
||||
{
|
||||
StatType stat = STAT_STRENGTH;
|
||||
|
||||
switch (unitMod)
|
||||
{
|
||||
case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
|
||||
case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
|
||||
case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
|
||||
case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
|
||||
case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
PowerType Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
|
||||
{
|
||||
switch (unitMod)
|
||||
@@ -10735,7 +10620,6 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
|
||||
// this enables pet details window (Shift+P)
|
||||
pet->InitPetCreateSpells();
|
||||
//pet->InitLevelupSpellsForLevel();
|
||||
pet->UpdateAllStats();
|
||||
pet->SetFullHealth();
|
||||
pet->CastSpell(pet, 99289, true); // Energize
|
||||
pet->SetReactState(REACT_ASSIST);
|
||||
@@ -14383,3 +14267,16 @@ void Unit::SetGameClientMovingMe(GameClient* gameClientMovingMe)
|
||||
{
|
||||
_gameClientMovingMe = gameClientMovingMe;
|
||||
}
|
||||
|
||||
Stats& Unit::GetStats() const
|
||||
{
|
||||
return *_stats;
|
||||
}
|
||||
|
||||
int32 Unit::GetStat(StatType statType) const
|
||||
{
|
||||
if (statType < StatType::Strength)
|
||||
return 0;
|
||||
|
||||
return GetInt32Value(UNIT_FIELD_STAT0 + AsUnderlyingType(statType));
|
||||
}
|
||||
@@ -18,20 +18,22 @@
|
||||
#ifndef __UNIT_H
|
||||
#define __UNIT_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "CombatManager.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "ThreatManager.h"
|
||||
#include "Timer.h"
|
||||
#include "UnitDefines.h"
|
||||
#include "Util.h"
|
||||
#include <array>
|
||||
#include <forward_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
#include "CombatManager.h"
|
||||
#include "Object.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "Stats.h"
|
||||
#include "ThreatManager.h"
|
||||
#include "Timer.h"
|
||||
#include "UnitDefines.h"
|
||||
#include "Util.h"
|
||||
|
||||
constexpr uint32 WORLD_TRIGGER = 12999;
|
||||
|
||||
constexpr uint8 MAX_SPELL_CHARM = 4;
|
||||
@@ -87,6 +89,7 @@ class Spell;
|
||||
class SpellCastTargets;
|
||||
class SpellHistory;
|
||||
class SpellInfo;
|
||||
class Stats;
|
||||
class Totem;
|
||||
class Transport;
|
||||
class TransportBase;
|
||||
@@ -161,11 +164,6 @@ enum WeaponDamageRange
|
||||
|
||||
enum UnitMods
|
||||
{
|
||||
UNIT_MOD_STAT_STRENGTH, // UNIT_MOD_STAT_STRENGTH..UNIT_MOD_STAT_SPIRIT must be in existed order, it's accessed by index values of Stats enum.
|
||||
UNIT_MOD_STAT_AGILITY,
|
||||
UNIT_MOD_STAT_STAMINA,
|
||||
UNIT_MOD_STAT_INTELLECT,
|
||||
UNIT_MOD_STAT_SPIRIT,
|
||||
UNIT_MOD_HEALTH,
|
||||
UNIT_MOD_MANA, // UNIT_MOD_MANA..UNIT_MOD_RUNIC_POWER must be in existed order, it's accessed by index values of Powers enum.
|
||||
UNIT_MOD_RAGE,
|
||||
@@ -192,8 +190,6 @@ enum UnitMods
|
||||
UNIT_MOD_DAMAGE_RANGED,
|
||||
UNIT_MOD_END,
|
||||
// synonyms
|
||||
UNIT_MOD_STAT_START = UNIT_MOD_STAT_STRENGTH,
|
||||
UNIT_MOD_STAT_END = UNIT_MOD_STAT_SPIRIT + 1,
|
||||
UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR,
|
||||
UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1,
|
||||
UNIT_MOD_POWER_START = UNIT_MOD_MANA,
|
||||
@@ -774,8 +770,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
uint32 getClassMask() const { return 1 << (getClass()-1); }
|
||||
uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER); }
|
||||
|
||||
float GetStat(StatType stat) const { return float(GetUInt32Value(UNIT_FIELD_STAT0 + AsUnderlyingType(stat))); }
|
||||
void SetStat(StatType stat, int32 val) { SetStatInt32Value(UNIT_FIELD_STAT0 + AsUnderlyingType(stat), val); }
|
||||
uint32 GetArmor() const { return GetResistance(SPELL_SCHOOL_NORMAL); }
|
||||
void SetArmor(int32 val) { SetResistance(SPELL_SCHOOL_NORMAL, val); }
|
||||
|
||||
@@ -1280,17 +1274,11 @@ class TC_GAME_API Unit : public WorldObject
|
||||
int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const;
|
||||
|
||||
void UpdateResistanceBuffModsMod(SpellSchools school);
|
||||
void InitStatBuffMods();
|
||||
void UpdateStatBuffMod(StatType stat);
|
||||
void SetCreateStat(StatType stat, float val) { m_createStats[stat] = val; }
|
||||
void SetCreateHealth(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_HEALTH, val); }
|
||||
uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); }
|
||||
void SetCreateMana(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_MANA, val); }
|
||||
uint32 GetCreateMana() const { return GetUInt32Value(UNIT_FIELD_BASE_MANA); }
|
||||
int32 GetCreatePowerValue(PowerType power) const;
|
||||
float GetPosStat(StatType stat) const { return GetFloatValue(UNIT_FIELD_POSSTAT0 + AsUnderlyingType(stat)); }
|
||||
float GetNegStat(StatType stat) const { return GetFloatValue(UNIT_FIELD_NEGSTAT0 + AsUnderlyingType(stat)); }
|
||||
float GetCreateStat(StatType stat) const { return m_createStats[stat]; }
|
||||
|
||||
ObjectGuid GetChannelObjectGuid() const { return GetGuidValue(UNIT_FIELD_CHANNEL_OBJECT); }
|
||||
void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); }
|
||||
@@ -1360,15 +1348,11 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void UpdateDamagePctDoneMods(WeaponAttackType attackType);
|
||||
void UpdateAllDamagePctDoneMods();
|
||||
|
||||
float GetTotalStatValue(StatType stat) const;
|
||||
float GetTotalAuraModValue(UnitMods unitMod) const;
|
||||
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const;
|
||||
StatType GetStatByAuraGroup(UnitMods unitMod) const;
|
||||
PowerType GetPowerTypeByAuraGroup(UnitMods unitMod) const;
|
||||
bool CanModifyStats() const { return m_canModifyStats; }
|
||||
void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; }
|
||||
virtual bool UpdateStats(StatType stat) = 0;
|
||||
virtual bool UpdateAllStats() = 0;
|
||||
virtual void UpdateResistances(uint32 school) = 0;
|
||||
virtual void UpdateAllResistances();
|
||||
virtual void UpdateArmor() = 0;
|
||||
@@ -1665,8 +1649,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
void _UpdateAutoRepeatSpell();
|
||||
|
||||
std::array<float, MAX_STATS> m_createStats;
|
||||
|
||||
AttackerSet m_attackers;
|
||||
Unit* m_attacking;
|
||||
|
||||
@@ -1819,6 +1801,12 @@ class TC_GAME_API Unit : public WorldObject
|
||||
std::unordered_map<MovementChangeType, PlayerMovementPendingChange> m_pendingMovementChanges;
|
||||
|
||||
/* Player Movement fields END*/
|
||||
|
||||
private:
|
||||
std::unique_ptr<Stats> _stats;
|
||||
public:
|
||||
Stats& GetStats() const;
|
||||
int32 GetStat(StatType statType) const;
|
||||
};
|
||||
|
||||
namespace Trinity
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Stats.h"
|
||||
#include "StringConvert.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "TerrainMgr.h"
|
||||
@@ -3282,10 +3283,9 @@ void ObjectMgr::LoadPetLevelInfo()
|
||||
pLevelInfo->mana = fields[3].GetUInt16();
|
||||
pLevelInfo->armor = fields[9].GetUInt32();
|
||||
|
||||
for (int i = 0; i < MAX_STATS; i++)
|
||||
{
|
||||
pLevelInfo->stats[i] = fields[i+4].GetUInt16();
|
||||
}
|
||||
|
||||
for (StatType stat : AllStats)
|
||||
pLevelInfo->stats[AsUnderlyingType(stat)] = fields[AsUnderlyingType(stat) + 4].GetUInt16();
|
||||
|
||||
++count;
|
||||
}
|
||||
@@ -3705,7 +3705,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
{
|
||||
struct RaceStats
|
||||
{
|
||||
std::array<int16, MAX_STATS> StatModifier = { };
|
||||
std::array<int16, AsUnderlyingType(StatType::Max)> StatModifier = { };
|
||||
};
|
||||
|
||||
std::array<RaceStats, MAX_RACES> raceStatModifiers = { };
|
||||
@@ -3732,8 +3732,8 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_STATS; ++i)
|
||||
raceStatModifiers[current_race].StatModifier[i] = fields[i + 1].GetInt16();
|
||||
for (StatType stat : AllStats)
|
||||
raceStatModifiers[current_race].StatModifier[AsUnderlyingType(stat)] = fields[AsUnderlyingType(stat) + 1].GetInt16();
|
||||
|
||||
} while (raceStatsResult->NextRow());
|
||||
|
||||
@@ -3781,8 +3781,8 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
playerInfo->levelInfo = std::make_unique<PlayerLevelInfo[]>(sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL));
|
||||
|
||||
PlayerLevelInfo& levelInfo = playerInfo->levelInfo[current_level - 1];
|
||||
for (uint8 i = 0; i < MAX_STATS; i++)
|
||||
levelInfo.stats[i] = fields[i + 2].GetUInt16() + raceStatModifiers[race].StatModifier[i];
|
||||
for (StatType stat : AllStats)
|
||||
levelInfo.stats[AsUnderlyingType(stat)] = fields[AsUnderlyingType(stat) + 2].GetUInt16() + raceStatModifiers[race].StatModifier[AsUnderlyingType(stat)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3940,73 +3940,73 @@ void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, Play
|
||||
// base data (last known level)
|
||||
*info = ASSERT_NOTNULL(Trinity::Containers::MapGetValuePtr(_playerInfo, { Races(race), Classes(_class) }))->levelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) - 1];
|
||||
|
||||
// if conversion from uint32 to uint8 causes unexpected behaviour, change lvl to uint32
|
||||
// if conversion from uint32 to uint8 causes unexpected behavior, change lvl to uint32
|
||||
for (uint8 lvl = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl)
|
||||
{
|
||||
switch (_class)
|
||||
{
|
||||
case CLASS_WARRIOR:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0);
|
||||
info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 3 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 6 && (lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 7 ? 1: 0);
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
|
||||
info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0);
|
||||
info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 4 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 4 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 8 && (lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
|
||||
info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 5 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 4 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 8 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
|
||||
break;
|
||||
case CLASS_PRIEST:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
|
||||
info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 5 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 3 ? 1: 0);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
|
||||
info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0);
|
||||
info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 4 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 7 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 5 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 4 ? 1: 0);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
|
||||
info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 5 ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
|
||||
info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
|
||||
info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 9 && !(lvl%2) ? 1: 0);
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
|
||||
info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
|
||||
info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
|
||||
info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Strength)] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Stamina)] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Agility)] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Intellect)] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
|
||||
info->stats[AsUnderlyingType(StatType::Spirit)] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,7 +672,7 @@ typedef std::vector<PlayerCreateInfoItem> PlayerCreateInfoItems;
|
||||
|
||||
struct PlayerLevelInfo
|
||||
{
|
||||
uint16 stats[MAX_STATS] = { };
|
||||
uint16 stats[5] = { };
|
||||
};
|
||||
|
||||
typedef std::vector<uint32> PlayerCreateInfoSpells;
|
||||
@@ -714,7 +714,7 @@ struct PlayerInfo
|
||||
|
||||
struct PetLevelInfo
|
||||
{
|
||||
uint16 stats[MAX_STATS] = { };
|
||||
uint16 stats[5] = { };
|
||||
uint16 health = 0;
|
||||
uint16 mana = 0;
|
||||
uint16 armor = 0;
|
||||
|
||||
@@ -405,7 +405,7 @@ namespace WorldPackets
|
||||
int32 Level = 0;
|
||||
int32 HealthDelta = 0;
|
||||
std::array<int32, 6> PowerDelta = { };
|
||||
std::array<int32, MAX_STATS> StatDelta = { };
|
||||
std::array<int32, 5> StatDelta = { };
|
||||
};
|
||||
|
||||
class BindPointUpdate final : public ServerPacket
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
*/
|
||||
|
||||
#include "SpellAuraEffects.h"
|
||||
|
||||
#include <G3D/g3dmath.h>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include "Battlefield.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "Battleground.h"
|
||||
@@ -41,14 +46,13 @@
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Stats.h"
|
||||
#include "ThreatManager.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Weather.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <G3D/g3dmath.h>
|
||||
#include <numeric>
|
||||
|
||||
class Aura;
|
||||
//
|
||||
@@ -3567,71 +3571,30 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
if (GetMiscValue() < -2 || GetMiscValue() > 4)
|
||||
StatType stat = static_cast<StatType>(GetMiscValue());
|
||||
if (stat < StatType::PrimaryStat || stat >= StatType::Max)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue());
|
||||
if (abs(spellGroupVal) >= abs(GetAmount()))
|
||||
return;
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
// -1 or -2 is all stats (misc < -2 checked in function beginning)
|
||||
if (GetMiscValue() < 0 || GetMiscValue() == i)
|
||||
{
|
||||
if (spellGroupVal)
|
||||
{
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply);
|
||||
if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet())
|
||||
target->UpdateStatBuffMod(StatType(i));
|
||||
}
|
||||
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet())
|
||||
target->UpdateStatBuffMod(StatType(i));
|
||||
}
|
||||
}
|
||||
target->GetStats().UpdateTotalStatModifier(stat);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
StatType stat = static_cast<StatType>(GetMiscValue());
|
||||
if (stat < StatType::PrimaryStat || stat >= StatType::Max)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
if (GetMiscValue() < -1 || GetMiscValue() > 4)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
// only players have base stats
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
if (GetMiscValue() == i || GetMiscValue() == -1)
|
||||
{
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
target->GetStats().UpdateBaseStatMultiplier(stat);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModSpellDamagePercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
@@ -3713,48 +3676,15 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
if (GetMiscValue() < -1 || GetMiscValue() > 4)
|
||||
StatType stat = static_cast<StatType>(GetMiscValue());
|
||||
if (stat < StatType::PrimaryStat || stat >= StatType::Max)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
|
||||
TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
// save current health state
|
||||
float healthPct = target->GetHealthPct();
|
||||
bool zeroHealth = !target->IsAlive();
|
||||
|
||||
// players in corpse state may mean two different states:
|
||||
/// 1. player just died but did not release (in this case health == 0)
|
||||
/// 2. player is corpse running (ie ghost) (in this case health == 1)
|
||||
if (target->getDeathState() == CORPSE)
|
||||
zeroHealth = (target->GetHealth() == 0);
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
if ((GetMiscValueB() & 1 << i) || !GetMiscValueB()) // affect the same stats
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if ((aurEff->GetMiscValueB() & 1 << i) || aurEff->GetMiscValueB() == -1)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount)
|
||||
continue;
|
||||
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount);
|
||||
if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet())
|
||||
target->UpdateStatBuffMod(StatType(i));
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_IS_ABILITY 0x00000010 flag)
|
||||
// this check is total bullshit i think
|
||||
if (((GetMiscValueB() & 1 << STAT_STAMINA) || GetMiscValueB() == - 1) && m_spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY))
|
||||
target->SetHealth(std::max<uint32>(CalculatePct(target->GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1)));
|
||||
target->GetStats().UpdateTotalStatMultiplier(stat);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
|
||||
@@ -4388,7 +4388,7 @@ class spell_gen_vengeance : public AuraScript
|
||||
|
||||
if (!caster->GetAura(SPELL_VENGEANCE_TRIGGERED, caster->GetGUID()))
|
||||
{
|
||||
uint32 healthCap = CalculatePct(caster->GetCreateHealth(), 10) + caster->GetStat(STAT_STAMINA);
|
||||
uint32 healthCap = CalculatePct(caster->GetCreateHealth(), 10) + caster->GetStat(StatType::Stamina);
|
||||
uint32 damageBonus = CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), 33);
|
||||
int32 bp = std::min<int32>(damageBonus, healthCap);
|
||||
caster->CastSpell(caster, SPELL_VENGEANCE_TRIGGERED, CastSpellExtraArgs(true).AddSpellBP0(bp).AddSpellMod(SPELLVALUE_BASE_POINT1, bp).AddSpellMod(SPELLVALUE_BASE_POINT2, bp));
|
||||
@@ -4448,7 +4448,7 @@ class spell_gen_vengeance_triggered : public AuraScript
|
||||
}
|
||||
}
|
||||
|
||||
uint32 healthCap = CalculatePct(target->GetCreateHealth(), 10) + target->GetStat(STAT_STAMINA);
|
||||
uint32 healthCap = CalculatePct(target->GetCreateHealth(), 10) + target->GetStat(StatType::Stamina);
|
||||
damageLastTwoSeconds = std::min<int32>(healthCap, CalculatePct(damageLastTwoSeconds, 33));
|
||||
if (damageLastTwoSeconds)
|
||||
target->CastSpell(target, SPELL_VENGEANCE_TRIGGERED, CastSpellExtraArgs(true).AddSpellBP0(damageLastTwoSeconds).AddSpellMod(SPELLVALUE_BASE_POINT1, damageLastTwoSeconds).AddSpellMod(SPELLVALUE_BASE_POINT2, damageLastTwoSeconds));
|
||||
|
||||
@@ -4213,8 +4213,8 @@ public:
|
||||
PreventDefaultAction();
|
||||
|
||||
Unit* caster = eventInfo.GetActor();
|
||||
float str = caster->GetStat(STAT_STRENGTH);
|
||||
float agi = caster->GetStat(STAT_AGILITY);
|
||||
float str = caster->GetStat(StatType::Strength);
|
||||
float agi = caster->GetStat(StatType::Agility);
|
||||
|
||||
switch (aurEff->GetId())
|
||||
{
|
||||
@@ -4359,10 +4359,10 @@ public:
|
||||
PreventDefaultAction();
|
||||
|
||||
Unit* caster = eventInfo.GetActor();
|
||||
float str = caster->GetStat(STAT_STRENGTH);
|
||||
float agi = caster->GetStat(STAT_AGILITY);
|
||||
float intl = caster->GetStat(STAT_INTELLECT);
|
||||
float spi = caster->GetStat(STAT_SPIRIT);
|
||||
int32 str = caster->GetStat(StatType::Strength);
|
||||
int32 agi = caster->GetStat(StatType::Agility);
|
||||
int32 intl = caster->GetStat(StatType::Intellect);
|
||||
int32 spi = caster->GetStat(StatType::Spirit);
|
||||
float stat = 0.0f;
|
||||
|
||||
uint32 spellTrigger = SPELL_DARKMOON_CARD_STRENGTH;
|
||||
|
||||
@@ -100,7 +100,7 @@ class spell_warl_pet_scaling_01 : public AuraScript
|
||||
{
|
||||
if (Player* owner = pet->GetOwner())
|
||||
{
|
||||
float stamina = owner->GetStat(STAT_STAMINA) * 0.6496f;
|
||||
float stamina = owner->GetStat(StatType::Stamina) * 0.6496f;
|
||||
|
||||
float staminaBonus = 0.0f;
|
||||
switch (pet->GetEntry())
|
||||
@@ -180,7 +180,7 @@ class spell_warl_pet_scaling_02 : public AuraScript
|
||||
{
|
||||
if (Player* owner = pet->GetOwner())
|
||||
{
|
||||
float intellect = owner->GetStat(STAT_INTELLECT);
|
||||
float intellect = owner->GetStat(StatType::Intellect);
|
||||
float manaBonus = 0.0f;
|
||||
switch (pet->GetEntry())
|
||||
{
|
||||
@@ -795,7 +795,7 @@ class spell_dk_pet_scaling_01 : public AuraScript
|
||||
if (AuraEffect const* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, DEATH_KNIGHT_ICON_ID_GLYPH_OF_RAISE_DEAD, EFFECT_0))
|
||||
percentage += aurEff->GetAmount();
|
||||
|
||||
amount = int32(CalculatePct(owner->GetStat(STAT_STAMINA), percentage));
|
||||
amount = int32(CalculatePct(owner->GetStat(StatType::Stamina), percentage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,7 +810,7 @@ class spell_dk_pet_scaling_01 : public AuraScript
|
||||
if (AuraEffect const* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, DEATH_KNIGHT_ICON_ID_GLYPH_OF_RAISE_DEAD, EFFECT_0))
|
||||
percentage += aurEff->GetAmount();
|
||||
|
||||
amount = int32(CalculatePct(owner->GetStat(STAT_STAMINA), percentage));
|
||||
amount = int32(CalculatePct(owner->GetStat(StatType::Stamina), percentage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,7 +1030,7 @@ class spell_mage_water_elemental_scaling_01 : public AuraScript
|
||||
{
|
||||
if (Player* owner = pet->GetOwner())
|
||||
{
|
||||
float stamina = CalculatePct(owner->GetStat(STAT_STAMINA), 30);
|
||||
float stamina = CalculatePct(owner->GetStat(StatType::Stamina), 30);
|
||||
float staminaBonus = stamina * 7.5f;
|
||||
float maxHealthBonus = owner->CountPctFromMaxHealth(50);
|
||||
|
||||
@@ -1063,7 +1063,7 @@ class spell_mage_water_elemental_scaling_02 : public AuraScript
|
||||
{
|
||||
if (Player* owner = pet->GetOwner())
|
||||
{
|
||||
float intellect = CalculatePct(owner->GetStat(STAT_INTELLECT), 30);
|
||||
float intellect = CalculatePct(owner->GetStat(StatType::Intellect), 30);
|
||||
float intellectBonus = intellect * 5.0f;
|
||||
float maxManaBonus = owner->CountPctFromMaxPower(POWER_MANA, 50);
|
||||
|
||||
|
||||
@@ -847,7 +847,7 @@ class spell_sha_mana_tide_totem : public AuraScript
|
||||
return;
|
||||
|
||||
if (Unit* summoner = caster->ToTempSummon()->GetSummoner())
|
||||
amount = CalculatePct(summoner->GetStat(STAT_SPIRIT), amount);
|
||||
amount = CalculatePct(summoner->GetStat(StatType::Spirit), amount);
|
||||
else
|
||||
amount = 0;
|
||||
}
|
||||
|
||||
@@ -227,17 +227,6 @@ enum MoneyConstants
|
||||
GOLD = SILVER*100
|
||||
};
|
||||
|
||||
enum StatType
|
||||
{
|
||||
STAT_STRENGTH = 0,
|
||||
STAT_AGILITY = 1,
|
||||
STAT_STAMINA = 2,
|
||||
STAT_INTELLECT = 3,
|
||||
STAT_SPIRIT = 4
|
||||
};
|
||||
|
||||
#define MAX_STATS 5
|
||||
|
||||
enum PowerType
|
||||
{
|
||||
POWER_MANA = 0,
|
||||
|
||||
Reference in new issue
Block a user