Fix tentacle slam

This commit is contained in:
luis
2026-09-27 13:20:50 -03:00
parent 615805a2a2
commit 0cf63552e0
+84 -48
View File
@@ -5232,76 +5232,112 @@ class spell_pri_void_volley : public SpellScript
};
// 1227280 - Tentacle Slam
// Effect 0 carries the radius the slam damages around the target, effect 2 carries how many enemies
// it applies Vampiric Touch to. The two are handled separately, otherwise the shared handler both
// deals its damage twice and reads the wrong effect value as the Vampiric Touch target count.
class spell_pri_tentacle_slam : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_VAMPIRIC_TOUCH, SPELL_PRIEST_TENTACLE_SLAM_DAMAGE });
return ValidateSpellInfo({ SPELL_PRIEST_VAMPIRIC_TOUCH });
}
void HandleDummy(SpellEffIndex /*effIndex*/)
// Every enemy the slam reaches around the target, split so targets without Vampiric Touch can
// be prioritised as the talent requires
void CollectSlamTargets(Unit* caster, Unit* target, std::vector<Unit*>& withoutVampiricTouch, std::vector<Unit*>& withVampiricTouch) const
{
float const radius = float(GetSpell()->GetSpellInfo()->GetEffect(EFFECT_0).CalcBaseValue(caster, target, 0, 0));
if (radius <= 0.0f)
return;
std::list<Unit*> enemyList;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck check(target, caster, radius);
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, enemyList, check);
Cell::VisitAllObjects(target, searcher, radius);
for (Unit* unit : enemyList)
{
if (unit->HasAura(SPELL_PRIEST_VAMPIRIC_TOUCH, caster->GetGUID()))
withVampiricTouch.push_back(unit);
else
withoutVampiricTouch.push_back(unit);
}
}
void ApplyVampiricTouch(Unit* caster, Unit* target) const
{
caster->CastSpell(target, SPELL_PRIEST_VAMPIRIC_TOUCH, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void HandleDamage(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
return;
// Cast damage spell on the target
caster->CastSpell(target, SPELL_PRIEST_TENTACLE_SLAM_DAMAGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
// The slam damage lives in a separate spell that the client only references, so it is
// skipped when the server data does not carry it. Vampiric Touch still has to be applied.
if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_TENTACLE_SLAM_DAMAGE, DIFFICULTY_NONE))
return;
// Apply Vampiric Touch to enemies without it, up to the spell's effect value
int32 maxTargets = GetEffectValueAsInt();
std::vector<Unit*> targets;
std::vector<Unit*> withoutVampiricTouch, withVampiricTouch;
CollectSlamTargets(caster, target, withoutVampiricTouch, withVampiricTouch);
// Find enemies in range around the target
std::list<Unit*> enemyList;
float radius = 10.0f; // Base radius for AoE
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, caster, radius);
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, enemyList, u_check);
Cell::VisitAllObjects(target, searcher, radius);
// Prioritize enemies without Vampiric Touch
std::vector<Unit*> withoutVT;
std::vector<Unit*> withVT;
for (Unit* unit : enemyList)
{
if (unit->HasAura(SPELL_PRIEST_VAMPIRIC_TOUCH))
withVT.push_back(unit);
else
withoutVT.push_back(unit);
}
// Add targets without VT first, then with VT
for (Unit* unit : withoutVT)
{
if (static_cast<int32>(targets.size()) < maxTargets)
targets.push_back(unit);
}
for (Unit* unit : withVT)
{
if (static_cast<int32>(targets.size()) < maxTargets)
targets.push_back(unit);
}
// Apply Vampiric Touch to selected targets
for (Unit* unit : targets)
{
caster->CastSpell(unit, SPELL_PRIEST_VAMPIRIC_TOUCH, CastSpellExtraArgsInit{
for (Unit* unit : withoutVampiricTouch)
caster->CastSpell(unit, SPELL_PRIEST_TENTACLE_SLAM_DAMAGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
for (Unit* unit : withVampiricTouch)
caster->CastSpell(unit, SPELL_PRIEST_TENTACLE_SLAM_DAMAGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void HandleApplyVampiricTouch(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
return;
int32 const maxTargets = GetEffectValueAsInt();
if (maxTargets <= 0)
return;
std::vector<Unit*> withoutVampiricTouch, withVampiricTouch;
CollectSlamTargets(caster, target, withoutVampiricTouch, withVampiricTouch);
int32 applied = 0;
for (Unit* unit : withoutVampiricTouch)
{
if (applied >= maxTargets)
break;
ApplyVampiricTouch(caster, unit);
++applied;
}
for (Unit* unit : withVampiricTouch)
{
if (applied >= maxTargets)
break;
ApplyVampiricTouch(caster, unit);
++applied;
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_pri_tentacle_slam::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_pri_tentacle_slam::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_pri_tentacle_slam::HandleDamage, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_pri_tentacle_slam::HandleApplyVampiricTouch, EFFECT_2, SPELL_EFFECT_DUMMY);
}
};