diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 9c94a2648..f02423509 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -2084,7 +2084,8 @@ namespace Framework.Constants { CooldownScalesWithWeaponSpeed = 0x01, // unused CooldownStartsOnEvent = 0x04, - CooldownExpiresAtDailyReset = 0x08 + CooldownExpiresAtDailyReset = 0x08, + IgnoreForModTimeRate = 0x40 } [Flags] diff --git a/Source/Framework/Constants/Spells/SpellAuraConst.cs b/Source/Framework/Constants/Spells/SpellAuraConst.cs index 8d0df37bc..52bb99daa 100644 --- a/Source/Framework/Constants/Spells/SpellAuraConst.cs +++ b/Source/Framework/Constants/Spells/SpellAuraConst.cs @@ -180,7 +180,7 @@ namespace Framework.Constants DetectAmore = 170, ModSpeedNotStack = 171, ModMountedSpeedNotStack = 172, - ModRecoveryRate2 = 173, // NYI + ModChargeRecoveryRateByTypeMask = 173, ModSpellDamageOfStatPercent = 174, // By Defeult Intelect, Dependent From ModSpellHealingOfStatPercent ModSpellHealingOfStatPercent = 175, SpiritOfRedemption = 176, @@ -212,7 +212,7 @@ namespace Framework.Constants IgnoreCombatResult = 202, PreventInterrupt = 203, // NYI PreventCorpseRelease = 204, // NYI - ModChargeCooldown = 205, // NYI + ModChargeRecoveryByTypeMask = 205, ModIncreaseVehicleFlightSpeed = 206, ModIncreaseMountedFlightSpeed = 207, ModIncreaseFlightSpeed = 208, diff --git a/Source/Game/Networking/Packets/SpellPackets.cs b/Source/Game/Networking/Packets/SpellPackets.cs index 0d89ef0f0..78a70f563 100644 --- a/Source/Game/Networking/Packets/SpellPackets.cs +++ b/Source/Game/Networking/Packets/SpellPackets.cs @@ -527,6 +527,25 @@ namespace Game.Networking.Packets } } + class UpdateChargeCategoryCooldown : ServerPacket + { + public uint Category; + public float ModChange = 1.0f; + public float ModRate = 1.0f; + public bool Snapshot; + + public UpdateChargeCategoryCooldown() : base(ServerOpcodes.UpdateChargeCategoryCooldown) { } + + public override void Write() + { + _worldPacket.WriteUInt32(Category); + _worldPacket.WriteFloat(ModChange); + _worldPacket.WriteFloat(ModRate); + _worldPacket.WriteBit(Snapshot); + _worldPacket.FlushBits(); + } + } + public class SpellCooldownPkt : ServerPacket { public SpellCooldownPkt() : base(ServerOpcodes.SpellCooldown, ConnectionType.Instance) { } diff --git a/Source/Game/Spells/SpellHistory.cs b/Source/Game/Spells/SpellHistory.cs index de283ff47..9bc6c054a 100644 --- a/Source/Game/Spells/SpellHistory.cs +++ b/Source/Game/Spells/SpellHistory.cs @@ -888,6 +888,45 @@ namespace Game.Spells SendSetSpellCharges(chargeCategoryId, chargeList); } + void UpdateChargeRecoveryRate(uint chargeCategoryId, float modChange, bool apply) + { + var categoryCharges = _categoryCharges.LookupByKey(chargeCategoryId); + if (categoryCharges == null || categoryCharges.Empty()) + return; + + if (modChange <= 0.0f) + return; + + if (!apply) + modChange = 1.0f / modChange; + + DateTime now = GameTime.GetDateAndTime(); + + var chargeIndex = 0; + var categoryEntry = categoryCharges[chargeIndex]; + categoryEntry.RechargeEnd = now + TimeSpan.FromMilliseconds((categoryEntry.RechargeEnd - now).TotalMilliseconds * modChange); + + DateTime prevEnd = categoryCharges[chargeIndex].RechargeEnd; + + while (++chargeIndex != categoryCharges.Count - 1) + { + categoryEntry = categoryCharges[chargeIndex]; + TimeSpan rechargeTime = TimeSpan.FromMilliseconds((categoryEntry.RechargeEnd - categoryEntry.RechargeStart).TotalMilliseconds * modChange); + categoryEntry.RechargeStart = prevEnd; + categoryEntry.RechargeEnd = prevEnd + rechargeTime; + prevEnd = categoryEntry.RechargeEnd; + } + + Player playerOwner = GetPlayerOwner(); + if (playerOwner != null) + { + UpdateChargeCategoryCooldown updateChargeCategoryCooldown = new(); + updateChargeCategoryCooldown.Category = chargeCategoryId; + updateChargeCategoryCooldown.ModChange = modChange; + playerOwner.SendPacket(updateChargeCategoryCooldown); + } + } + public void RestoreCharge(uint chargeCategoryId) { var chargeList = _categoryCharges.LookupByKey(chargeCategoryId); @@ -967,6 +1006,10 @@ namespace Game.Spells int recoveryTime = chargeCategoryEntry.ChargeRecoveryTime; recoveryTime += _owner.GetTotalAuraModifierByMiscValue(AuraType.ChargeRecoveryMod, (int)chargeCategoryId); + foreach (AuraEffect modRecoveryRate in _owner.GetAuraEffectsByType(AuraType.ModChargeRecoveryByTypeMask)) + if ((modRecoveryRate.GetMiscValue() & chargeCategoryEntry.TypeMask) != 0) + recoveryTime += modRecoveryRate.GetAmount(); + float recoveryTimeF = recoveryTime; recoveryTimeF *= _owner.GetTotalAuraMultiplierByMiscValue(AuraType.ChargeRecoveryMultiplier, (int)chargeCategoryId); @@ -976,6 +1019,19 @@ namespace Game.Spells if (_owner.HasAuraTypeWithMiscvalue(AuraType.ChargeRecoveryAffectedByHasteRegen, (int)chargeCategoryId)) recoveryTimeF *= _owner.m_unitData.ModHasteRegen; + foreach (AuraEffect modRecoveryRate in _owner.GetAuraEffectsByType(AuraType.ModChargeRecoveryRate)) + if (modRecoveryRate.GetMiscValue() == chargeCategoryId) + recoveryTimeF *= 100.0f / (Math.Max(modRecoveryRate.GetAmount(), -99.0f) + 100.0f); + + foreach (AuraEffect modRecoveryRate in _owner.GetAuraEffectsByType(AuraType.ModChargeRecoveryRateByTypeMask)) + if ((modRecoveryRate.GetMiscValue() & chargeCategoryEntry.TypeMask) != 0) + recoveryTimeF *= 100.0f / (Math.Max(modRecoveryRate.GetAmount(), -99.0f) + 100.0f); + + if (TimeSpan.FromMilliseconds(chargeCategoryEntry.ChargeRecoveryTime) <= TimeSpan.FromHours(1) + && !chargeCategoryEntry.HasFlag(SpellCategoryFlags.IgnoreForModTimeRate) + && !chargeCategoryEntry.HasFlag(SpellCategoryFlags.CooldownExpiresAtDailyReset)) + recoveryTimeF *= _owner.m_unitData.ModTimeRate; + return (int)Math.Floor(recoveryTimeF); } diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index c9d934499..6243b222a 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -3592,7 +3592,7 @@ namespace Game.Spells case AuraType.ModWeaponCritPercent: case AuraType.PowerBurn: case AuraType.ModCooldown: - case AuraType.ModChargeCooldown: + case AuraType.ModChargeRecoveryByTypeMask: case AuraType.ModIncreaseSpeed: case AuraType.ModParryPercent: case AuraType.SetVehicleId: