mirror of
https://github.com/liyunfan1223/azerothcore-wotlk.git
synced 2026-08-05 06:17:56 +00:00
Boss will no longer despawn after he has done his lap and should return to the correct position when Speaker is dead (at the bottom of the stairs)
423 lines
15 KiB
C++
423 lines
15 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*/
|
|
|
|
/* 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"
|
|
|
|
enum Says
|
|
{
|
|
SAY_AGGRO = 0,
|
|
SAY_DING_KILL = 1,
|
|
SAY_WATCH = 2,
|
|
SAY_WATCH_WHISPER = 3,
|
|
SAY_OHGAN_DEAD = 4,
|
|
SAY_GRATS_JINDO = 0,
|
|
};
|
|
|
|
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 //
|
|
};
|
|
|
|
enum Events
|
|
{
|
|
EVENT_CHECK_SPEAKER = 1,
|
|
EVENT_CHECK_START = 2,
|
|
EVENT_STARTED = 3,
|
|
EVENT_OVERPOWER = 4,
|
|
EVENT_MORTAL_STRIKE = 5,
|
|
EVENT_WHIRLWIND = 6,
|
|
EVENT_CHECK_OHGAN = 7,
|
|
EVENT_WATCH_PLAYER = 8,
|
|
EVENT_CHARGE_PLAYER = 9
|
|
};
|
|
|
|
enum Misc
|
|
{
|
|
MODEL_OHGAN_MOUNT = 15271,
|
|
PATH_MANDOKIR = 492861,
|
|
POINT_MANDOKIR_END = 24,
|
|
CHAINED_SPIRT_COUNT = 20
|
|
};
|
|
|
|
Position const PosSummonChainedSpirits[CHAINED_SPIRT_COUNT] =
|
|
{
|
|
{ -12167.17f, -1979.330f, 133.0992f, 2.268928f },
|
|
{ -12262.74f, -1953.394f, 133.5496f, 0.593412f },
|
|
{ -12176.89f, -1983.068f, 133.7841f, 2.129302f },
|
|
{ -12226.45f, -1977.933f, 132.7982f, 1.466077f },
|
|
{ -12204.74f, -1890.431f, 135.7569f, 4.415683f },
|
|
{ -12216.70f, -1891.806f, 136.3496f, 4.677482f },
|
|
{ -12236.19f, -1892.034f, 134.1041f, 5.044002f },
|
|
{ -12248.24f, -1893.424f, 134.1182f, 5.270895f },
|
|
{ -12257.36f, -1897.663f, 133.1484f, 5.462881f },
|
|
{ -12265.84f, -1903.077f, 133.1649f, 5.654867f },
|
|
{ -12158.69f, -1972.707f, 133.8751f, 2.408554f },
|
|
{ -12178.82f, -1891.974f, 134.1786f, 3.944444f },
|
|
{ -12193.36f, -1890.039f, 135.1441f, 4.188790f },
|
|
{ -12275.59f, -1932.845f, 134.9017f, 0.174533f },
|
|
{ -12273.51f, -1941.539f, 136.1262f, 0.314159f },
|
|
{ -12247.02f, -1963.497f, 133.9476f, 0.872665f },
|
|
{ -12238.68f, -1969.574f, 133.6273f, 1.134464f },
|
|
{ -12192.78f, -1982.116f, 132.6966f, 1.919862f },
|
|
{ -12210.81f, -1979.316f, 133.8700f, 1.797689f },
|
|
{ -12283.51f, -1924.839f, 133.5170f, 0.069813f }
|
|
};
|
|
|
|
Position const PosMandokir[2] =
|
|
{
|
|
{ -12167.8f, -1927.25f, 153.73f, 3.76991f },
|
|
{ -12197.86f, -1949.392f, 130.2745f, 0.0f }
|
|
};
|
|
|
|
class boss_mandokir : public CreatureScript
|
|
{
|
|
public: boss_mandokir() : CreatureScript("boss_mandokir") { }
|
|
|
|
struct boss_mandokirAI : public BossAI
|
|
{
|
|
boss_mandokirAI(Creature* creature) : BossAI(creature, DATA_MANDOKIR) { }
|
|
|
|
void Reset()
|
|
{
|
|
if (me->GetPositionZ() > 140.0f)
|
|
{
|
|
|
|
killCount = 0;
|
|
events.ScheduleEvent(EVENT_CHECK_START, 1000);
|
|
if (Creature* speaker = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_VILEBRANCH_SPEAKER)))
|
|
if (!speaker->IsAlive())
|
|
speaker->Respawn(true);
|
|
}
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
|
|
summons.DespawnAll();
|
|
me->Mount(MODEL_OHGAN_MOUNT);
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
// Do not want to unsummon Ohgan
|
|
for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i)
|
|
if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpirtGUIDs[i]))
|
|
unsummon->DespawnOrUnsummon();
|
|
instance->SetBossState(DATA_MANDOKIR, DONE);
|
|
instance->SaveToDB();
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/)
|
|
{
|
|
_EnterCombat();
|
|
events.ScheduleEvent(EVENT_OVERPOWER, urand(7000, 9000));
|
|
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000));
|
|
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));
|
|
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)
|
|
{
|
|
Creature* chainedSpirt = me->SummonCreature(NPC_CHAINED_SPIRT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
|
|
chainedSpirtGUIDs[i] = chainedSpirt->GetGUID();
|
|
}
|
|
DoZoneInCombat();
|
|
}
|
|
|
|
void KilledUnit(Unit* victim)
|
|
{
|
|
if (victim->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (++killCount == 3)
|
|
{
|
|
Talk(SAY_DING_KILL);
|
|
if (Creature* jindo = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_JINDO)))
|
|
if (jindo->IsAlive())
|
|
jindo->AI()->Talk(SAY_GRATS_JINDO);
|
|
DoCast(me, SPELL_LEVEL_UP, true);
|
|
killCount = 0;
|
|
}
|
|
}
|
|
|
|
void MovementInform(uint32 type, uint32 id)
|
|
{
|
|
if (type == WAYPOINT_MOTION_TYPE)
|
|
{
|
|
me->SetWalk(false);
|
|
if (id == POINT_MANDOKIR_END)
|
|
{
|
|
me->SetHomePosition(PosMandokir[0]);
|
|
instance->SetBossState(DATA_MANDOKIR, NOT_STARTED);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
events.Update(diff);
|
|
|
|
if (!UpdateVictim())
|
|
{
|
|
if (instance->GetBossState(DATA_MANDOKIR) == NOT_STARTED || instance->GetBossState(DATA_MANDOKIR) == SPECIAL)
|
|
{
|
|
while (uint32 eventId = events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_CHECK_START:
|
|
if (instance->GetBossState(DATA_MANDOKIR) == SPECIAL)
|
|
{
|
|
me->GetMotionMaster()->MovePoint(0, PosMandokir[1].m_positionX, PosMandokir[1].m_positionY, PosMandokir[1].m_positionZ);
|
|
events.ScheduleEvent(EVENT_STARTED, 6000);
|
|
}
|
|
else
|
|
events.ScheduleEvent(EVENT_CHECK_START, 1000);
|
|
break;
|
|
case EVENT_STARTED:
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
while (uint32 eventId = events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_OVERPOWER:
|
|
DoCastVictim(SPELL_OVERPOWER, true);
|
|
events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 12000));
|
|
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));
|
|
break;
|
|
case EVENT_WHIRLWIND:
|
|
DoCast(me, SPELL_WHIRLWIND);
|
|
events.ScheduleEvent(EVENT_WHIRLWIND, urand(22000, 26000));
|
|
break;
|
|
case EVENT_CHECK_OHGAN:
|
|
if (instance->GetBossState(DATA_OHGAN) == DONE)
|
|
{
|
|
DoCast(me, SPELL_FRENZY);
|
|
Talk(SAY_OHGAN_DEAD);
|
|
}
|
|
else
|
|
events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000);
|
|
break;
|
|
case EVENT_WATCH_PLAYER:
|
|
if (Unit* player = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
|
{
|
|
DoCast(player, SPELL_WATCH);
|
|
Talk(SAY_WATCH, player);
|
|
}
|
|
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 15000));
|
|
break;
|
|
case EVENT_CHARGE_PLAYER:
|
|
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true), SPELL_CHARGE);
|
|
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(22000, 30000));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
|
|
private:
|
|
uint8 killCount;
|
|
uint64 chainedSpirtGUIDs[CHAINED_SPIRT_COUNT];
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetZulGurubAI<boss_mandokirAI>(creature);
|
|
}
|
|
};
|
|
|
|
// Ohgan
|
|
|
|
enum OhganSpells
|
|
{
|
|
SPELL_SUNDERARMOR = 24317
|
|
};
|
|
|
|
class npc_ohgan : public CreatureScript
|
|
{
|
|
public: npc_ohgan() : CreatureScript("npc_ohgan") { }
|
|
|
|
struct npc_ohganAI : public ScriptedAI
|
|
{
|
|
npc_ohganAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
|
|
|
|
void Reset()
|
|
{
|
|
SunderArmor_Timer = 5000;
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/) { }
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
instance->SetBossState(DATA_OHGAN, DONE);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
// Return since we have no target
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (SunderArmor_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_SUNDERARMOR, true);
|
|
SunderArmor_Timer = urand(10000, 15000);
|
|
} else SunderArmor_Timer -= diff;
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
|
|
private:
|
|
uint32 SunderArmor_Timer;
|
|
InstanceScript* instance;
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetZulGurubAI<npc_ohganAI>(creature);
|
|
}
|
|
};
|
|
|
|
enum VilebranchSpells
|
|
{
|
|
SPELL_DEMORALIZING_SHOUT = 13730,
|
|
SPELL_CLEAVE = 15284
|
|
};
|
|
|
|
class npc_vilebranch_speaker : public CreatureScript
|
|
{
|
|
public: npc_vilebranch_speaker() : CreatureScript("npc_vilebranch_speaker") { }
|
|
|
|
struct npc_vilebranch_speakerAI : public ScriptedAI
|
|
{
|
|
npc_vilebranch_speakerAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
|
|
|
|
void Reset()
|
|
{
|
|
demoralizing_Shout_Timer = urand(2000, 4000);
|
|
cleave_Timer = urand(5000, 8000);
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/) { }
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
instance->SetBossState(DATA_MANDOKIR, SPECIAL);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
// Return since we have no target
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (demoralizing_Shout_Timer <= diff)
|
|
{
|
|
DoCast(me, SPELL_DEMORALIZING_SHOUT);
|
|
demoralizing_Shout_Timer = urand(22000, 30000);
|
|
} else demoralizing_Shout_Timer -= diff;
|
|
|
|
if (cleave_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_CLEAVE, true);
|
|
cleave_Timer = urand(6000, 9000);
|
|
} else cleave_Timer -= diff;
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
|
|
private:
|
|
uint32 demoralizing_Shout_Timer;
|
|
uint32 cleave_Timer;
|
|
InstanceScript* instance;
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetInstanceAI<npc_vilebranch_speakerAI>(creature);
|
|
}
|
|
};
|
|
|
|
class spell_threatening_gaze : public SpellScriptLoader
|
|
{
|
|
public:
|
|
spell_threatening_gaze() : SpellScriptLoader("spell_threatening_gaze") { }
|
|
|
|
class spell_threatening_gaze_AuraScript : public AuraScript
|
|
{
|
|
PrepareAuraScript(spell_threatening_gaze_AuraScript);
|
|
|
|
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);
|
|
}
|
|
|
|
void Register()
|
|
{
|
|
OnEffectRemove += AuraEffectRemoveFn(spell_threatening_gaze_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
|
}
|
|
};
|
|
|
|
AuraScript* GetAuraScript() const
|
|
{
|
|
return new spell_threatening_gaze_AuraScript();
|
|
}
|
|
};
|
|
|
|
void AddSC_boss_mandokir()
|
|
{
|
|
new boss_mandokir();
|
|
new npc_ohgan();
|
|
new npc_vilebranch_speaker();
|
|
new spell_threatening_gaze();
|
|
}
|