fix(Scripts/ZulGurub): Hakkar's Blood Siphon (#12196)

This commit is contained in:
UltraNix
2022-07-09 16:05:09 +02:00
committed by GitHub
parent 32ba21d029
commit 346150c92a
12 changed files with 90 additions and 44 deletions

View File

@@ -3439,7 +3439,7 @@ bool Creature::IsMovementPreventedByCasting() const
{
Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL];
// first check if currently a movement allowed channel is active and we're not casting
if (spell && spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive() && spell->GetSpellInfo()->IsMoveAllowedChannel())
if (spell && spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive() && spell->GetSpellInfo()->IsActionAllowedChannel())
{
return false;
}

View File

@@ -3622,8 +3622,12 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell)
{
// generic spells always break channeled not delayed spells
if (Spell* s = GetCurrentSpell(CURRENT_CHANNELED_SPELL))
if (s->GetSpellInfo()->Id != 69051) // pussywizard: FoS, boss Devourer of Souls, Mirrored Soul, does not have any special attribute
{
if (!s->GetSpellInfo()->IsActionAllowedChannel())
{
InterruptSpell(CURRENT_CHANNELED_SPELL, false);
}
}
// autorepeat breaking
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
@@ -3658,7 +3662,14 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell)
if (pSpell->m_spellInfo->Id != 75)
{
// generic autorepeats break generic non-delayed and channeled non-delayed spells
InterruptSpell(CURRENT_GENERIC_SPELL, false);
if (Spell* s = GetCurrentSpell(CURRENT_CHANNELED_SPELL))
{
if (!s->GetSpellInfo()->IsActionAllowedChannel())
{
InterruptSpell(CURRENT_CHANNELED_SPELL, false);
}
}
InterruptSpell(CURRENT_CHANNELED_SPELL, false);
}
// special action: set first cast flag
@@ -3793,7 +3804,7 @@ bool Unit::IsMovementPreventedByCasting() const
{
if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
{
if (spell->GetSpellInfo()->IsMoveAllowedChannel())
if (spell->GetSpellInfo()->IsActionAllowedChannel())
{
return false;
}
@@ -3804,15 +3815,6 @@ bool Unit::IsMovementPreventedByCasting() const
return true;
}
bool Unit::CanMoveDuringChannel() const
{
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
if (spell->getState() != SPELL_STATE_FINISHED)
return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL) && spell->IsChannelActive();
return false;
}
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && HasInArc(arc, target);

View File

@@ -2029,9 +2029,6 @@ public:
// delayed+channeled spells are always interrupted
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, bool bySelf = false);
// Check if our current channel spell has attribute SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL
[[nodiscard]] bool CanMoveDuringChannel() const;
[[nodiscard]] Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
[[nodiscard]] Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
[[nodiscard]] Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;

View File

@@ -491,7 +491,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket)
if (!spellInfo)
return;
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
// not allow remove spells with attr SPELL_ATTR0_NO_AURA_CANCEL
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL))
{
return;
@@ -569,12 +569,33 @@ void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& /*recvPacket*/
void WorldSession::HandleCancelChanneling(WorldPacket& recvData)
{
recvData.read_skip<uint32>(); // spellid, not used
uint32 spellID = 0;
recvData >> spellID;
// ignore for remote control state (for player case)
Unit* mover = _player->m_mover;
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
if (!mover)
{
return;
}
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
if (!spellInfo)
{
return;
}
// not allow remove spells with attr SPELL_ATTR0_NO_AURA_CANCEL
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL))
{
return;
}
Spell* spell = mover->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
if (!spell || spell->GetSpellInfo()->Id != spellInfo->Id)
{
return;
}
mover->InterruptSpell(CURRENT_CHANNELED_SPELL);
}

View File

@@ -3555,9 +3555,13 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->isMoving() && m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT && !IsTriggered())
{
SendCastResult(SPELL_FAILED_MOVING);
finish(false);
return SPELL_FAILED_MOVING;
// 1. Has casttime, 2. Or doesn't have flag to allow action during channel
if (m_casttime || !m_spellInfo->IsActionAllowedChannel())
{
SendCastResult(SPELL_FAILED_MOVING);
finish(false);
return SPELL_FAILED_MOVING;
}
}
// xinef: if spell have nearby target entry only, do not allow to cast if no targets are found

View File

@@ -1241,7 +1241,7 @@ bool SpellInfo::IsChanneled() const
return (AttributesEx & (SPELL_ATTR1_IS_CHANNELED | SPELL_ATTR1_IS_SELF_CHANNELED));
}
bool SpellInfo::IsMoveAllowedChannel() const
bool SpellInfo::IsActionAllowedChannel() const
{
return IsChanneled() && HasAttribute(SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL);
}

View File

@@ -457,7 +457,7 @@ public:
bool IsPositive() const;
bool IsPositiveEffect(uint8 effIndex) const;
bool IsChanneled() const;
[[nodiscard]] bool IsMoveAllowedChannel() const;
[[nodiscard]] bool IsActionAllowedChannel() const;
bool NeedsComboPoints() const;
bool IsBreakingStealth() const;
bool IsRangedWeaponSpell() const;

