diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 9c1c97d8e..21236f886 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -2538,7 +2538,7 @@ namespace Framework.Constants { None = 0x0, - Heartbeat = 0x01, // 00 Killed by agressor - not sure about this flag + Heartbeat = 0x01, // 00 Heartbeat Kill = 0x02, // 01 Kill target (in most cases need XP/Honor reward) DealMeleeSwing = 0x04, // 02 Done melee auto attack diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 89415eca1..c180de319 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -148,7 +148,6 @@ namespace Game.Entities AttackSwingErr? m_swingErrorMsg; DateTime m_regenInterruptTimestamp; uint m_regenTimerCount; - uint m_foodEmoteTimerCount; uint m_weaponChangeTimer; //Quest diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 6837d01c9..d753b03e3 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -3484,7 +3484,6 @@ namespace Game.Entities void RegenerateAll() { m_regenTimerCount += RegenTimer; - m_foodEmoteTimerCount += RegenTimer; for (PowerType power = PowerType.Mana; power < PowerType.Max; power++)// = power + 1) if (power != PowerType.Runes) @@ -3521,33 +3520,8 @@ namespace Game.Entities } 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 - // 5 seconds over and over again which confirms my theory that we have a independed timer. - if (m_foodEmoteTimerCount >= 5000) - { - List auraList = GetAuraEffectsByType(AuraType.ModRegen); - auraList.AddRange(GetAuraEffectsByType(AuraType.ModPowerRegen)); - - foreach (var auraEffect in auraList) - { - // Food emote comes above drinking emote if we have to decide (mage regen food for example) - if (auraEffect.GetBase().HasEffectType(AuraType.ModRegen) && auraEffect.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing)) - { - SendPlaySpellVisualKit(SpellConst.VisualKitFood, 0, 0); - break; - } - else if (auraEffect.GetBase().HasEffectType(AuraType.ModPowerRegen) && auraEffect.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing)) - { - SendPlaySpellVisualKit(SpellConst.VisualKitDrink, 0, 0); - break; - } - } - m_foodEmoteTimerCount -= 5000; - } } + void Regenerate(PowerType power) { // Skip regeneration for power type we cannot have diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 2eb5b00fa..84efcfa30 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -2561,6 +2561,17 @@ namespace Game.Entities // SMSG_FLIGHT_SPLINE_SYNC for cyclic splines SendFlightSplineSyncUpdate(); + + // Trigger heartbeat procs and generic aura behavior such as food emotes + TriggerAuraHeartbeat(); + } + + void TriggerAuraHeartbeat() + { + foreach (var (_, auraApplication) in m_appliedAuras) + auraApplication.GetBase().Heartbeat(); + + Unit.ProcSkillsAndAuras(this, null, new ProcFlagsInit(ProcFlags.Heartbeat), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } public bool HaveOffhandWeapon() diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index 3571c2ba2..cb0c534bf 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -364,6 +364,8 @@ namespace Game.Spells // m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs } + public virtual void Heartbeat() { } + public T GetScript() where T : AuraScript { return (T)GetScriptByType(typeof(T)); @@ -2863,6 +2865,28 @@ namespace Game.Spells _staticApplications[target.GetGUID()] |= effMask; } + void Heartbeat() + { + base.Heartbeat(); + + // Periodic food and drink emote animation + HandlePeriodicFoodSpellVisualKit(); + } + + void HandlePeriodicFoodSpellVisualKit() + { + SpellSpecificType specificType = GetSpellInfo().GetSpellSpecific(); + + bool food = specificType == SpellSpecificType.Food || specificType == SpellSpecificType.FoodAndDrink; + bool drink = specificType == SpellSpecificType.Drink || specificType == SpellSpecificType.FoodAndDrink; + + if (food) + GetUnitOwner().SendPlaySpellVisualKit(SpellConst.VisualKitFood, 0, 0); + + if (drink) + GetUnitOwner().SendPlaySpellVisualKit(SpellConst.VisualKitDrink, 0, 0); + } + // Allow Apply Aura Handler to modify and access m_AuraDRGroup public void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; } public DiminishingGroup GetDiminishGroup() { return m_AuraDRGroup; }