fix(Core/Spells): Fix Rapid Recuperation, Rapid Killing, and auto-generate PROC_ATTR_REQ_SPELLMOD (#24830)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "ProcChanceTestHelper.h"
|
||||
#include "ProcEventInfoHelper.h"
|
||||
#include "SpellInfoTestHelper.h"
|
||||
#include "AuraStub.h"
|
||||
#include "UnitStub.h"
|
||||
#include "gtest/gtest.h"
|
||||
@@ -135,6 +136,151 @@ TEST_F(SpellProcAttributeTest, ReqSpellmod_AttributeNotSet)
|
||||
EXPECT_FALSE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// PROC_ATTR_REQ_SPELLMOD Auto-Generation Tests
|
||||
// Validates that LoadSpellProcs auto-generates REQ_SPELLMOD for modifier
|
||||
// auras with charges, preventing charge consumption by unrelated spells.
|
||||
// =============================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
// Replicates the auto-generation logic from SpellMgr::LoadSpellProcs
|
||||
void ApplyAutoGeneratedSpellmodFlag(SpellInfo const* spellInfo, SpellProcEntry& procEntry)
|
||||
{
|
||||
if (spellInfo->ProcCharges)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (spellInfo->Effects[i].IsAura(SPELL_AURA_ADD_FLAT_MODIFIER) ||
|
||||
spellInfo->Effects[i].IsAura(SPELL_AURA_ADD_PCT_MODIFIER))
|
||||
{
|
||||
procEntry.AttributesMask |= PROC_ATTR_REQ_SPELLMOD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_PctModifierWithCharges)
|
||||
{
|
||||
// Rapid Killing (35099): ADD_PCT_MODIFIER + 1 charge
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(35099)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_ADD_PCT_MODIFIER)
|
||||
.WithProcFlags(PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)
|
||||
.WithProcCharges(1)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithProcFlags(PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)
|
||||
.WithCharges(1)
|
||||
.WithChance(100.0f)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_TRUE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_FlatModifierWithCharges)
|
||||
{
|
||||
// Clearcasting-like: ADD_FLAT_MODIFIER + charges
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(12345)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_ADD_FLAT_MODIFIER)
|
||||
.WithProcCharges(2)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithCharges(2)
|
||||
.WithChance(100.0f)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_TRUE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_NoCharges_NotSet)
|
||||
{
|
||||
// Modifier aura without charges should NOT get the flag
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(12345)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_ADD_PCT_MODIFIER)
|
||||
.WithProcCharges(0)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithCharges(0)
|
||||
.WithChance(100.0f)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_FALSE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_NonModifierWithCharges_NotSet)
|
||||
{
|
||||
// Non-modifier aura with charges should NOT get the flag
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(12345)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_PROC_TRIGGER_SPELL)
|
||||
.WithProcCharges(1)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithCharges(1)
|
||||
.WithChance(100.0f)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_FALSE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_ModifierOnSecondEffect)
|
||||
{
|
||||
// Modifier on effect index 1, not 0
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(12345)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_PROC_TRIGGER_SPELL)
|
||||
.WithEffect(1, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_ADD_FLAT_MODIFIER)
|
||||
.WithProcCharges(1)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithCharges(1)
|
||||
.WithChance(100.0f)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_TRUE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
}
|
||||
|
||||
TEST_F(SpellProcAttributeTest, ReqSpellmod_AutoGen_PreservesExistingAttributes)
|
||||
{
|
||||
// Should OR with existing attributes, not replace
|
||||
auto spellInfo = SpellInfoBuilder()
|
||||
.WithId(12345)
|
||||
.WithEffect(0, SPELL_EFFECT_APPLY_AURA, SPELL_AURA_ADD_PCT_MODIFIER)
|
||||
.WithProcCharges(1)
|
||||
.BuildUnique();
|
||||
|
||||
SpellProcEntry procEntry = SpellProcEntryBuilder()
|
||||
.WithCharges(1)
|
||||
.WithChance(100.0f)
|
||||
.WithAttributesMask(PROC_ATTR_TRIGGERED_CAN_PROC)
|
||||
.Build();
|
||||
|
||||
ApplyAutoGeneratedSpellmodFlag(spellInfo.get(), procEntry);
|
||||
|
||||
EXPECT_TRUE(procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD);
|
||||
EXPECT_TRUE(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// PROC_ATTR_USE_STACKS_FOR_CHARGES (0x10) Tests
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user