mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 05:06:24 +00:00
fix(Scripts/ZulGurub): Mandokir's Threatening Gaze. (#12095)
* fix(Scripts/ZulGurub: Mandokir's Threatening Gaze. Boss can melee attack while casting. Boss charges after the debuff run out. Guillotine is casted on hit rather than on launch. Properly coded Threatening Gaze Charge (with dot/hot exceptions) Whirlwind is removed during charge. Fixes #11748 * Update * missing * Update * Update. * Update. * Update. * Update. * Update.
This commit is contained in:
@@ -207,6 +207,9 @@ public:
|
||||
|
||||
static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
|
||||
bool IsInBoundary(Position const* who = nullptr) const;
|
||||
|
||||
virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { }
|
||||
|
||||
protected:
|
||||
virtual void MoveInLineOfSight(Unit* /*who*/);
|
||||
|
||||
|
||||
@@ -38,12 +38,23 @@ void HostileRefMgr::threatAssist(Unit* victim, float baseThreat, SpellInfo const
|
||||
return;
|
||||
|
||||
HostileReference* ref = getFirst();
|
||||
float threat = ThreatCalcHelper::calcThreat(victim, iOwner, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell);
|
||||
float threat = ThreatCalcHelper::calcThreat(victim, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell);
|
||||
threat /= getSize();
|
||||
while (ref)
|
||||
{
|
||||
if (ThreatCalcHelper::isValidProcess(victim, ref->GetSource()->GetOwner(), threatSpell))
|
||||
Unit* refOwner = ref->GetSource()->GetOwner();
|
||||
if (ThreatCalcHelper::isValidProcess(victim, refOwner, threatSpell))
|
||||
{
|
||||
if (Creature* hatingCreature = refOwner->ToCreature())
|
||||
{
|
||||
if (hatingCreature->IsAIEnabled)
|
||||
{
|
||||
hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell);
|
||||
}
|
||||
}
|
||||
|
||||
ref->GetSource()->doAddThreat(victim, threat);
|
||||
}
|
||||
|
||||
ref = ref->next();
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
//==============================================================
|
||||
|
||||
// The hatingUnit is not used yet
|
||||
float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
{
|
||||
if (threatSpell)
|
||||
{
|
||||
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id))
|
||||
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id))
|
||||
if (threatEntry->pctMod != 1.0f)
|
||||
threat *= threatEntry->pctMod;
|
||||
|
||||
@@ -427,10 +427,19 @@ void ThreatMgr::clearReferences()
|
||||
|
||||
void ThreatMgr::addThreat(Unit* victim, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
{
|
||||
if (!ThreatCalcHelper::isValidProcess(victim, GetOwner(), threatSpell))
|
||||
if (!ThreatCalcHelper::isValidProcess(victim, iOwner, threatSpell))
|
||||
return;
|
||||
|
||||
doAddThreat(victim, ThreatCalcHelper::calcThreat(victim, iOwner, threat, schoolMask, threatSpell));
|
||||
threat = ThreatCalcHelper::calcThreat(victim, threat, schoolMask, threatSpell);
|
||||
if (Creature* hatingCreature = iOwner->ToCreature())
|
||||
{
|
||||
if (hatingCreature->IsAIEnabled)
|
||||
{
|
||||
hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell);
|
||||
}
|
||||
}
|
||||
|
||||
doAddThreat(victim, threat);
|
||||
}
|
||||
|
||||
void ThreatMgr::doAddThreat(Unit* victim, float threat)
|
||||
|
||||
@@ -39,7 +39,7 @@ class SpellInfo;
|
||||
|
||||
struct ThreatCalcHelper
|
||||
{
|
||||
static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
|
||||
static float calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
|
||||
static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = nullptr);
|
||||
};
|
||||
|
||||
|
||||
@@ -2329,14 +2329,14 @@ void Unit::CalcHealAbsorb(HealInfo& healInfo)
|
||||
healInfo.AbsorbHeal(absorbAmount);
|
||||
}
|
||||
|
||||
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
|
||||
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_ATTACK*/, bool extra /*= false*/, bool ignoreCasting /*= false*/)
|
||||
{
|
||||
if (HasUnitFlag(UNIT_FLAG_PACIFIED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra)
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra && !ignoreCasting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1533,7 +1533,7 @@ public:
|
||||
void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& procAuras);
|
||||
|
||||
void HandleEmoteCommand(uint32 emoteId);
|
||||
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
|
||||
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false);
|
||||
|
||||
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
|
||||
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
|
||||
|
||||
@@ -1363,12 +1363,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].Amplitude = 15000;
|
||||
});
|
||||
|
||||
// Threatening Gaze
|
||||
ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
|
||||
});
|
||||
|
||||
// Frightening Shout
|
||||
ApplySpellFix({ 19134 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@@ -80,7 +80,8 @@ enum Misc
|
||||
MODEL_OHGAN_MOUNT = 15271,
|
||||
PATH_MANDOKIR = 492861,
|
||||
POINT_MANDOKIR_END = 24,
|
||||
CHAINED_SPIRIT_COUNT = 20
|
||||
CHAINED_SPIRIT_COUNT = 20,
|
||||
ACTION_CHARGE = 1
|
||||
};
|
||||
|
||||
Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
|
||||
@@ -169,6 +170,7 @@ public:
|
||||
me->Mount(MODEL_OHGAN_MOUNT);
|
||||
reviveGUID.Clear();
|
||||
_useExecute = false;
|
||||
_chargeTarget.first.Clear();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -226,9 +228,44 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
reviveGUID = guid;
|
||||
if (action == ACTION_START_REVIVE)
|
||||
{
|
||||
std::list<Creature*> creatures;
|
||||
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
|
||||
if (creatures.empty())
|
||||
return;
|
||||
|
||||
for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
|
||||
{
|
||||
if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID()))
|
||||
{
|
||||
chainedSpirit->AI()->SetGUID(reviveGUID);
|
||||
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 type) override
|
||||
{
|
||||
if (type == ACTION_CHARGE)
|
||||
{
|
||||
if (_chargeTarget.first == guid && _chargeTarget.second > 0.f)
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, _chargeTarget.first))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_WHIRLWIND);
|
||||
DoCast(target, SPELL_WATCH_CHARGE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reviveGUID = guid;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
@@ -244,6 +281,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateThreat(Unit* hatedUnit, float& threat, SpellInfo const* threatSpell) override
|
||||
{
|
||||
if (_chargeTarget.first == hatedUnit->GetGUID())
|
||||
{
|
||||
// Do not count DOTs/HOTs
|
||||
if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))
|
||||
{
|
||||
_chargeTarget.second += threat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) override
|
||||
{
|
||||
if (doneTo && doneTo == me->GetVictim())
|
||||
@@ -264,6 +313,43 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DoMeleeAttackIfReady(bool ignoreCasting)
|
||||
{
|
||||
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* victim = me->GetVictim();
|
||||
if (!victim || !victim->IsInWorld())
|
||||
return;
|
||||
|
||||
if (!me->IsWithinMeleeRange(victim))
|
||||
return;
|
||||
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me->isAttackReady())
|
||||
{
|
||||
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
|
||||
if (me->haveOffhandWeapon())
|
||||
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim, BASE_ATTACK, false, ignoreCasting);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
// xinef: delay main hand attack if both will hit at the same time (players code)
|
||||
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim, OFF_ATTACK, false, ignoreCasting);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
@@ -299,7 +385,14 @@ public:
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
|
||||
{
|
||||
if (me->GetCurrentSpellCastTime(SPELL_WATCH) >= 0)
|
||||
{
|
||||
DoMeleeAttackIfReady(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
@@ -339,6 +432,7 @@ public:
|
||||
{
|
||||
DoCast(player, SPELL_WATCH);
|
||||
Talk(SAY_WATCH, player);
|
||||
_chargeTarget = std::make_pair(player->GetGUID(), 0.f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
|
||||
break;
|
||||
@@ -393,13 +487,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
DoMeleeAttackIfReady(false);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 killCount;
|
||||
ObjectGuid reviveGUID;
|
||||
bool _useExecute;
|
||||
std::pair<ObjectGuid, float> _chargeTarget;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -614,13 +709,16 @@ public:
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
|
||||
if (Creature* caster = GetCaster()->ToCreature())
|
||||
{
|
||||
caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
|
||||
if (caster->IsAIEnabled)
|
||||
{
|
||||
caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,6 +754,29 @@ class spell_mandokir_charge : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_threatening_gaze_charge : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_threatening_gaze_charge)
|
||||
|
||||
void PreventLaunchHit(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
}
|
||||
|
||||
void LaunchHit(SpellEffIndex effIndex)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Unit* target = GetHitUnit())
|
||||
caster->CastSpell(target, GetSpellInfo()->Effects[effIndex].TriggerSpell, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunchTarget += SpellEffectFn(spell_threatening_gaze_charge::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_threatening_gaze_charge::LaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_mandokir()
|
||||
{
|
||||
new boss_mandokir();
|
||||
@@ -664,4 +785,5 @@ void AddSC_boss_mandokir()
|
||||
RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
|
||||
new spell_threatening_gaze();
|
||||
RegisterSpellScript(spell_mandokir_charge);
|
||||
RegisterSpellScript(spell_threatening_gaze_charge);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user