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

This commit is contained in:
Shauren
2025-03-19 00:03:38 +01:00
parent e0d3781989
commit fa75f63566
10 changed files with 99 additions and 9 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,

View File

@@ -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))

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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();

View File

@@ -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: