diff --git a/data/sql/updates/pending_db_world/rev_1655562192338775600.sql b/data/sql/updates/pending_db_world/rev_1655562192338775600.sql new file mode 100644 index 000000000..6711c69c4 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1655562192338775600.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id`=24315; +INSERT INTO `spell_script_names` VALUES +(24315,'spell_threatening_gaze_charge'); diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f08e5eaf8..b03e25578 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -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*/); diff --git a/src/server/game/Combat/HostileRefMgr.cpp b/src/server/game/Combat/HostileRefMgr.cpp index 20b30a27a..f44638080 100644 --- a/src/server/game/Combat/HostileRefMgr.cpp +++ b/src/server/game/Combat/HostileRefMgr.cpp @@ -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(); } diff --git a/src/server/game/Combat/ThreatMgr.cpp b/src/server/game/Combat/ThreatMgr.cpp index 5a9bfcde5..87af1c4d4 100644 --- a/src/server/game/Combat/ThreatMgr.cpp +++ b/src/server/game/Combat/ThreatMgr.cpp @@ -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) diff --git a/src/server/game/Combat/ThreatMgr.h b/src/server/game/Combat/ThreatMgr.h index b6622d8e1..5f87b094c 100644 --- a/src/server/game/Combat/ThreatMgr.h +++ b/src/server/game/Combat/ThreatMgr.h @@ -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); }; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 045ee219f..317f747db 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8bb7eeea4..f40b8e533 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1533,7 +1533,7 @@ public: void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& 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); diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 736d9d950..985ead07c 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -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) { diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 6959632e2..018b64b64 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -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 creatures; + GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f); + if (creatures.empty()) + return; + + for (std::list::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 _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); }