View File

@@ -4301,6 +4301,16 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].MiscValueB = 64;
});
// Blood Siphon
ApplySpellFix({ 24322, 24323 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_MOD_STUN;
spellInfo->Effects[EFFECT_2].Effect = 0;
spellInfo->Attributes |= SPELL_ATTR0_NO_AURA_CANCEL;
spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL;
spellInfo->ChannelInterruptFlags &= ~AURA_INTERRUPT_FLAG_MOVE;
});
// Place Fake Fur
ApplySpellFix({ 46085 }, [](SpellInfo* spellInfo)
{

View File

@@ -39,10 +39,9 @@ enum Says
enum Spells
{
SPELL_POISONOUS_BLOOD = 24321,
SPELL_BLOOD_SIPHON_HEAL = 24322,
SPELL_BLOOD_SIPHON_DMG = 24323,
SPELL_BLOOD_SIPHON = 24324,
SPELL_BLOOD_SIPHON_HEAL = 24322,
SPELL_BLOOD_SIPHON_DAMAGE = 24323,
SPELL_CORRUPTED_BLOOD = 24328,
SPELL_CAUSE_INSANITY = 24327,
SPELL_ENRAGE = 24318,
@@ -51,7 +50,8 @@ enum Spells
SPELL_ASPECT_OF_VENOXIS = 24688,
SPELL_ASPECT_OF_MARLI = 24686,
SPELL_ASPECT_OF_THEKAL = 24689,
SPELL_ASPECT_OF_ARLOKK = 24690
SPELL_ASPECT_OF_ARLOKK = 24690,
SPELL_POISONOUS_BLOOD = 24321
};
enum Events
@@ -265,31 +265,39 @@ public:
}
};
class spell_hakkar_blood_siphon : public SpellScript
class spell_blood_siphon : public SpellScript
{
PrepareSpellScript(spell_hakkar_blood_siphon);
PrepareSpellScript(spell_blood_siphon);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_HEAL, SPELL_BLOOD_SIPHON_DMG });
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_DAMAGE, SPELL_BLOOD_SIPHON_HEAL });
}
void OnSpellHit()
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
return;
// Max. 20 targets
if (!targets.empty())
{
Acore::Containers::RandomResize(targets, 20);
}
}
if (target->HasAura(SPELL_POISONOUS_BLOOD))
target->CastSpell(caster, SPELL_BLOOD_SIPHON_DMG, true);
else
target->CastSpell(caster, SPELL_BLOOD_SIPHON_HEAL, true);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (Player* player = GetHitPlayer())
{
player->CastSpell(caster, player->HasAura(SPELL_POISONOUS_BLOOD) ? SPELL_BLOOD_SIPHON_DAMAGE : SPELL_BLOOD_SIPHON_HEAL, true);
}
}
}
void Register() override
{
OnHit += SpellHitFn(spell_hakkar_blood_siphon::OnSpellHit);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blood_siphon::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_blood_siphon::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
@@ -299,5 +307,5 @@ void AddSC_boss_hakkar()
new at_zulgurub_entrance_speech();
new at_zulgurub_bridge_speech();
new at_zulgurub_temple_speech();
RegisterSpellScript(spell_hakkar_blood_siphon);
RegisterSpellScript(spell_blood_siphon);
}

View File

@@ -536,7 +536,7 @@ enum SpellAttr4 : uint32
// EnumUtils: DESCRIBE THIS
enum SpellAttr5 : uint32
{
SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL = 0x00000001, // TITLE Can be channeled while moving
SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL = 0x00000001, // TITLE Can be channeled while moving/casting
SPELL_ATTR5_NO_REAGENT_COST_WITH_AURA = 0x00000002, // TITLE No reagents during arena preparation
SPELL_ATTR5_REMOVE_ENTERING_ARENA = 0x00000004, // TITLE Remove when entering arena DESCRIPTION Force this aura to be removed on entering arena, regardless of other properties
SPELL_ATTR5_ALLOW_WHILE_STUNNED = 0x00000008, // TITLE Usable while stunned

View File

@@ -802,7 +802,7 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr5>::ToString(SpellAttr5 value)
{
switch (value)
{
case SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL: return { "SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL", "Can be channeled while moving", "" };
case SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL: return { "SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL", "Can be channeled while moving/casting", "" };
case SPELL_ATTR5_NO_REAGENT_COST_WITH_AURA: return { "SPELL_ATTR5_NO_REAGENT_COST_WITH_AURA", "No reagents during arena preparation", "" };
case SPELL_ATTR5_REMOVE_ENTERING_ARENA: return { "SPELL_ATTR5_REMOVE_ENTERING_ARENA", "Remove when entering arena", "Force this aura to be removed on entering arena, regardless of other properties" };
case SPELL_ATTR5_ALLOW_WHILE_STUNNED: return { "SPELL_ATTR5_ALLOW_WHILE_STUNNED", "Usable while stunned", "" };