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:
1 parent
902d373de5
commit
e7ba484fcf
14 files changed
+188
-241
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user