Core/Units: reworked creature power regeneration handling

* players and creatures now share the same power regeneration regeneration function
* UpdatePowerRegeneration is now virtual and handles creature and player specific formulas individually
* handle update field flag UF_FLAG_UNIT_ALL to handle UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER and UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER for creatures as well
This commit is contained in:
Ovahlord committed 2020-04-27 14:20:33 +02:00
1 parent 902d373de5
commit e7ba484fcf
14 files changed
+188 -241

No files matched your search

+15 -56
View File
@@ -205,7 +205,6 @@ 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 = REGENERATION_INTERVAL;
m_valuesCount = UNIT_END;
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
@@ -213,6 +212,7 @@ m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(fa
DisableReputationGain = false;
_healthRegenerationTimer = UNIT_HEALTH_REGENERATION_INTERVAL;
m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
m_CombatDistance = 0;//MELEE_RANGE;
@@ -248,6 +248,8 @@ void Creature::AddToWorld()
if (GetZoneScript())
GetZoneScript()->OnCreatureCreate(this);
UpdatePowerRegeneration(GetPowerType());
}
}
@@ -771,33 +773,22 @@ void Creature::Update(uint32 diff)
if (!IsAlive())
break;
if (m_regenTimer > 0)
_healthRegenerationTimer -= diff;
if (_healthRegenerationTimer <= 0)
{
if (diff >= m_regenTimer)
m_regenTimer = 0;
else
m_regenTimer -= diff;
}
bool isInCombat = IsInCombat() && (!GetVictim() || // if IsInCombat() is true and this has no victim
!EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() || // or the victim/owner/charmer is not a player
!EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->IsGameMaster()); // or the victim/owner/charmer is not a GameMaster
if (m_regenTimer == 0)
{
bool bInCombat = IsInCombat() && (!GetVictim() || // if IsInCombat() is true and this has no victim
!EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() || // or the victim/owner/charmer is not a player
!EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->IsGameMaster()); // or the victim/owner/charmer is not a GameMaster
if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed() || CanNotReachTarget())) // regenerate health if not in combat or if polymorphed
if (!IsInEvadeMode() && (!isInCombat || IsPolymorphed() || CanNotReachTarget())) // regenerate health if not in combat or if polymorphed
RegenerateHealth();
if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER))
{
if (GetPowerType() == POWER_ENERGY)
Regenerate(POWER_ENERGY);
else
RegenerateMana();
}
m_regenTimer = REGENERATION_INTERVAL;
_healthRegenerationTimer += UNIT_HEALTH_REGENERATION_INTERVAL;
}
if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER))
Regenerate(GetPowerType(), diff);
// Update serverside orientation of channeled spells that are suposed to track the channel target
if (Spell const* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR1_CHANNEL_TRACK_TARGET))
@@ -819,38 +810,6 @@ void Creature::Update(uint32 diff)
}
}
void Creature::RegenerateMana()
{
uint32 curValue = GetPower(POWER_MANA);
uint32 maxValue = GetMaxPower(POWER_MANA);
if (curValue >= maxValue)
return;
uint32 addvalue = 0;
// Combat and any controlled creature
if (IsInCombat() || GetCharmerOrOwnerGUID())
{
float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA);
float Spirit = GetStat(STAT_SPIRIT);
addvalue = uint32((Spirit / 5.0f + 17.0f) * ManaIncreaseRate);
}
else
addvalue = maxValue / 3;
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if ((*i)->GetMiscValue() == POWER_MANA)
AddPct(addvalue, (*i)->GetAmount());
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) * REGENERATION_INTERVAL / (5 * IN_MILLISECONDS);
ModifyPower(POWER_MANA, addvalue);
}
void Creature::RegenerateHealth()
{
if (!isRegeneratingHealth())
@@ -876,14 +835,14 @@ void Creature::RegenerateHealth()
addvalue = uint32(Spirit * 0.80 * HealthIncreaseRate);
}
else
addvalue = maxValue/3;
addvalue = maxValue / 3;
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
AddPct(addvalue, (*i)->GetAmount());
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * REGENERATION_INTERVAL / (5 * IN_MILLISECONDS);
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * UNIT_HEALTH_REGENERATION_INTERVAL / (5 * IN_MILLISECONDS);
ModifyHealth(addvalue);
}
+4 -4
View File
@@ -146,6 +146,7 @@ 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) override;
void UpdatePowerRegeneration(Powers powerType) override;
void SetCanDualWield(bool value) override;
int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
@@ -319,8 +320,9 @@ 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;
int32 _healthRegenerationTimer;
float m_SightDistance;
float m_CombatDistance;
bool m_isTempWorldObject; //true when possessed
@@ -369,9 +371,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
uint32 m_combatPulseDelay; // (secs) how often the creature puts the entire zone in combat (only works in dungeons)
ReactStates m_reactState; // for AI, not charmInfo
void RegenerateMana();
void RegenerateHealth();
void Regenerate(Powers power);
MovementGeneratorType m_defaultMovementType;
ObjectGuid::LowType m_spawnId; ///< For new or temporary creatures is 0 for saved it is lowguid
uint8 m_equipmentId;
@@ -748,6 +748,9 @@ uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const
if (plr && plr->IsInSameRaidWith(target))
visibleFlag |= UF_FLAG_PARTY_MEMBER;
if (IsCreature())
visibleFlag |= UF_FLAG_UNIT_ALL;
break;
}
case TYPEID_GAMEOBJECT:
@@ -209,16 +209,16 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] =
UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER3
UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER4
UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER5
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+1
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+2
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+3
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+4
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+1
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+2
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+3
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+4
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+1
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+2
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+3
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+4
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+1
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+2
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+3
UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNIT_ALL, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+4
UF_FLAG_PUBLIC, // UNIT_FIELD_LEVEL
UF_FLAG_PUBLIC, // UNIT_FIELD_FACTIONTEMPLATE
UF_FLAG_PUBLIC, // UNIT_VIRTUAL_ITEM_SLOT_ID
@@ -31,7 +31,7 @@ enum UpdatefieldFlags
UF_FLAG_ITEM_OWNER = 0x010,
UF_FLAG_SPECIAL_INFO = 0x020,
UF_FLAG_PARTY_MEMBER = 0x040,
UF_FLAG_UNUSED2 = 0x080,
UF_FLAG_UNIT_ALL = 0x080,
UF_FLAG_DYNAMIC = 0x100
};
-43
View File
@@ -54,7 +54,6 @@ Pet::Pet(Player* owner, PetType type) :
}
m_name = "Pet";
m_petFocusRegenTimer = PetFocusRegenInterval;
}
Pet::~Pet()
@@ -594,16 +593,6 @@ void Pet::Update(uint32 diff)
}
}
// Regenerate Focus
m_petFocusRegenTimer -= diff;
if (m_petFocusRegenTimer <= 0)
{
if (GetPowerType() == POWER_FOCUS)
Regenerate(POWER_FOCUS);
m_petFocusRegenTimer += PetFocusRegenInterval;
}
break;
}
default:
@@ -612,38 +601,6 @@ void Pet::Update(uint32 diff)
Creature::Update(diff);
}
void Creature::Regenerate(Powers power)
{
uint32 curValue = GetPower(power);
uint32 maxValue = GetMaxPower(power);
if (curValue >= maxValue)
return;
float addvalue = 0.0f;
switch (power)
{
case POWER_FOCUS:
addvalue = 5 * sWorld->getRate(RATE_POWER_FOCUS);
break;
case POWER_ENERGY:
addvalue = 20;
// For Death Knight Ghouls
if (GetEntry() == 26125)
if (Unit* owner = GetOwner())
AddPct(addvalue, (1.0f / owner->ToPlayer()->GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN) - 1.0f) * 100.0f);
break;
default:
return;
}
// Apply modifiers (if any).
AddPct(addvalue, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power));
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (IsHunterPet() ? PetFocusRegenInterval : REGENERATION_INTERVAL) / (5 * IN_MILLISECONDS);
ModifyPower(power, int32(addvalue));
}
void Pet::Remove(PetSaveMode mode, bool returnreagent)
{
GetOwner()->RemovePet(this, mode, returnreagent);
-3
View File
@@ -21,8 +21,6 @@
#include "PetDefines.h"
#include "TemporarySummon.h"
static constexpr uint32 const PetFocusRegenInterval = 1 * IN_MILLISECONDS;
enum StableResultCode
{
STABLE_ERR_MONEY = 0x01, // "you don't have enough money"
@@ -174,7 +172,6 @@ class TC_GAME_API Pet : public Guardian
int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets)
uint64 m_auraRaidUpdateMask;
bool m_loading;
int32 m_petFocusRegenTimer;
DeclinedName* m_declinedname;
uint32 m_petSlot;
-107
View File
@@ -159,7 +159,6 @@ Player::Player(WorldSession* session): Unit(true)
m_comboPoints = 0;
_regenerationTimer = 0;
m_foodEmoteTimerCount = 0;
m_weaponChangeTimer = 0;
@@ -339,9 +338,6 @@ Player::Player(WorldSession* session): Unit(true)
m_ChampioningFaction = 0;
for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
m_powerFraction[i] = 0;
isDebugAreaTriggers = false;
m_WeeklyQuestChanged = false;
@@ -1822,7 +1818,6 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Un
void Player::RegenerateAll(uint32 diff)
{
_regenerationTimer += diff;
m_foodEmoteTimerCount += diff;
Regenerate(POWER_ENERGY, diff);
@@ -1854,19 +1849,6 @@ void Player::RegenerateAll(uint32 diff)
}
}
if (_regenerationTimer >= REGENERATION_INTERVAL)
{
// Not in combat or they have regeneration
if (!IsInCombat() || IsPolymorphed() || m_baseHealthRegen ||
HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) ||
HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT))
{
RegenerateHealth();
}
_regenerationTimer -= REGENERATION_INTERVAL;
}
// 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
@@ -1899,95 +1881,6 @@ void Player::RegenerateAll(uint32 diff)
}
}
void Player::Regenerate(Powers power, uint32 diff)
{
uint32 maxValue = GetMaxPower(power);
if (!maxValue)
return;
uint32 curValue = GetPower(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
uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return;
float addValue = GetPowerRegen(power, IsInCombat()) * (0.001f * diff);
// Apply config values
switch (power)
{
case POWER_MANA:
addValue *= sWorld->getRate(RATE_POWER_MANA);
break;
case POWER_RAGE:
addValue *= sWorld->getRate(RATE_POWER_RAGE_LOSS);
break;
case POWER_RUNIC_POWER:
addValue*= sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS);
break;
case POWER_FOCUS:
addValue *= sWorld->getRate(RATE_POWER_FOCUS);
break;
case POWER_ENERGY:
addValue *= sWorld->getRate(RATE_POWER_ENERGY);
break;
default:
break;
}
if (addValue < 0.0f)
{
if (curValue == 0)
return;
}
else if (addValue > 0.0f)
{
if (curValue == maxValue)
return;
}
else
return;
addValue += m_powerFraction[powerIndex];
uint32 integerValue = uint32(std::fabs(addValue));
if (addValue < 0.0f)
{
if (curValue > integerValue)
{
curValue -= integerValue;
m_powerFraction[powerIndex] = addValue + integerValue;
}
else
{
curValue = 0;
m_powerFraction[powerIndex] = 0;
}
}
else
{
curValue += integerValue;
if (curValue > maxValue)
{
curValue = maxValue;
m_powerFraction[powerIndex] = 0;
}
else
m_powerFraction[powerIndex] = addValue - integerValue;
}
if (_regenerationTimer >= REGENERATION_INTERVAL)
SetPower(power, curValue);
else
UpdateUInt32Value(UNIT_FIELD_POWER1 + powerIndex, curValue);
}
void Player::RegenerateHealth()
{
uint32 curValue = GetHealth();
+1 -4
View File
@@ -1515,7 +1515,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SendTalentWipeConfirm(ObjectGuid guid) const;
void ResetPetTalents();
void RegenerateAll(uint32 diff);
void Regenerate(Powers power, uint32 diff);
void RegenerateHealth();
void SetRegenerationTimer(uint32 time) { _regenerationTimer = time;}
void setWeaponChangeTimer(uint32 time) { m_weaponChangeTimer = time;}
@@ -1837,7 +1836,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 UpdatePowerRegeneration(Powers powerType);
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]; }
@@ -2397,9 +2396,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
uint32 _regenerationTimer;
uint32 m_foodEmoteTimerCount;
float m_powerFraction[MAX_POWERS_PER_CLASS];
uint32 m_contestedPvPTimer;
/*********************************************************/
+35 -5
View File
@@ -762,7 +762,7 @@ void Player::UpdatePowerRegeneration(Powers powerType)
if (powerIndex == MAX_POWERS && powerType != POWER_RUNE)
return;
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType);
float powerRegenMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, powerType) / 5.f;
float powerRegenModPct = GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, powerType);
switch (powerType)
@@ -778,20 +778,20 @@ void Player::UpdatePowerRegeneration(Powers powerType)
if (GetStat(STAT_INTELLECT) > 0.0f)
spirit_regen *= std::sqrt(GetStat(STAT_INTELLECT));
// CombatRegen = 5% of Base Mana
float base_regen = GetCreateMana() * 0.01f + powerRegenMod / 5.0f;
// 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);
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);
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + powerIndex, 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);
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + powerIndex, powerRegenMod);
break;
case POWER_RUNE:
{
@@ -913,6 +913,36 @@ 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() || GetOwnerGUID())
{
float spiritRegen = (GetStat(STAT_SPIRIT) / 5.f + 17.f) * sWorld->getRate(RATE_POWER_MANA);
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:
{
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;
+104
View File
@@ -413,6 +413,11 @@ Unit::Unit(bool isWorldObject) :
_powerBarId = 0;
for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
_powerFraction[i] = 0;
_regenerationTimer = 0;
_oldFactionId = 0;
_isWalkingBeforeCharm = false;
}
@@ -543,6 +548,12 @@ void Unit::Update(uint32 p_time)
if (ObjectGuid guid = GetChannelObjectGuid())
if (WorldObject* target = ObjectAccessor::GetWorldObject(*this, guid))
SetOrientation(GetAngle(target));
// Update Power regeneration interval
if (_regenerationTimer >= int32(GetRegenerationInterval()))
_regenerationTimer -= (GetRegenerationInterval() - p_time);
else
_regenerationTimer += p_time;
}
bool Unit::haveOffhandWeapon() const
@@ -10265,6 +10276,96 @@ int32 Unit::GetCreatePowers(Powers power) const
return 0;
}
void Unit::Regenerate(Powers powerType, uint32 diff)
{
uint32 maxValue = GetMaxPower(powerType);
if (!maxValue)
return;
uint32 curValue = GetPower(powerType);
// Block power regeneration
if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, powerType) || HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
return;
// Skip regeneration for power type we cannot have
uint32 powerIndex = GetPowerIndex(powerType);
if (powerIndex == MAX_POWERS)
return;
float addValue = GetPowerRegen(powerType, IsInCombat()) * (diff / float(IN_MILLISECONDS));
// Apply config values
switch (powerType)
{
case POWER_MANA:
addValue *= sWorld->getRate(RATE_POWER_MANA);
break;
case POWER_RAGE:
addValue *= sWorld->getRate(RATE_POWER_RAGE_LOSS);
break;
case POWER_RUNIC_POWER:
addValue*= sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS);
break;
case POWER_FOCUS:
addValue *= sWorld->getRate(RATE_POWER_FOCUS);
break;
case POWER_ENERGY:
addValue *= sWorld->getRate(RATE_POWER_ENERGY);
break;
default:
break;
}
if (addValue < 0.0f)
{
if (curValue == 0)
return;
}
else if (addValue > 0.0f)
{
if (curValue == maxValue)
return;
}
else
return;
addValue += _powerFraction[powerIndex];
uint32 integerValue = uint32(std::fabs(addValue));
if (addValue < 0.0f)
{
if (curValue > integerValue)
{
curValue -= integerValue;
_powerFraction[powerIndex] = addValue + integerValue;
}
else
{
curValue = 0;
_powerFraction[powerIndex] = 0;
}
}
else
{
curValue += integerValue;
if (curValue > maxValue)
{
curValue = maxValue;
_powerFraction[powerIndex] = 0;
}
else
_powerFraction[powerIndex] = addValue - integerValue;
}
// Players update their powers in 2 seconds intervals, creatures in 1 second ones
if (_regenerationTimer >= int32(GetRegenerationInterval()))
SetPower(powerType, curValue);
else
UpdateUInt32Value(UNIT_FIELD_POWER1 + powerIndex, curValue);
}
void Unit::RemoveFromWorld()
{
// cleanup
@@ -14500,6 +14601,9 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
if (plr && plr->IsInSameRaidWith(target))
visibleFlag |= UF_FLAG_PARTY_MEMBER;
if (IsCreature())
visibleFlag |= UF_FLAG_UNIT_ALL;
Creature const* creature = ToCreature();
for (uint16 index = 0; index < valCount; ++index)
{
+10
View File
@@ -1057,6 +1057,8 @@ 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; }
@@ -1113,6 +1115,8 @@ class TC_GAME_API Unit : public WorldObject
void SetPower(Powers power, int32 val);
void SetMaxPower(Powers power, int32 val);
void SetPowerBarID(uint32 id) { _powerBarId = id; }
void Regenerate(Powers powerType, uint32 diff);
inline void SetFullPower(Powers power) { SetPower(power, GetMaxPower(power)); }
// returns the change in power
@@ -1927,6 +1931,7 @@ class TC_GAME_API Unit : public WorldObject
virtual void Whisper(uint32 textId, Player* target, bool isBossWhisper = false);
float GetCollisionHeight() const override;
protected:
explicit Unit (bool isWorldObject);
@@ -1999,6 +2004,8 @@ class TC_GAME_API Unit : public WorldObject
uint32 m_unitTypeMask;
LiquidTypeEntry const* _lastLiquid;
uint32 _powerBarId;
float _powerFraction[MAX_POWERS_PER_CLASS];
int32 _regenerationTimer;
bool IsAlwaysVisibleFor(WorldObject const* seer) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
@@ -2009,6 +2016,7 @@ class TC_GAME_API Unit : public WorldObject
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData);
void InterruptMovementBasedAuras();
private:
void UpdateSplineMovement(uint32 t_diff);
@@ -2020,6 +2028,8 @@ class TC_GAME_API Unit : public WorldObject
void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType);
uint32 GetRegenerationInterval() const { return IsPlayer() ? PLAYER_REGENERATION_INTERVAL : UNIT_REGENERATION_INTERVAL; }
protected:
void SetFeared(bool apply);
void SetConfused(bool apply);
@@ -245,8 +245,10 @@ enum Powers
POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value)
};
#define MAX_POWERS_PER_CLASS 5
#define REGENERATION_INTERVAL 2 * IN_MILLISECONDS
#define MAX_POWERS_PER_CLASS 5
#define PLAYER_REGENERATION_INTERVAL 2 * IN_MILLISECONDS
#define UNIT_REGENERATION_INTERVAL 1 * IN_MILLISECONDS
#define UNIT_HEALTH_REGENERATION_INTERVAL 2 * IN_MILLISECONDS
enum SpellSchools
{
@@ -3644,12 +3644,8 @@ void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode,
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target)
return;
// Update power regen values
target->UpdatePowerRegeneration(Powers(GetMiscValue()));
aurApp->GetTarget()->UpdatePowerRegeneration(Powers(GetMiscValue()));
}
void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3659,7 +3655,6 @@ void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mod
if (target->GetTypeId() == TYPEID_PLAYER)
target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, GetAmount(), !apply);
HandleModPowerRegen(aurApp, mode, apply);
}