Core/Units: updated power regeneration handling to get closer to the master version of it

This commit is contained in:
Ovahlord committed 2025-03-09 10:30:07 +01:00
1 parent e8588fd5ba
commit f9425284ca
10 files changed
+290 -236

No files matched your search

+53
View File
@@ -1332,6 +1332,59 @@ EmotesTextSoundEntry const* DBCManager::FindTextSoundEmoteFor(uint32 emote, uint
return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr;
}
/*static*/ float DBCManager::GetBasePowerRegen(Powers powerType, bool isInCombat, uint32 powerBarId)
{
if (powerType != POWER_ALTERNATE_POWER)
{
switch (powerType)
{
case POWER_RAGE: return isInCombat ? 0.f : -12.5f;
case POWER_FOCUS: return 5.f;
case POWER_RUNIC_POWER: return isInCombat ? 0.f : -12.5f;
case POWER_ENERGY: return 10.f;
case POWER_HOLY_POWER: return isInCombat ? 0.f : -0.1f;
case POWER_RUNE: return 0.1f;
default:
return 0.f;
}
}
else
{
UnitPowerBarEntry const* powerBar = sUnitPowerBarStore.LookupEntry(powerBarId);
if (!powerBar)
return 0.f;
return isInCombat ? powerBar->RegenerationCombat : powerBar->RegenerationPeace;
}
return 0.f;
}
/*static*/ bool DBCManager::IsPowerTypeAffectedByHaste(Powers powerType)
{
switch (powerType)
{
case POWER_ENERGY:
case POWER_FOCUS:
case POWER_RUNE:
return true;
default:
return false;
}
return false;
}
/*static*/ float DBCManager::GetGtOCTRegenMPPerSpirit(uint8 classId, uint8 level)
{
level = std::min<uint8>(level, GT_MAX_LEVEL);
GtRegenMPPerSptEntry const* gt = sGtRegenMPPerSptStore.LookupEntry((classId - 1) * GT_MAX_LEVEL + level - 1);
if (gt == nullptr)
return 0.0f;
return gt->ratio;
}
bool DBCManager::IsInArea(uint32 objectAreaId, uint32 areaId)
{
do
+5 -2
View File
@@ -238,7 +238,7 @@ public:
static uint32 GetLiquidFlags(uint32 liquidType);
static uint32 GetDefaultMapLight(uint32 mapId);
PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level);
PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id);
PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id);
CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender);
CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color);
uint32 GetPowerIndexByClass(Powers power, uint32 classId);
@@ -248,7 +248,10 @@ public:
std::vector<SkillLineAbilityEntry const*> const* GetSkillLineAbilitiesBySkill(uint32 skillId) const;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
ResponseCodes ValidateName(std::wstring const& name, LocaleConstant locale);
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
static float GetBasePowerRegen(Powers powerType, bool isInCombat, uint32 powerBarId = 0);
static bool IsPowerTypeAffectedByHaste(Powers powerType);
static float GetGtOCTRegenMPPerSpirit(uint8 classId, uint8 level);
};
#define sDBCManager DBCManager::Instance()
@@ -1428,6 +1428,7 @@ void Creature::UpdateLevelDependantStats()
Powers powerType = CalculateDisplayPowerType();
SetCreateMana(stats->BaseMana);
SetStatPctModifier(UnitMods(UNIT_MOD_POWER_START + AsUnderlyingType(powerType)), BASE_PCT, cInfo->ModMana * cInfo->ModManaExtra);
RegisterPowerTypes();
SetPowerType(powerType);
switch (getClass())
@@ -178,7 +178,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
uint32 GetPowerIndex(Powers power) const override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override;
void UpdatePowerRegeneration(Powers powerType) override;
void SetCanDualWield(bool value) override;
int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
+6 -23
View File
@@ -451,6 +451,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, createInfo->Class);
SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, createInfo->Gender);
SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, powertype);
RegisterPowerTypes();
InitDisplayIds();
if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP)
{
@@ -4929,25 +4930,6 @@ float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
return 0.0f;
}
float Player::OCTRegenMPPerSpirit() const
{
uint8 level = getLevel();
uint32 pclass = getClass();
if (level > GT_MAX_LEVEL)
level = GT_MAX_LEVEL;
// GtOCTRegenMPEntry const* baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
GtRegenMPPerSptEntry const* moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
if (moreRatio == nullptr)
return 0.0f;
// Formula get from PaperDollFrame script
float spirit = GetStat(STAT_SPIRIT);
float regen = spirit * moreRatio->ratio;
return regen;
}
void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
{
// explicit affected values
@@ -4959,16 +4941,16 @@ void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
ApplyAttackTimePercentMod(BASE_ATTACK, (m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
ApplyAttackTimePercentMod(OFF_ATTACK, m_baseRatingValue[combatRating] * GetRatingMultiplier(combatRating), false);
ApplyAttackTimePercentMod(OFF_ATTACK, (m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
ApplyHasteRegenMod(BASE_ATTACK, m_baseRatingValue[combatRating] * GetRatingMultiplier(combatRating), false);
ApplyHasteRegenMod(BASE_ATTACK, (m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
// Haste Rating affects all three haste types so we only have to apply it once here
ApplyHasteRegenMod(m_baseRatingValue[combatRating] * GetRatingMultiplier(combatRating), false);
ApplyHasteRegenMod((m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
break;
}
case CR_HASTE_RANGED:
{
ApplyAttackTimePercentMod(RANGED_ATTACK, m_baseRatingValue[combatRating] * GetRatingMultiplier(combatRating), false);
ApplyAttackTimePercentMod(RANGED_ATTACK, (m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
ApplyHasteRegenMod(RANGED_ATTACK, m_baseRatingValue[combatRating] * GetRatingMultiplier(combatRating), false);
ApplyHasteRegenMod(RANGED_ATTACK, (m_baseRatingValue[combatRating] + (apply ? value : -value)) * GetRatingMultiplier(combatRating), true);
break;
}
case CR_HASTE_SPELL:
@@ -16973,6 +16955,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
//mails are loaded only when needed ;-) - when player in game click on mailbox.
//_LoadMail();
RegisterPowerTypes();
UpdateDisplayPower();
_LoadTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
_LoadSpells(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
-2
View File
@@ -1793,7 +1793,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
float GetMeleeCritFromAgility() const;
void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const;
float GetSpellCritFromIntellect() const;
float OCTRegenMPPerSpirit() const;
float GetRatingMultiplier(CombatRating cr) const;
float GetRatingBonusValue(CombatRating cr) const;
@@ -1819,7 +1818,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void UpdateExpertise(WeaponAttackType attType);
void ApplyManaRegenBonus(int32 amount, bool apply);
void ApplyHealthRegenBonus(int32 amount, bool apply);
void UpdatePowerRegeneration(Powers powerType) override;
uint32 GetRuneTimer(uint8 index) const { return m_runeGraceCooldown[index]; }
void SetRuneTimer(uint8 index, uint32 timer) { m_runeGraceCooldown[index] = timer; }
uint32 GetLastRuneGraceTimer(uint8 index) const { return m_lastRuneGraceTimers[index]; }
+134 -101
View File
@@ -119,6 +119,140 @@ int32 Unit::GetCreatePowerValue(Powers power) const
return 0;
}
void Unit::UpdatePowerRegeneration(Powers powerType)
{
uint32 powerIndex = GetPowerIndex(powerType);
if ((powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS) && powerType != POWER_RUNE)
return;
// Runes are not officially considered a power type for the class so we gotta bypass the rules this way
if (powerType == POWER_RUNE && (!IsPlayer() || getClass() != CLASS_DEATH_KNIGHT))
return;
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType) / 5.f;
float powerRegenModPct = GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, powerType);
switch (powerType)
{
case POWER_MANA:
{
// Get base of Mana Pool in sBaseMPGameTable
uint32 basemana = 0, basehp = 0;
if (IsPlayer())
sObjectMgr->GetPlayerClassLevelInfo(getClass(), getLevel(), basemana, basehp);
else
basemana = GetCreateMana(); // this should also get replaced by the base mana game table in the future.
// BaseRegen = 5% of Base Mana per five seconds
float baseRegen = basemana / 100.f;
// SPELL_AURA_MOD_POWER_REGEN flat bonus
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));
// SPELL_AURA_MOD_POWER_REGEN_PERCENT pct bonus
baseRegen *= powerRegenModPct;
spiritRegen *= powerRegenModPct;
// SPELL_AURA_MOD_MANA_REGEN_INTERRUPT allow some of the spirit regeneration to bypass the combat restriction
int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, baseRegen + CalculatePct(spiritRegen, modManaRegenInterrupt));
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, baseRegen + spiritRegen);
break;
}
case POWER_RUNE:
{
float baseRegen = DBCManager::GetBasePowerRegen(powerType, false, 0);
// Hase Regen
if (DBCManager::IsPowerTypeAffectedByHaste(powerType) && IsPlayer())
{
float hasteRegen = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (G3D::fuzzyNe(hasteRegen, 0.0f))
baseRegen /= hasteRegen;
}
baseRegen += powerRegenMod;
if (IsPlayer())
for (uint8 i = 0; i < NUM_RUNE_TYPES; ++i)
SetFloatValue(PLAYER_RUNE_REGEN_1 + i, baseRegen);
break;
}
default:
{
// Base Regen
float peaceRegen = DBCManager::GetBasePowerRegen(powerType, false, 0);
float combatRegen = DBCManager::GetBasePowerRegen(powerType, true, 0);
// Hase Regen
if (DBCManager::IsPowerTypeAffectedByHaste(powerType) && IsPlayer())
{
float hasteRegen = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (G3D::fuzzyNe(hasteRegen, 0.0f))
{
peaceRegen /= hasteRegen;
combatRegen /= hasteRegen;
}
}
peaceRegen *= powerRegenModPct;
combatRegen *= powerRegenModPct;
// Subtract the base value to get the proper offset
peaceRegen -= DBCManager::GetBasePowerRegen(powerType, false, 0);
combatRegen -= DBCManager::GetBasePowerRegen(powerType, true, 0);
peaceRegen += powerRegenMod;
combatRegen += powerRegenMod;
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, combatRegen);
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, peaceRegen);
}
/*
case POWER_FOCUS:
case POWER_ENERGY:
{
// Energy and Focus regeneration is always consistent in and out of combat
float baseRegen = DBCManager::GetBasePowerRegen(powerType, false, 0);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, baseRegen * powerRegenModPct - baseRegen + powerRegenMod);
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, baseRegen * powerRegenModPct - baseRegen + powerRegenMod);
break;
}
case POWER_RUNIC_POWER:
case POWER_RAGE:
// Butchery and Anger Management
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, powerRegenMod);
break;
case POWER_RUNE:
{
// Formular: base cooldown / (1 - haste)
float regeneration = 0.1f;
float haste = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (haste != 0.f)
regeneration /= haste;
for (int8 i = 0; i < NUM_RUNE_TYPES; i++)
{
float mod = 0.f;
for (AuraEffect const* effect : GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN))
if (effect->GetMiscValue() == int32(powerType) && effect->GetMiscValueB() == i)
mod += effect->GetAmount();
SetFloatValue(PLAYER_RUNE_REGEN_1 + i, regeneration + mod);
}
break;
}
*/
}
}
/*#######################################
######## ########
######## PLAYERS STAT SYSTEM ########
@@ -817,76 +951,6 @@ void Player::ApplyHealthRegenBonus(int32 amount, bool apply)
_ModifyUInt32(apply, m_baseHealthRegen, amount);
}
void Player::UpdatePowerRegeneration(Powers powerType)
{
uint32 powerIndex = GetPowerIndex(powerType);
if (powerIndex == MAX_POWERS && powerType != POWER_RUNE)
return;
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType) / 5.f;
float powerRegenModPct = GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, powerType);
switch (powerType)
{
case POWER_MANA:
{
// Mana regen from spirit
float spirit_regen = OCTRegenMPPerSpirit();
// Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
spirit_regen *= powerRegenModPct;
// SpiritRegen(SPI, INT, LEVEL) = (0.001 + (SPI x sqrt(INT) x BASE_REGEN[LEVEL])) x 5
if (GetStat(STAT_INTELLECT) > 0.0f)
spirit_regen *= std::sqrt(GetStat(STAT_INTELLECT));
// CombatRegen = 5% of Base Mana per five seconds
float base_regen = CalculatePct(GetCreateMana(), 1) + powerRegenMod;
// Set regen rate in cast state apply only on spirit based regen
int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, base_regen + CalculatePct(spirit_regen, modManaRegenInterrupt));
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, spirit_regen + base_regen);
break;
}
case POWER_FOCUS:
case POWER_ENERGY:
{
// Energy and Focus regeneration is always consistent in and out of combat
float baseRegen = Unit::GetBasePowerRegen(0, powerType, false);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, baseRegen * powerRegenModPct - baseRegen + powerRegenMod);
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, baseRegen * powerRegenModPct - baseRegen + powerRegenMod);
break;
}
case POWER_RUNIC_POWER:
case POWER_RAGE:
// Butchery and Anger Management
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, powerRegenMod);
break;
case POWER_RUNE:
{
// Formular: base cooldown / (1 - haste)
float regeneration = 0.1f;
float haste = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (haste != 0.f)
regeneration /= haste;
for (int8 i = 0; i < NUM_RUNE_TYPES; i++)
{
float mod = 0.f;
for (AuraEffect const* effect : GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN))
if (effect->GetMiscValue() == int32(powerType) && effect->GetMiscValueB() == i)
mod += effect->GetAmount();
SetFloatValue(PLAYER_RUNE_REGEN_1 + i, regeneration + mod);
}
break;
}
default:
break;
}
}
void Player::_ApplyAllStatBonuses()
{
SetCanModifyStats(false);
@@ -983,37 +1047,6 @@ void Creature::UpdateMaxPower(Powers power)
SetMaxPower(power, uint32(std::lroundf(value)));
}
void Creature::UpdatePowerRegeneration(Powers powerType)
{
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType) / 5.f;
float powerRegenModPct = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, powerType);
switch (powerType)
{
case POWER_MANA:
// Regeneration for controlled units
if (!GetCharmerGUID().IsEmpty() || !GetOwnerGUID().IsEmpty())
{
float spiritRegen = (GetStat(STAT_SPIRIT) / 5.f + 17.f);
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, spiritRegen + powerRegenMod);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, powerRegenMod);
}
else // Default creature regeneration value.
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, 8.714059f + powerRegenMod); // Most common value in sniffs. Todo: research
break;
case POWER_ENERGY:
case POWER_FOCUS:
{
float regenerationRate = CalculatePct<float>(10, powerRegenModPct) + powerRegenMod;
SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, regenerationRate);
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, regenerationRate);
break;
}
default:
break;
}
}
void Creature::UpdateAttackPowerAndDamage(bool ranged)
{
UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
+46 -54
View File
@@ -368,11 +368,12 @@ Unit::Unit(bool isWorldObject) :
_powerBarId = 0;
_powerFraction.fill(0.0f);
_powerUpdateTimer = GetPowerUpdateInterval();
_healthRegenerationTimer = UNIT_HEALTH_REGENERATION_INTERVAL;
_powerFraction.fill(0.0f);
_usedPowerTypes.fill(MAX_POWERS);
_oldFactionId = 0;
_isWalkingBeforeCharm = false;
}
@@ -5205,12 +5206,19 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
SendAttackStateUpdate(&dmgInfo);
}
void Unit::SetPowerType(Powers new_powertype)
void Unit::SetPowerType(Powers power)
{
if (GetPowerType() == new_powertype)
if (GetPowerType() == power)
return;
SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, new_powertype);
SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, power);
// Creatures can swap out their power type at index 0 so we do keep track of the new power type here
if (IsCreature())
{
_usedPowerTypes[GetPowerIndex(power)] = power;
UpdatePowerRegeneration(power);
}
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -5228,10 +5236,10 @@ void Unit::SetPowerType(Powers new_powertype)
}
// Update max power
UpdateMaxPower(new_powertype);
UpdateMaxPower(power);
// Update current power
switch (new_powertype)
switch (power)
{
case POWER_MANA: // Keep the same (druid form switching...)
case POWER_ENERGY:
@@ -5240,7 +5248,7 @@ void Unit::SetPowerType(Powers new_powertype)
SetPower(POWER_RAGE, 0);
break;
case POWER_FOCUS: // Make it full
SetFullPower(new_powertype);
SetFullPower(power);
break;
default:
break;
@@ -8218,39 +8226,12 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*
return gain;
}
/*static */ float Unit::GetBasePowerRegen(uint32 powerBarId, Powers powerType, bool isInCombat)
{
if (powerType != POWER_ALTERNATE_POWER)
{
switch (powerType)
{
case POWER_RAGE: return isInCombat ? 0.f : -12.5f;
case POWER_FOCUS: return 5.f;
case POWER_RUNIC_POWER: return isInCombat ? 0.f : -12.5f;
case POWER_ENERGY: return 10.f;
case POWER_HOLY_POWER: return isInCombat ? 0.f : -0.1f;
default:
return 0.f;
}
}
else
{
UnitPowerBarEntry const* powerBar = sUnitPowerBarStore.LookupEntry(powerBarId);
if (!powerBar)
return 0.f;
return isInCombat ? powerBar->RegenerationCombat : powerBar->RegenerationPeace;
}
return 0.f;
}
// Based on client function
float Unit::GetPowerRegen(Powers powerType, bool isInCombat) const
{
uint32 powerSlot = MAX_POWERS;
float totalRegeneration = 0.f;
double result = GetBasePowerRegen(_powerBarId, powerType, isInCombat); // base power regen
double result = DBCManager::GetBasePowerRegen(powerType, isInCombat, _powerBarId);
float combatRegeneration = result;
powerSlot = GetPowerIndex(powerType);
@@ -8263,10 +8244,10 @@ float Unit::GetPowerRegen(Powers powerType, bool isInCombat) const
else
totalRegeneration = result;
if (IsPlayer() && (powerType == POWER_ENERGY || powerType == POWER_FOCUS))
if (IsPlayer() && DBCManager::IsPowerTypeAffectedByHaste(powerType))
{
float hasteRegen = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (hasteRegen != 0.f)
if (G3D::fuzzyNe(hasteRegen, 0.f))
result = totalRegeneration / hasteRegen;
}
@@ -9480,6 +9461,18 @@ void Unit::Regenerate(Powers powerType, uint32 diff)
UpdateUInt32Value(UNIT_FIELD_POWER1 + powerIndex, curValue);
}
void Unit::RegisterPowerTypes()
{
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
{
uint32 powerIndex = GetPowerIndex(Powers(i));
if (powerIndex == MAX_POWERS || powerIndex == MAX_POWERS_PER_CLASS)
continue;
_usedPowerTypes[powerIndex] = static_cast<Powers>(i);
}
}
void Unit::AIUpdateTick(uint32 diff)
{
if (UnitAI* ai = GetAI())
@@ -10652,32 +10645,31 @@ void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply
m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct);
}
void Unit::ApplyHasteRegenMod(WeaponAttackType att, float val, bool apply)
void Unit::ApplyHasteRegenMod(float val, bool apply)
{
if (GetTypeId() != TYPEID_PLAYER)
if (!IsPlayer())
return;
float amount = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (val > 0.f)
{
if (att == BASE_ATTACK && getClass() != CLASS_HUNTER)
ApplyPercentModFloatVar(amount, val, !apply);
else if (att == RANGED_ATTACK && getClass() == CLASS_HUNTER)
ApplyPercentModFloatVar(amount, val, !apply);
}
ApplyPercentModFloatVar(amount, val, !apply);
else
{
if (att == BASE_ATTACK && getClass() != CLASS_HUNTER)
ApplyPercentModFloatVar(amount, -val, apply);
else if (att == RANGED_ATTACK && getClass() == CLASS_HUNTER)
ApplyPercentModFloatVar(amount, -val, apply);
}
ApplyPercentModFloatVar(amount, -val, apply);
SetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, amount);
if (getClass() == CLASS_DEATH_KNIGHT)
ToPlayer()->UpdatePowerRegeneration(POWER_RUNE);
for (Powers powerType : GetUsedPowerTypes())
{
if (powerType == MAX_POWERS || GetPowerIndex(powerType) == MAX_POWERS)
continue;
if (DBCManager::IsPowerTypeAffectedByHaste(powerType))
UpdatePowerRegeneration(powerType);
}
if (IsPlayer() && getClass() == CLASS_DEATH_KNIGHT)
UpdatePowerRegeneration(POWER_RUNE);
}
void Unit::ApplyCastTimePercentMod(float val, bool apply, bool withCastHaste /*= true*/, bool withCastSpeed /*= true*/)
+11 -5
View File
@@ -876,8 +876,6 @@ class TC_GAME_API Unit : public WorldObject
void ClearUnitState(uint32 f) { m_state &= ~f; }
bool CanFreeMove() const;
virtual void UpdatePowerRegeneration(Powers /*powerType*/) { }
uint32 HasUnitTypeMask(uint32 mask) const { return mask & m_unitTypeMask; }
void AddUnitTypeMask(uint32 mask) { m_unitTypeMask |= mask; }
bool IsSummon() const { return (m_unitTypeMask & UNIT_MASK_SUMMON) != 0; }
@@ -938,12 +936,13 @@ class TC_GAME_API Unit : public WorldObject
void SetMaxPower(Powers power, int32 val);
void SetPowerBarID(uint32 id) { _powerBarId = id; }
void Regenerate(Powers powerType, uint32 diff);
void UpdatePowerRegeneration(Powers powerType);
void RegisterPowerTypes();
inline void SetFullPower(Powers power) { SetPower(power, GetMaxPower(power)); }
// returns the change in power
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
static float GetBasePowerRegen(uint32 powerBarId, Powers powerType, bool isInCombat);
float GetPowerRegen(Powers powerType, bool isInCombat) const;
virtual void RegenerateHealth() { }
@@ -951,7 +950,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetAttackTime(WeaponAttackType att) const;
void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att), val * m_modAttackSpeedPct[att]); }
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply);
void ApplyHasteRegenMod(WeaponAttackType att, float val, bool apply);
void ApplyHasteRegenMod(float val, bool apply);
void ApplyCastTimePercentMod(float val, bool apply, bool withCastHaste = true, bool withCastSpeed = true);
SheathState GetSheath() const { return SheathState(GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_SHEATH_STATE)); }
@@ -1846,10 +1845,17 @@ class TC_GAME_API Unit : public WorldObject
uint32 m_unitTypeMask;
LiquidTypeEntry const* _lastLiquid;
uint32 _powerBarId;
std::array<float, MAX_POWERS_PER_CLASS> _powerFraction;
int32 _powerUpdateTimer;
int32 _healthRegenerationTimer;
std::array<float, MAX_POWERS_PER_CLASS> _powerFraction;
std::array<Powers, MAX_POWERS_PER_CLASS> _usedPowerTypes;
public:
// Returns an array that contains information about which power type is used at which power index. MAX_POWERS implies that a power at given index is not used.
std::array<Powers, MAX_POWERS_PER_CLASS> const& GetUsedPowerTypes() const { return _usedPowerTypes; }
protected:
bool IsAlwaysVisibleFor(WorldObject const* seer) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
@@ -200,7 +200,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
&AuraEffect::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
&AuraEffect::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE
&AuraEffect::HandleModHealingDonePercent, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT
&AuraEffect::HandleModHealingDonePercent, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT
&AuraEffect::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
&AuraEffect::HandleModMeleeSpeedPct, //138 SPELL_AURA_MOD_MELEE_HASTE
&AuraEffect::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION
@@ -2197,7 +2197,7 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode,
{
if (caster->HasAura(52648)) // Glyph of the Penguin
model_id = 26452;
else if (caster->HasAura(57927)) // Glyph of the Monkey
else if (caster->HasAura(57927)) // Glyph of the Monkey
model_id = 21362;
}
}
@@ -2316,7 +2316,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo
}
}
}
for (auto& pair : target->GetThreatManager().GetThreatenedByMeList())
pair.second->ScaleThreat(0.0f);
@@ -3344,7 +3344,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
target->GetThreatManager().EvaluateSuppressed();
}
else
{
{
// do not remove unit flag if there are more than this auraEffect of that kind on unit
if (target->HasAuraType(GetAuraType()))
return;
@@ -4108,12 +4108,6 @@ void AuraEffect::HandleModMeleeRangedSpeedPct(AuraApplication const* aurApp, uin
target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply);
if (GetAuraType() != SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2)
{
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyHasteRegenMod(RANGED_ATTACK, (float)GetAmount(), apply);
}
}
void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4122,7 +4116,7 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
return;
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW);
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
if (abs(spellGroupVal) >= abs(GetAmount()))
return;
@@ -4132,16 +4126,16 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
target->ApplyHasteRegenMod(float(spellGroupVal), !apply);
}
target->ApplyCastTimePercentMod(float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply);
if (GetAuraType() != SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2)
{
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyHasteRegenMod(RANGED_ATTACK, (float)GetAmount(), apply);
}
target->ApplyHasteRegenMod((float)GetAmount(), apply);
}
void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4152,8 +4146,6 @@ void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
if (GetAuraType() != SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2)
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), apply);
target->UpdateDamagePhysical(BASE_ATTACK);
}
@@ -4163,35 +4155,26 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
return;
Unit* target = aurApp->GetTarget();
bool applyRegenPct = GetAuraType() != SPELL_AURA_MOD_MELEE_HASTE_3 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2;
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
if (abs(spellGroupVal) >= abs(GetAmount()))
bool applyHasteRegenMod = GetAuraType() == SPELL_AURA_MOD_MELEE_HASTE;
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
if (target->GetTypeId() == TYPEID_PLAYER && applyRegenPct && GetBase()->HasEffectType(SPELL_AURA_MOD_MELEE_HASTE_3))
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), !apply);
else
{
target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), !apply);
if (applyRegenPct)
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), !apply);
}
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
if (applyHasteRegenMod)
target->ApplyHasteRegenMod(float(spellGroupVal), !apply);
}
// Auras that only increase regeneration
if (target->GetTypeId() == TYPEID_PLAYER && applyRegenPct && GetBase()->HasEffectType(SPELL_AURA_MOD_MELEE_HASTE_3))
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), apply);
else
{
target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply);
if (applyRegenPct)
target->ApplyHasteRegenMod(BASE_ATTACK, (float)GetAmount(), apply);
}
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
if (applyHasteRegenMod)
target->ApplyHasteRegenMod(float(GetAmount()), apply);
}
void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4201,19 +4184,22 @@ void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 m
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
if (abs(spellGroupVal) >= abs(GetAmount()))
bool applyHasteRegenMod = GetAuraType() == SPELL_AURA_MOD_RANGED_HASTE;
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), !apply);
if (GetAuraType() != SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2)
target->ApplyHasteRegenMod(RANGED_ATTACK, (float)GetAmount(), !apply);
}
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply);
if (GetAuraType() != SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 && GetAuraType() != SPELL_AURA_MOD_RANGED_HASTE_2)
target->ApplyHasteRegenMod(RANGED_ATTACK, (float)GetAmount(), apply);
if (applyHasteRegenMod)
target->ApplyHasteRegenMod(float(spellGroupVal), !apply);
}
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply);
if (applyHasteRegenMod)
target->ApplyHasteRegenMod(float(GetAmount()), apply);
}
/********************************/