diff --git a/data/sql/updates/pending_db_world/rev_1653580726731163907.sql b/data/sql/updates/pending_db_world/rev_1653580726731163907.sql
new file mode 100644
index 000000000..47eda61ab
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1653580726731163907.sql
@@ -0,0 +1,3 @@
+
+UPDATE `creature_template` SET `ScriptName`='npc_chained_spirit', `speed_run`=0.4, `unit_flags`=`unit_flags`|33554432 WHERE `entry`=15117;
+
diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp
index f2d8a9de0..9e85278f4 100644
--- a/src/server/game/Spells/SpellInfoCorrections.cpp
+++ b/src/server/game/Spells/SpellInfoCorrections.cpp
@@ -1363,6 +1363,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].Amplitude = 15000;
});
+ // Threatening Gaze
+ ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
+ });
+
// Isle of Conquest
ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
{
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
index 9e6dd8bc2..4f04748b8 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
@@ -15,19 +15,14 @@
* with this program. If not, see .
*/
-/* ScriptData
-SDName: Boss_Mandokir
-SD%Complete: 90
-SDComment: Ohgan function needs improvements.
-SDCategory: Zul'Gurub
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "zulgurub.h"
+#include "Player.h"
+#include "TaskScheduler.h"
enum Says
{
@@ -41,15 +36,19 @@ enum Says
enum Spells
{
- SPELL_CHARGE = 24408, // seen
- SPELL_OVERPOWER = 24407, // Seen
- SPELL_FEAR = 29321,
- SPELL_WHIRLWIND = 13736, // Triggers 15589
- SPELL_MORTAL_STRIKE = 16856, // Seen
- SPELL_FRENZY = 24318, // seen
- SPELL_WATCH = 24314, // seen 24315, 24316
- SPELL_WATCH_CHARGE = 24315, // Triggers 24316
- SPELL_LEVEL_UP = 24312 //
+ SPELL_CHARGE = 24408,
+ SPELL_OVERPOWER = 24407,
+ SPELL_FRIGHTENING_SHOUT = 19134,
+ SPELL_WHIRLWIND = 13736, // triggers 15589
+ SPELL_MORTAL_STRIKE = 16856,
+ SPELL_FRENZY = 24318,
+ SPELL_WATCH = 24314, // triggers 24315 and 24316
+ SPELL_WATCH_CHARGE = 24315, // triggers 24316
+ SPELL_LEVEL_UP = 24312,
+ SPELL_EXECUTE = 7160,
+ SPELL_MANDOKIR_CLEAVE = 20691,
+
+ SPELL_REVIVE = 24341 // chained spirit
};
enum Events
@@ -62,18 +61,29 @@ enum Events
EVENT_WHIRLWIND = 6,
EVENT_CHECK_OHGAN = 7,
EVENT_WATCH_PLAYER = 8,
- EVENT_CHARGE_PLAYER = 9
+ EVENT_CHARGE_PLAYER = 9,
+ EVENT_EXECUTE = 10,
+ EVENT_FRIGHTENING_SHOUT = 11,
+ EVENT_CLEAVE = 12
+};
+
+enum Action
+{
+ ACTION_START_REVIVE = 1, // broodlord mandokir
+ ACTION_REVIVE = 2 // chained spirit
};
enum Misc
{
+ POINT_START_REVIVE = 1, // chained spirit
+
MODEL_OHGAN_MOUNT = 15271,
PATH_MANDOKIR = 492861,
POINT_MANDOKIR_END = 24,
- CHAINED_SPIRT_COUNT = 20
+ CHAINED_SPIRIT_COUNT = 20
};
-Position const PosSummonChainedSpirits[CHAINED_SPIRT_COUNT] =
+Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
{
{ -12167.17f, -1979.330f, 133.0992f, 2.268928f },
{ -12262.74f, -1953.394f, 133.5496f, 0.593412f },
@@ -114,28 +124,36 @@ public:
void Reset() override
{
+ BossAI::Reset();
+ killCount = 0;
if (me->GetPositionZ() > 140.0f)
{
events.ScheduleEvent(EVENT_CHECK_START, 1000);
if (Creature* speaker = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_VILEBRANCH_SPEAKER)))
+ {
if (!speaker->IsAlive())
+ {
speaker->Respawn(true);
+ }
+ }
}
-
- killCount = 0;
me->RemoveAurasDueToSpell(SPELL_FRENZY);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
- summons.DespawnAll();
instance->SetBossState(DATA_OHGAN, NOT_STARTED);
me->Mount(MODEL_OHGAN_MOUNT);
+ reviveGUID.Clear();
}
void JustDied(Unit* /*killer*/) override
{
// Do not want to unsummon Ohgan
- for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i)
- if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpirtGUIDs[i]))
+ for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
+ {
+ if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpiritGUIDs[i]))
+ {
unsummon->DespawnOrUnsummon();
+ }
+ }
instance->SetBossState(DATA_MANDOKIR, DONE);
instance->SaveToDB();
}
@@ -143,22 +161,23 @@ public:
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- events.ScheduleEvent(EVENT_OVERPOWER, urand(7000, 9000));
- events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000));
+ events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 8000));
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(14000, 28000));
events.ScheduleEvent(EVENT_WHIRLWIND, urand(24000, 30000));
events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000);
- events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(13000, 15000));
- events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(33000, 38000));
+ events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
+ events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
+ events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
+ events.ScheduleEvent(EVENT_CLEAVE, urand(10000, 20000));
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
Talk(SAY_AGGRO);
me->Dismount();
// Summon Ohgan (Spell missing) TEMP HACK
me->SummonCreature(NPC_OHGAN, me->GetPositionX() - 3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000);
- // Summon Chained Spirits
- for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i)
+ for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
{
- Creature* chainedSpirt = me->SummonCreature(NPC_CHAINED_SPIRT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
- chainedSpirtGUIDs[i] = chainedSpirt->GetGUID();
+ Creature* chainedSpirit = me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
+ chainedSpiritGUIDs[i] = chainedSpirit->GetGUID();
}
DoZoneInCombat();
}
@@ -168,17 +187,49 @@ public:
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
+ reviveGUID = victim->GetGUID();
+ DoAction(ACTION_START_REVIVE);
if (++killCount == 3)
{
Talk(SAY_DING_KILL);
if (Creature* jindo = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_JINDO)))
+ {
if (jindo->IsAlive())
+ {
jindo->AI()->Talk(SAY_GRATS_JINDO);
+ }
+ }
DoCast(me, SPELL_LEVEL_UP, true);
killCount = 0;
}
}
+ void DoAction(int32 action) override
+ {
+ 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 = 0 */) override
+ {
+ reviveGUID = guid;
+ }
+
void MovementInform(uint32 type, uint32 id) override
{
if (type == WAYPOINT_MOTION_TYPE)
@@ -211,7 +262,9 @@ public:
events.ScheduleEvent(EVENT_STARTED, 6000);
}
else
+ {
events.ScheduleEvent(EVENT_CHECK_START, 1000);
+ }
break;
case EVENT_STARTED:
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
@@ -232,13 +285,12 @@ public:
switch (eventId)
{
case EVENT_OVERPOWER:
- DoCastVictim(SPELL_OVERPOWER, true);
- events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 12000));
+ DoCastVictim(SPELL_OVERPOWER);
+ events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 8000));
break;
case EVENT_MORTAL_STRIKE:
- if (me->GetVictim() && me->GetVictim()->HealthBelowPct(50))
- DoCastVictim(SPELL_MORTAL_STRIKE, true);
- events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000));
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(14000, 28000));
break;
case EVENT_WHIRLWIND:
DoCast(me, SPELL_WHIRLWIND);
@@ -251,7 +303,9 @@ public:
Talk(SAY_OHGAN_DEAD);
}
else
+ {
events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000);
+ }
break;
case EVENT_WATCH_PLAYER:
if (Unit* player = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
@@ -259,23 +313,57 @@ public:
DoCast(player, SPELL_WATCH);
Talk(SAY_WATCH, player);
}
- events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 15000));
+ events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
break;
case EVENT_CHARGE_PLAYER:
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_CHARGE);
- events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(22000, 30000));
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 1500);
+ if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f))
+ {
+ me->GetThreatMgr().modifyThreatPercent(mainTarget, -100);
+ }
+ events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
break;
+ case EVENT_EXECUTE:
+ if (me->GetVictim() && me->GetVictim()->HealthBelowPct(20))
+ {
+ DoCastVictim(SPELL_EXECUTE, true);
+ }
+ events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
+ break;
+ case EVENT_FRIGHTENING_SHOUT:
+ DoCastAOE(SPELL_FRIGHTENING_SHOUT);
+ break;
+ case EVENT_CLEAVE:
+ {
+ std::list meleeRangeTargets;
+ auto i = me->GetThreatMgr().getThreatList().begin();
+ for (; i != me->GetThreatMgr().getThreatList().end(); ++i)
+ {
+ Unit* target = (*i)->getTarget();
+ if (me->IsWithinMeleeRange(target))
+ {
+ meleeRangeTargets.push_back(target);
+ }
+ }
+ if (meleeRangeTargets.size() >= 5)
+ {
+ DoCastVictim(SPELL_MANDOKIR_CLEAVE);
+ }
+ events.ScheduleEvent(EVENT_CLEAVE, urand(10000, 20000));
+ break;
+ }
default:
break;
}
}
-
DoMeleeAttackIfReady();
}
private:
uint8 killCount;
- ObjectGuid chainedSpirtGUIDs[CHAINED_SPIRT_COUNT];
+ ObjectGuid chainedSpiritGUIDs[CHAINED_SPIRIT_COUNT];
+ ObjectGuid reviveGUID;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -288,7 +376,8 @@ public:
enum OhganSpells
{
- SPELL_SUNDERARMOR = 24317
+ SPELL_SUNDERARMOR = 24317,
+ SPELL_THRASH = 3417 // Triggers 3391
};
class npc_ohgan : public CreatureScript
@@ -302,10 +391,61 @@ public:
void Reset() override
{
- SunderArmor_Timer = 5000;
+ me->AddAura(SPELL_THRASH, me);
+ _scheduler.CancelAll();
+ _scheduler.SetValidator([this]
+ {
+ return !me->HasUnitState(UNIT_STATE_CASTING);
+ });
+
+ reviveGUID.Clear();
}
- void EnterCombat(Unit* /*who*/) override { }
+ void EnterCombat(Unit* victim) override
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ reviveGUID = victim->GetGUID();
+ DoAction(ACTION_START_REVIVE);
+ _scheduler.Schedule(6s, 12s, [this](TaskContext context)
+ {
+ DoCastVictim(SPELL_SUNDERARMOR);
+ context.Repeat(6s, 12s);
+ });
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ reviveGUID = victim->GetGUID();
+ DoAction(ACTION_START_REVIVE);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_START_REVIVE)
+ {
+ std::list creatures;
+ GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
+ if (creatures.empty())
+ return;
+
+ for (Creature* chainedSpirit : creatures)
+ {
+ chainedSpirit->AI()->SetGUID(reviveGUID);
+ chainedSpirit->AI()->DoAction(ACTION_REVIVE);
+ reviveGUID.Clear();
+ }
+ }
+ }
+
+ void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
+ {
+ reviveGUID = guid;
+ }
void JustDied(Unit* /*killer*/) override
{
@@ -314,23 +454,20 @@ public:
void UpdateAI(uint32 diff) override
{
- // Return since we have no target
- if (!UpdateVictim())
- return;
+ _scheduler.Update(diff);
- if (SunderArmor_Timer <= diff)
+ if (!UpdateVictim())
{
- DoCastVictim(SPELL_SUNDERARMOR, true);
- SunderArmor_Timer = urand(10000, 15000);
+ return;
}
- else SunderArmor_Timer -= diff;
DoMeleeAttackIfReady();
}
private:
- uint32 SunderArmor_Timer;
InstanceScript* instance;
+ ObjectGuid reviveGUID;
+ TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -339,6 +476,75 @@ public:
}
};
+struct npc_chained_spirit : public ScriptedAI
+{
+public:
+ npc_chained_spirit(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ me->AddUnitMovementFlag(MOVEMENTFLAG_HOVER);
+ }
+
+ void Reset() override
+ {
+ revivePlayerGUID.Clear();
+ }
+
+ void SetGUID(ObjectGuid const guid, int32 /*id*/) override
+ {
+ revivePlayerGUID = guid;
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_REVIVE)
+ {
+ if (Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID))
+ {
+ Position pos;
+ target->GetNearPoint(me, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 0.0f, target->GetAbsoluteAngle(me));
+ me->GetMotionMaster()->MovePoint(POINT_START_REVIVE, pos);
+ }
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != POINT_MOTION_TYPE || !revivePlayerGUID)
+ return;
+
+ if (pointId == POINT_START_REVIVE)
+ {
+ if (Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID))
+ {
+ DoCast(target, SPELL_REVIVE);
+ }
+ me->DespawnOrUnsummon(1000);
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID);
+ if (!target || target->IsAlive())
+ return;
+
+ if (Creature* mandokir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MANDOKIR)))
+ {
+ mandokir->GetAI()->SetGUID(target->GetGUID());
+ mandokir->GetAI()->DoAction(ACTION_START_REVIVE);
+ }
+ me->DespawnOrUnsummon();
+ }
+
+ void UpdateAI(uint32 /*diff*/) override { }
+
+private:
+ InstanceScript* instance;
+ ObjectGuid revivePlayerGUID;
+
+};
+
enum VilebranchSpells
{
SPELL_DEMORALIZING_SHOUT = 13730,
@@ -414,9 +620,15 @@ public:
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
+ {
if (Unit* target = GetTarget())
+ {
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
- caster->CastSpell(target, SPELL_WATCH_CHARGE);
+ {
+ caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
+ }
+ }
+ }
}
void Register() override
@@ -435,6 +647,7 @@ void AddSC_boss_mandokir()
{
new boss_mandokir();
new npc_ohgan();
+ RegisterZulGurubCreatureAI(npc_chained_spirit);
new npc_vilebranch_speaker();
new spell_threatening_gaze();
}
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h
index 8c44120d1..79e40b4c4 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h
@@ -57,7 +57,7 @@ enum CreatureIds
NPC_MANDOKIR = 11382, // Mandokir Event
NPC_OHGAN = 14988, // Mandokir Event
NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event
- NPC_CHAINED_SPIRT = 15117, // Mandokir Event
+ NPC_CHAINED_SPIRIT = 15117, // Mandokir Event
NPC_HAKKAR = 14834,
NPC_ZULGURUB_TIGER = 11361
};
@@ -74,4 +74,6 @@ inline AI* GetZulGurubAI(T* obj)
return GetInstanceAI(obj, ZGScriptName);
}
+#define RegisterZulGurubCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetZulGurubAI)
+
#endif