Core/Units: reworked power regeneration for players

* use a reversed client function to get the power regeneration rate for all types of powers
* unified all player based regeneration updates into a single statsystem helper
* cleaned up unnecessary regeneration timers
* implement power regeneration for alternative powers
* corrected rage gain numbers based on simulationcraft formulas
This commit is contained in:
Ovahlord committed 2020-04-19 22:53:29 +02:00
1 parent 0ea2200879
commit c537a2658a
14 files changed
+192 -192

No files matched your search

+2 -2
View File
@@ -2476,8 +2476,8 @@ struct UnitPowerBarEntry
uint32 MaxPower; // 3
uint32 StartPower; // 4
//uint32 CenterPower; // 5
//float RegenerationPeace; // 6
//float RegenerationCombat; // 7
float RegenerationPeace; // 6
float RegenerationCombat; // 7
//uint32 BarType; // 8
//uint32 FileDataID[6]; // 9 - 14
//uint32 Color[6]; // 15 - 20
+1 -1
View File
@@ -184,7 +184,7 @@ char const TaxiNodesEntryfmt[] = "nifffsiiiff";
char const TaxiPathEntryfmt[] = "niii";
char const TaxiPathNodeEntryfmt[] = "diiifffiiii";
char const TotemCategoryEntryfmt[] = "nxii";
char const UnitPowerBarfmt[] = "niiixxxxxxxxxxxxxxxxxxxxxxx";
char const UnitPowerBarfmt[] = "niiixffxxxxxxxxxxxxxxxxxxxx";
char const TransportAnimationfmt[] = "diifffx";
char const TransportRotationfmt[] = "diiffff";
char const VehicleEntryfmt[] = "niffffiiiiiiiifffffffffffffffssssfifiiii";
@@ -205,7 +205,7 @@ m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(fal
m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0),
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_regenTimer = REGENERATION_INTERVAL;
m_valuesCount = UNIT_END;
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
@@ -788,7 +788,7 @@ void Creature::Update(uint32 diff)
else
RegenerateMana();
}
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_regenTimer = REGENERATION_INTERVAL;
}
// Update serverside orientation of channeled spells that are suposed to track the channel target
@@ -839,7 +839,7 @@ void Creature::RegenerateMana()
if ((*i)->GetMiscValue() == POWER_MANA)
AddPct(addvalue, (*i)->GetAmount());
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) * REGENERATION_INTERVAL / (5 * IN_MILLISECONDS);
ModifyPower(POWER_MANA, addvalue);
}
@@ -876,7 +876,7 @@ void Creature::RegenerateHealth()
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
AddPct(addvalue, (*i)->GetAmount());
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * REGENERATION_INTERVAL / (5 * IN_MILLISECONDS);
ModifyHealth(addvalue);
}
@@ -318,6 +318,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
static float _GetDamageMod(int32 Rank);
uint32 m_regenTimer;
float m_SightDistance, m_CombatDistance;
bool m_isTempWorldObject; //true when possessed
@@ -122,7 +122,6 @@ struct TC_GAME_API CreatureMovementData
std::string ToString() const;
};
static uint32 const CREATURE_REGEN_INTERVAL = 2 * IN_MILLISECONDS;
static uint32 const CREATURE_NOPATH_EVADE_TIME = 5 * IN_MILLISECONDS;
static uint8 const MAX_KILL_CREDIT = 2;
+1 -1
View File
@@ -641,7 +641,7 @@ void Creature::Regenerate(Powers power)
// Apply modifiers (if any).
AddPct(addvalue, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power));
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (IsHunterPet() ? PetFocusRegenInterval : CREATURE_REGEN_INTERVAL) / (5 * IN_MILLISECONDS);
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (IsHunterPet() ? PetFocusRegenInterval : REGENERATION_INTERVAL) / (5 * IN_MILLISECONDS);
ModifyPower(power, int32(addvalue));
}
+36 -124
View File
@@ -159,10 +159,7 @@ Player::Player(WorldSession* session): Unit(true)
m_comboPoints = 0;
m_regenTimer = 0;
m_regenTimerCount = 0;
m_holyPowerRegenTimerCount = 0;
m_focusRegenTimerCount = 0;
_regenerationTimer = 0;
m_foodEmoteTimerCount = 0;
m_weaponChangeTimer = 0;
@@ -1223,10 +1220,7 @@ void Player::Update(uint32 p_time)
}
if (IsAlive())
{
m_regenTimer += p_time;
RegenerateAll();
}
RegenerateAll(p_time);
if (m_deathState == JUST_DIED)
KillPlayer();
@@ -1838,24 +1832,18 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Un
return Unit::IsImmunedToSpellEffect(spellInfo, index, caster);
}
void Player::RegenerateAll()
void Player::RegenerateAll(uint32 diff)
{
//if (m_regenTimer <= 500)
// return;
_regenerationTimer += diff;
m_foodEmoteTimerCount += diff;
m_regenTimerCount += m_regenTimer;
if (getClass() == CLASS_PALADIN)
m_holyPowerRegenTimerCount += m_regenTimer;
if (getClass() == CLASS_HUNTER)
m_focusRegenTimerCount += m_regenTimer;
m_foodEmoteTimerCount += m_regenTimer;
Regenerate(POWER_ENERGY);
Regenerate(POWER_MANA);
Regenerate(POWER_FOCUS);
Regenerate(POWER_ENERGY, diff);
Regenerate(POWER_MANA, diff);
Regenerate(POWER_FOCUS, diff);
Regenerate(POWER_HOLY_POWER, diff);
Regenerate(POWER_RUNIC_POWER, diff);
Regenerate(POWER_RAGE, diff);
Regenerate(POWER_ALTERNATE_POWER, diff);
// Runes act as cooldowns, and they don't need to send any data
if (getClass() == CLASS_DEATH_KNIGHT)
@@ -1874,11 +1862,11 @@ void Player::RegenerateAll()
}
if (cd)
SetRuneCooldown(runeToRegen, (cd > (m_regenTimer * cdmod)) ? cd - (m_regenTimer * cdmod) : 0);
SetRuneCooldown(runeToRegen, (cd > (diff * cdmod)) ? cd - (diff * cdmod) : 0);
}
}
if (m_regenTimerCount >= 2000)
if (_regenerationTimer >= REGENERATION_INTERVAL)
{
// Not in combat or they have regeneration
if (!IsInCombat() || IsPolymorphed() || m_baseHealthRegen ||
@@ -1888,21 +1876,9 @@ void Player::RegenerateAll()
RegenerateHealth();
}
Regenerate(POWER_RAGE);
if (getClass() == CLASS_DEATH_KNIGHT)
Regenerate(POWER_RUNIC_POWER);
m_regenTimerCount -= 2000;
_regenerationTimer -= REGENERATION_INTERVAL;
}
if (m_holyPowerRegenTimerCount >= 10000 && getClass() == CLASS_PALADIN)
{
Regenerate(POWER_HOLY_POWER);
m_holyPowerRegenTimerCount -= 10000;
}
m_regenTimer = 0;
// Handles the emotes for drinking and eating.
// According to sniffs there is a background timer going on that repeats independed from the time window where the aura applies.
// That's why we dont need to reset the timer on apply. In sniffs I have seen that the first call for the spell visual is totally random, then after
@@ -1935,7 +1911,7 @@ void Player::RegenerateAll()
}
}
void Player::Regenerate(Powers power)
void Player::Regenerate(Powers power, uint32 diff)
{
uint32 maxValue = GetMaxPower(power);
if (!maxValue)
@@ -1943,8 +1919,8 @@ void Player::Regenerate(Powers power)
uint32 curValue = GetPower(power);
/// @todo possible use of miscvalueb instead of amount
if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power))
// Block power regeneration
if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power) || HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
return;
// Skip regeneration for power type we cannot have
@@ -1952,88 +1928,36 @@ void Player::Regenerate(Powers power)
if (powerIndex == MAX_POWERS)
return;
float addvalue = 0.0f;
// Powers now benefit from haste.
float meleeHaste = GetFloatValue(PLAYER_FIELD_MOD_HASTE);
float spellHaste = GetFloatValue(UNIT_MOD_CAST_SPEED);
float addValue = GetPowerRegen(power, IsInCombat()) * (0.001f * diff);
// Apply config values
switch (power)
{
case POWER_MANA:
{
float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA);
if (IsInCombat()) // Trinity Updates Mana in intervals of 2s, which is correct
addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * ((0.001f * m_regenTimer) + CalculatePct(0.001f, spellHaste));
else
addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * ((0.001f * m_regenTimer) + CalculatePct(0.001f, spellHaste));
addValue *= sWorld->getRate(RATE_POWER_MANA);
break;
}
case POWER_RAGE: // Regenerate rage
{
if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
{
float RageDecreaseRate = sWorld->getRate(RATE_POWER_RAGE_LOSS);
addvalue += -25 * RageDecreaseRate / meleeHaste; // 2.5 rage by tick (= 2 seconds => 1.25 rage/sec)
}
case POWER_RAGE:
addValue *= sWorld->getRate(RATE_POWER_RAGE_LOSS);
break;
}
case POWER_FOCUS:
{
float haste = (1.0f / GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN) - 1.0f) * 100.0f;
addvalue += (5.0f + CalculatePct(5.0f, haste)) * (m_regenTimer / 1000.0f);
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_HASTE_SPELLS);
break;
}
case POWER_ENERGY: // Regenerate energy (rogue)
{
float haste = (1.0f / GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN) - 1.0f) * 100.0f;
addvalue += (10.0f + CalculatePct(10.0f, haste)) * (m_regenTimer / 1000.0f);
break;
}
case POWER_RUNIC_POWER:
{
if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
{
float RunicPowerDecreaseRate = sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS);
addvalue += -30 * RunicPowerDecreaseRate; // 3 RunicPower by tick
}
addValue*= sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS);
break;
}
case POWER_HOLY_POWER: // Regenerate holy power
{
if (!IsInCombat())
addvalue += -1.0f; // remove 1 each 10 sec
case POWER_FOCUS:
addValue *= sWorld->getRate(RATE_POWER_FOCUS);
break;
}
case POWER_RUNE:
case POWER_ENERGY:
addValue *= sWorld->getRate(RATE_POWER_ENERGY);
break;
case POWER_HEALTH:
return;
default:
break;
}
// Mana regen calculated in Player::UpdateManaRegen()
if (power != POWER_MANA && power != POWER_FOCUS && power != POWER_ENERGY)
{
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if (Powers((*i)->GetMiscValue()) == power)
AddPct(addvalue, (*i)->GetAmount());
// Butchery requires combat for this effect
if (power != POWER_RUNIC_POWER || IsInCombat())
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * ((power != POWER_ENERGY) ? m_regenTimerCount : m_regenTimer) / (5 * IN_MILLISECONDS);
}
if (addvalue < 0.0f)
if (addValue < 0.0f)
{
if (curValue == 0)
return;
}
else if (addvalue > 0.0f)
else if (addValue > 0.0f)
{
if (curValue == maxValue)
return;
@@ -2041,15 +1965,15 @@ void Player::Regenerate(Powers power)
else
return;
addvalue += m_powerFraction[powerIndex];
uint32 integerValue = uint32(std::fabs(addvalue));
addValue += m_powerFraction[powerIndex];
uint32 integerValue = uint32(std::fabs(addValue));
if (addvalue < 0.0f)
if (addValue < 0.0f)
{
if (curValue > integerValue)
{
curValue -= integerValue;
m_powerFraction[powerIndex] = addvalue + integerValue;
m_powerFraction[powerIndex] = addValue + integerValue;
}
else
{
@@ -2067,10 +1991,10 @@ void Player::Regenerate(Powers power)
m_powerFraction[powerIndex] = 0;
}
else
m_powerFraction[powerIndex] = addvalue - integerValue;
m_powerFraction[powerIndex] = addValue - integerValue;
}
if (m_regenTimerCount >= 2000)
if (_regenerationTimer >= REGENERATION_INTERVAL)
SetPower(power, curValue);
else
UpdateUInt32Value(UNIT_FIELD_POWER1 + powerIndex, curValue);
@@ -25682,18 +25606,6 @@ void Player::InitRunes()
SetFloatValue(PLAYER_RUNE_REGEN_1 + i, 0.1f); // set a base regen timer equal to 10 sec
}
void Player::UpdateRuneRegeneration()
{
// Formular: base cooldown / (1 - haste)
float regeneration = 0.1f;
float haste = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (haste)
regeneration /= haste;
for (uint8 i = 0; i < NUM_RUNE_TYPES; i++)
SetFloatValue(PLAYER_RUNE_REGEN_1 + i, regeneration);
}
bool Player::IsBaseRuneSlotsOnCooldown(RuneType runeType) const
{
for (uint8 i = 0; i < MAX_RUNES; ++i)
+6 -10
View File
@@ -1515,11 +1515,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SetBindPoint(ObjectGuid guid) const;
void SendTalentWipeConfirm(ObjectGuid guid) const;
void ResetPetTalents();
void RegenerateAll();
void Regenerate(Powers power);
void RegenerateAll(uint32 diff);
void Regenerate(Powers power, uint32 diff);
void RegenerateHealth();
void setRegenTimerCount(uint32 time) {m_regenTimerCount = time;}
void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;}
void SetRegenerationTimer(uint32 time) { _regenerationTimer = time;}
void setWeaponChangeTimer(uint32 time) { m_weaponChangeTimer = time;}
uint64 GetMoney() const { return GetUInt64Value(PLAYER_FIELD_COINAGE); }
bool ModifyMoney(int64 amount, bool sendError = true);
@@ -1837,7 +1837,7 @@ 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 UpdateManaRegen();
void UpdatePowerRegeneration(Powers powerType);
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]; }
@@ -2320,7 +2320,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void ResyncRunes(uint8 count);
void AddRunePower(uint8 mask);
void InitRunes();
void UpdateRuneRegeneration();
void SendRespondInspectAchievements(Player* player) const;
uint32 GetAchievementPoints() const;
@@ -2395,13 +2394,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 GetTransportSpawnID() const { return _transportSpawnID; }
void SetTransportSpawnID(uint32 spawnId) { _transportSpawnID = spawnId; }
void ResetHolyPowerRegenerationTimer() { m_holyPowerRegenTimerCount = 0; }
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
uint32 m_regenTimerCount;
uint32 m_holyPowerRegenTimerCount;
uint32 m_focusRegenTimerCount;
uint32 _regenerationTimer;
uint32 m_foodEmoteTimerCount;
float m_powerFraction[MAX_POWERS_PER_CLASS];
uint32 m_contestedPvPTimer;
+55 -20
View File
@@ -132,7 +132,7 @@ bool Player::UpdateStats(Stats stat)
}
UpdateSpellDamageAndHealingBonus();
UpdateManaRegen();
UpdatePowerRegeneration(POWER_MANA);
// Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
uint32 mask = 0;
@@ -222,7 +222,7 @@ bool Player::UpdateAllStats()
UpdateParryPercentage();
UpdateDodgePercentage();
UpdateSpellDamageAndHealingBonus();
UpdateManaRegen();
UpdatePowerRegeneration(POWER_MANA);
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
UpdateAllResistances();
@@ -739,7 +739,7 @@ void Player::UpdateExpertise(WeaponAttackType attack)
void Player::ApplyManaRegenBonus(int32 amount, bool apply)
{
_ModifyUInt32(apply, m_baseManaRegen, amount);
UpdateManaRegen();
UpdatePowerRegeneration(POWER_MANA);
}
void Player::ApplyHealthRegenBonus(int32 amount, bool apply)
@@ -747,30 +747,65 @@ void Player::ApplyHealthRegenBonus(int32 amount, bool apply)
_ModifyUInt32(apply, m_baseHealthRegen, amount);
}
void Player::UpdateManaRegen()
void Player::UpdatePowerRegeneration(Powers powerType)
{
if (getPowerType() == POWER_MANA || getClass() == CLASS_DRUID)
uint32 powerIndex = GetPowerIndex(powerType);
if (powerIndex == MAX_POWERS && powerType != POWER_RUNE)
return;
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType);
float powerRegenModPct = GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, powerType);
switch (powerType)
{
// 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 *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
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));
// 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
float base_regen = GetCreateMana() * 0.01f + GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
// CombatRegen = 5% of Base Mana
float base_regen = GetCreateMana() * 0.01f + powerRegenMod / 5.0f;
// Set regen rate in cast state apply only on spirit based regen
int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
// Set regen rate in cast state apply only on spirit based regen
int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, base_regen + CalculatePct(spirit_regen, modManaRegenInterrupt));
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, 0.001f + spirit_regen + base_regen);
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, base_regen + CalculatePct(spirit_regen, modManaRegenInterrupt));
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, 0.001f + spirit_regen + base_regen);
break;
}
case POWER_RUNIC_POWER:
case POWER_RAGE:
// Butchery and Anger Management
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, powerRegenMod / 5.0f);
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;
}
else if (getClass() == CLASS_HUNTER)
SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, -0.2f);
}
void Player::_ApplyAllStatBonuses()
+65 -12
View File
@@ -322,7 +322,7 @@ Unit::Unit(bool isWorldObject) :
IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(),
m_ControlledByPlayer(false), movespline(new Movement::MoveSpline()),
i_AI(nullptr), i_disabledAI(nullptr), m_AutoRepeatFirstCast(false), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this),
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_ThreatManager(this),
m_vehicle(nullptr), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(),
m_HostileRefManager(this), _lastDamagedTime(0), m_spellHistory(new SpellHistory(this))
{
@@ -409,6 +409,8 @@ Unit::Unit(bool isWorldObject) :
_lastLiquid = nullptr;
_powerBarId = 0;
_oldFactionId = 0;
_isWalkingBeforeCharm = false;
}
@@ -860,7 +862,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// Rage from Damage made (only from direct weapon damage)
if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && getPowerType() == POWER_RAGE)
{
uint32 rage = uint32(GetAttackTime(cleanDamage->attackType) / 1000 * 8.125f);
uint32 rage = uint32(GetAttackTime(cleanDamage->attackType) / 1000 * 6.5f);
// Sentinel
if (victim->GetVictim() && victim->GetVictim() != this)
@@ -6651,9 +6653,6 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers po
// needs to be called after sending spell log
victim->ModifyPower(powerType, damage);
if (powerType == POWER_HOLY_POWER && GetTypeId() == TYPEID_PLAYER)
ToPlayer()->ResetHolyPowerRegenerationTimer();
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo);
}
@@ -8902,6 +8901,61 @@ int32 Unit::ModifyPowerPct(Powers power, float pct, bool apply)
return ModifyPower(power, (int32)amount - GetMaxPower(power));
}
inline float 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
float combatRegeneration = result;
powerSlot = GetPowerIndex(powerType);
if (powerSlot != MAX_POWERS)
{
uint32 powerRegenIndex = isInCombat ? UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER : UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER;
totalRegeneration = GetFloatValue(powerRegenIndex + powerSlot) + combatRegeneration;
result = totalRegeneration;
}
else
totalRegeneration = result;
if (IsPlayer() && (powerType == POWER_ENERGY || powerType == POWER_FOCUS))
{
float hasteRegen = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN);
if (hasteRegen != 0.f)
result = totalRegeneration / hasteRegen;
}
return result;
}
uint32 Unit::GetAttackTime(WeaponAttackType att) const
{
float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + att) / m_modAttackSpeedPct[att];
@@ -11303,7 +11357,7 @@ void Unit::ApplyHasteRegenMod(WeaponAttackType att, float val, bool apply)
}
if (getClass() == CLASS_DEATH_KNIGHT)
ToPlayer()->UpdateRuneRegeneration();
ToPlayer()->UpdatePowerRegeneration(POWER_RUNE);
}
void Unit::ApplyCastTimePercentMod(float val, bool apply)
@@ -13995,21 +14049,20 @@ void Unit::RewardRage(uint32 baseRage, bool attacker)
if (attacker)
{
addRage = baseRage;
// talent who gave more rage on attack
// Additional rage from attacks (e.g. Anger Management)
AddPct(addRage, GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT));
}
else
{
// Calculate rage from health and damage taken
//! ToDo: Check formula
addRage = floor(0.5f + (25.7f * baseRage / GetMaxHealth()));
// Berserker Rage effect
// Calculate rage from health and damage taken (formular taken from SimulationCraft)
addRage = baseRage * 18.92 / GetMaxHealth();
// Berserker Rage
if (HasAura(18499))
addRage *= 2.0f;
}
addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
ModifyPower(POWER_RAGE, uint32(addRage * 10));
}
+4 -1
View File
@@ -1110,9 +1110,12 @@ class TC_GAME_API Unit : public WorldObject
int32 CountPctFromMaxPower(Powers power, int32 pct) const { return CalculatePct(GetMaxPower(power), pct); }
void SetPower(Powers power, int32 val);
void SetMaxPower(Powers power, int32 val);
void SetPowerBarID(uint32 id) { _powerBarId = id; }
// returns the change in power
int32 ModifyPower(Powers power, int32 val);
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
float GetPowerRegen(Powers powerType, bool isInCombat) const;
uint32 GetAttackTime(WeaponAttackType att) const;
void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att, val*m_modAttackSpeedPct[att]); }
@@ -1983,7 +1986,6 @@ class TC_GAME_API Unit : public WorldObject
MotionMaster* i_motionMaster;
uint32 m_reactiveTimer[MAX_REACTIVE];
uint32 m_regenTimer;
ThreatManager m_ThreatManager;
@@ -1992,6 +1994,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 m_unitTypeMask;
LiquidTypeEntry const* _lastLiquid;
uint32 _powerBarId;
bool IsAlwaysVisibleFor(WorldObject const* seer) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
@@ -24,7 +24,7 @@
struct VehicleSeatEntry;
enum PowerType
enum PowerType : uint32
{
POWER_STEAM = 61,
POWER_PYRITE = 41,
@@ -245,6 +245,7 @@ enum Powers
};
#define MAX_POWERS_PER_CLASS 5
#define REGENERATION_INTERVAL 2 * IN_MILLISECONDS
enum SpellSchools
{
@@ -2178,7 +2178,7 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode,
// for players, start regeneration after 1s (in polymorph fast regeneration case)
// only if caster is Player (after patch 2.4.2)
if (GetCasterGUID().IsPlayer())
target->ToPlayer()->setRegenTimerCount(1*IN_MILLISECONDS);
target->ToPlayer()->SetRegenerationTimer(1 * IN_MILLISECONDS);
//dismount polymorphed target (after patch 2.4.2)
if (target->IsMounted())
@@ -3638,22 +3638,17 @@ void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mod
/********************************/
/*** HEAL & ENERGIZE ***/
/********************************/
void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
if (target->GetTypeId() != TYPEID_PLAYER)
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target)
return;
// Update manaregen value
if (GetMiscValue() == POWER_MANA)
target->ToPlayer()->UpdateManaRegen();
else if (GetMiscValue() == POWER_RUNE)
target->ApplyPercentModFloatValue(PLAYER_RUNE_REGEN_1 + GetMiscValueB(), float(GetAmount()), apply);
// other powers are not immediate effects - implemented in Player::Regenerate, Creature::Regenerate
// Update power regen values
target->UpdatePowerRegeneration(Powers(GetMiscValue()));
}
void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3678,7 +3673,7 @@ void AuraEffect::HandleModManaRegen(AuraApplication const* aurApp, uint8 mode, b
return;
//Note: an increase in regen does NOT cause threat.
target->ToPlayer()->UpdateManaRegen();
target->ToPlayer()->UpdatePowerRegeneration(POWER_MANA);
}
void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -6338,13 +6333,18 @@ void AuraEffect::HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode,
if (!powerEntry)
return;
Unit* target = aurApp->GetTarget();
if (apply)
{
aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, powerEntry->MaxPower);
aurApp->GetTarget()->SetPower(POWER_ALTERNATE_POWER, powerEntry->StartPower);
target->SetMaxPower(POWER_ALTERNATE_POWER, powerEntry->MaxPower);
target->SetPower(POWER_ALTERNATE_POWER, powerEntry->StartPower);
target->SetPowerBarID(altPowerId);
}
else
aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, 0);
{
target->SetMaxPower(POWER_ALTERNATE_POWER, 0);
target->SetPowerBarID(0);
}
}
void AuraEffect::HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const