aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2025-03-19 00:03:38 +0100
committerShauren <shauren.trinity@gmail.com>2025-03-19 00:03:38 +0100
commitfa75f635669df6f0aab4abef074f9e8da4b5bf06 (patch)
tree64aacb5246beaa5a6b21143b0dd462a6694c5b3c
parente0d3781989c3e9339bfc14981a57683d3010f4e0 (diff)
Core/Auras: Implemented SPELL_AURA_MOD_CHARGE_RECOVERY_RATE, SPELL_AURA_MOD_CHARGE_RECOVERY_RATE_BY_TYPE_MASK and SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK
-rw-r--r--src/server/game/DataStores/DBCEnums.h3
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp11
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h13
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraDefines.h6
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp15
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h1
-rw-r--r--src/server/game/Spells/SpellHistory.cpp54
-rw-r--r--src/server/game/Spells/SpellHistory.h1
-rw-r--r--src/server/game/Spells/SpellInfo.cpp2
10 files changed, 99 insertions, 9 deletions
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 8342b9cbe1b..054c4bbdebd 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -2085,7 +2085,8 @@ enum SpellCategoryFlags
{
SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused
SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04,
- SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_DAILY_RESET = 0x08
+ SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_DAILY_RESET = 0x08,
+ SPELL_CATEGORY_FLAG_IGNORE_FOR_MOD_TIME_RATE = 0x40
};
enum class SpellEffectAttributes
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp
index 23391e57175..e7bb499d85b 100644
--- a/src/server/game/Server/Packets/SpellPackets.cpp
+++ b/src/server/game/Server/Packets/SpellPackets.cpp
@@ -704,6 +704,17 @@ WorldPacket const* SetSpellCharges::Write()
return &_worldPacket;
}
+WorldPacket const* UpdateChargeCategoryCooldown::Write()
+{
+ _worldPacket << int32(Category);
+ _worldPacket << float(ModChange);
+ _worldPacket << float(ModRate);
+ _worldPacket << Bits<1>(Snapshot);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
+
ByteBuffer& operator<<(ByteBuffer& data, SpellChargeEntry const& chargeEntry)
{
data << uint32(chargeEntry.Category);
diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h
index 63798895ebb..5893496f13d 100644
--- a/src/server/game/Server/Packets/SpellPackets.h
+++ b/src/server/game/Server/Packets/SpellPackets.h
@@ -658,6 +658,19 @@ namespace WorldPackets
float ChargeModRate = 1.0f;
};
+ class UpdateChargeCategoryCooldown final : public ServerPacket
+ {
+ public:
+ UpdateChargeCategoryCooldown() : ServerPacket(SMSG_UPDATE_CHARGE_CATEGORY_COOLDOWN, 4 + 4 + 4 + 1) { }
+
+ WorldPacket const* Write() override;
+
+ int32 Category = 0;
+ float ModChange = 1.0f;
+ float ModRate = 1.0f;
+ bool Snapshot = false;
+ };
+
struct SpellChargeEntry
{
uint32 Category = 0;
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index c1ebd755f4c..6192dce193e 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -2202,7 +2202,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CAPTURE_POINT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CELESTIAL_BODY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARACTER_FLAGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARGE_CATEGORY_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARGE_CATEGORY_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CRAFTING_NPC_RECIPES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_DAILY_MISSION_COUNTER, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h
index 662f7d3a07f..d502faaaa67 100644
--- a/src/server/game/Spells/Auras/SpellAuraDefines.h
+++ b/src/server/game/Spells/Auras/SpellAuraDefines.h
@@ -239,7 +239,7 @@ enum AuraType : uint32
SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT2 = 145,
SPELL_AURA_ALLOW_TAME_PET_TYPE = 146,
SPELL_AURA_MECHANIC_IMMUNITY_MASK = 147,
- SPELL_AURA_MOD_CHARGE_RECOVERY_RATE = 148, // NYI
+ SPELL_AURA_MOD_CHARGE_RECOVERY_RATE = 148,
SPELL_AURA_REDUCE_PUSHBACK = 149, // Reduce Pushback
SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT = 150,
SPELL_AURA_TRACK_STEALTHED = 151, // Track Stealthed
@@ -264,7 +264,7 @@ enum AuraType : uint32
SPELL_AURA_DETECT_AMORE = 170,
SPELL_AURA_MOD_SPEED_NOT_STACK = 171,
SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK = 172,
- SPELL_AURA_MOD_RECOVERY_RATE_2 = 173, // NYI
+ SPELL_AURA_MOD_CHARGE_RECOVERY_RATE_BY_TYPE_MASK = 173,
SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT = 174, // by defeult intelect, dependent from SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT = 175,
SPELL_AURA_SPIRIT_OF_REDEMPTION = 176,
@@ -296,7 +296,7 @@ enum AuraType : uint32
SPELL_AURA_IGNORE_COMBAT_RESULT = 202,
SPELL_AURA_PREVENT_INTERRUPT = 203,
SPELL_AURA_PREVENT_CORPSE_RELEASE = 204, // NYI
- SPELL_AURA_MOD_CHARGE_COOLDOWN = 205, // NYI
+ SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK = 205,
SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED = 206,
SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED = 207,
SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED = 208,
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 061a55c5002..7b1ef3d960a 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -217,7 +217,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleAuraModIncreaseHealthPercent, //145 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT2
&AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE
&AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
- &AuraEffect::HandleNULL, //148 SPELL_AURA_MOD_CHARGE_RECOVERY_RATE
+ &AuraEffect::HandleModChargeRecoveryRate, //148 SPELL_AURA_MOD_CHARGE_RECOVERY_RATE also implemented in SpellHistory::GetChargeRecoveryTime
&AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
&AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
&AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
@@ -242,7 +242,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleDetectAmore, //170 SPELL_AURA_DETECT_AMORE used to detect various spells that change visual of units for aura target
&AuraEffect::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
&AuraEffect::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
- &AuraEffect::HandleUnused, //173 unused (4.3.4) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
+ &AuraEffect::HandleNoImmediateEffect, //173 SPELL_AURA_MOD_CHARGE_RECOVERY_RATE_BY_TYPE_MASK implemented in SpellHistory::GetChargeRecoveryTime
&AuraEffect::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus
&AuraEffect::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus
&AuraEffect::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
@@ -274,7 +274,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
&AuraEffect::HandleNoImmediateEffect, //203 SPELL_AURA_PREVENT_INTERRUPT implemented in SpellInfo::CanBeInterrupted
&AuraEffect::HandleNULL, //204 SPELL_AURA_PREVENT_CORPSE_RELEASE
- &AuraEffect::HandleNULL, //205 SPELL_AURA_MOD_CHARGE_COOLDOWN
+ &AuraEffect::HandleNoImmediateEffect, //205 SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK implemented in SpellHistory::GetChargeRecoveryTime
&AuraEffect::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
&AuraEffect::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
&AuraEffect::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@@ -6266,6 +6266,15 @@ void AuraEffect::HandleModRecoveryRateBySpellLabel(AuraApplication const* aurApp
}, rate, apply);
}
+void AuraEffect::HandleModChargeRecoveryRate(AuraApplication const* aurApp, uint8 mode, bool apply) const
+{
+ if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK))
+ return;
+
+ float rate = 100.0f / (std::max<float>(GetAmount(), -99.0f) + 100.0f);
+ aurApp->GetTarget()->GetSpellHistory()->UpdateChargeRecoveryRate(GetMiscValue(), rate, apply);
+}
+
void AuraEffect::HandleShowConfirmationPrompt(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index c9d27770593..f141df6e1de 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -326,6 +326,7 @@ class TC_GAME_API AuraEffect
void HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModRecoveryRate(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModRecoveryRateBySpellLabel(AuraApplication const* aurApp, uint8 mode, bool apply) const;
+ void HandleModChargeRecoveryRate(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleShowConfirmationPrompt(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAllowUsingGameobjectsWhileMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const;
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index b6e7160ebaa..10df8b51c0f 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -900,6 +900,43 @@ void SpellHistory::ModifyChargeRecoveryTime(uint32 chargeCategoryId, Duration co
SendSetSpellCharges(chargeCategoryId, itr->second);
}
+void SpellHistory::UpdateChargeRecoveryRate(uint32 chargeCategoryId, float modChange, bool apply)
+{
+ auto itr = _categoryCharges.find(chargeCategoryId);
+ if (itr == _categoryCharges.end() || itr->second.empty())
+ return;
+
+ if (modChange <= 0.0f)
+ return;
+
+ if (!apply)
+ modChange = 1.0f / modChange;
+
+ TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
+
+ auto chargeItr = itr->second.begin();
+
+ chargeItr->RechargeEnd = now + duration_cast<Duration>((chargeItr->RechargeEnd - now) * modChange);
+
+ TimePoint prevEnd = chargeItr->RechargeEnd;
+
+ while (++chargeItr != itr->second.end())
+ {
+ Duration rechargeTime = duration_cast<Duration>((chargeItr->RechargeEnd - chargeItr->RechargeStart) * modChange);
+ chargeItr->RechargeStart = prevEnd;
+ chargeItr->RechargeEnd = prevEnd + rechargeTime;
+ prevEnd = chargeItr->RechargeEnd;
+ }
+
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPackets::Spells::UpdateChargeCategoryCooldown updateChargeCategoryCooldown;
+ updateChargeCategoryCooldown.Category = chargeCategoryId;
+ updateChargeCategoryCooldown.ModChange = modChange;
+ playerOwner->SendDirectMessage(updateChargeCategoryCooldown.Write());
+ }
+}
+
void SpellHistory::RestoreCharge(uint32 chargeCategoryId)
{
auto itr = _categoryCharges.find(chargeCategoryId);
@@ -974,6 +1011,10 @@ int32 SpellHistory::GetChargeRecoveryTime(uint32 chargeCategoryId) const
int32 recoveryTime = chargeCategoryEntry->ChargeRecoveryTime;
recoveryTime += _owner->GetTotalAuraModifierByMiscValue(SPELL_AURA_CHARGE_RECOVERY_MOD, chargeCategoryId);
+ for (AuraEffect const* modRecoveryRate : _owner->GetAuraEffectsByType(SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK))
+ if (modRecoveryRate->GetMiscValue() & chargeCategoryEntry->TypeMask)
+ recoveryTime += modRecoveryRate->GetAmount();
+
float recoveryTimeF = float(recoveryTime);
recoveryTimeF *= _owner->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER, chargeCategoryId);
@@ -983,6 +1024,19 @@ int32 SpellHistory::GetChargeRecoveryTime(uint32 chargeCategoryId) const
if (_owner->HasAuraTypeWithMiscvalue(SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE_REGEN, chargeCategoryId))
recoveryTimeF *= _owner->m_unitData->ModHasteRegen;
+ for (AuraEffect const* modRecoveryRate : _owner->GetAuraEffectsByType(SPELL_AURA_MOD_CHARGE_RECOVERY_RATE))
+ if (modRecoveryRate->GetMiscValue() == int32(chargeCategoryId))
+ recoveryTimeF *= 100.0f / (std::max<float>(modRecoveryRate->GetAmount(), -99.0f) + 100.0f);
+
+ for (AuraEffect const* modRecoveryRate : _owner->GetAuraEffectsByType(SPELL_AURA_MOD_CHARGE_RECOVERY_RATE_BY_TYPE_MASK))
+ if (modRecoveryRate->GetMiscValue() & chargeCategoryEntry->TypeMask)
+ recoveryTimeF *= 100.0f / (std::max<float>(modRecoveryRate->GetAmount(), -99.0f) + 100.0f);
+
+ if (Milliseconds(chargeCategoryEntry->ChargeRecoveryTime) <= 1h
+ && !(chargeCategoryEntry->Flags & SPELL_CATEGORY_FLAG_IGNORE_FOR_MOD_TIME_RATE)
+ && !(chargeCategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_DAILY_RESET))
+ recoveryTimeF *= *_owner->m_unitData->ModTimeRate;
+
return int32(std::floor(recoveryTimeF));
}
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
index b731cbfc329..5deae792ba9 100644
--- a/src/server/game/Spells/SpellHistory.h
+++ b/src/server/game/Spells/SpellHistory.h
@@ -184,6 +184,7 @@ public:
// Charges
bool ConsumeCharge(uint32 chargeCategoryId);
void ModifyChargeRecoveryTime(uint32 chargeCategoryId, Duration cooldownMod);
+ void UpdateChargeRecoveryRate(uint32 chargeCategoryId, float modChange, bool apply);
void RestoreCharge(uint32 chargeCategoryId);
void ResetCharges(uint32 chargeCategoryId);
void ResetAllCharges();
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index f6e0561dfc7..ff1c34de729 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -4831,7 +4831,7 @@ bool _isPositiveEffectImpl(SpellInfo const* spellInfo, SpellEffectInfo const& ef
case SPELL_AURA_MOD_WEAPON_CRIT_PERCENT:
case SPELL_AURA_POWER_BURN:
case SPELL_AURA_MOD_COOLDOWN:
- case SPELL_AURA_MOD_CHARGE_COOLDOWN:
+ case SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK:
case SPELL_AURA_MOD_INCREASE_SPEED:
case SPELL_AURA_MOD_PARRY_PERCENT:
case SPELL_AURA_SET_VEHICLE_ID: