mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Scripts/Karazhan: Rework Attumen the Huntsman's script
Change log: - Timers are more accurate - Corrected Charge ability ID based on 6.x researches - Added Midnight's missing emotes - Fixed issue with instance being stuck in combat in case of wipes - Solved the rare scenario where Attumen would be summoned multiple times - Visual spell on 3rd phase transition added - Attumen and Midnight can now be damaged during 3rd phase transition - Midnight calls for the aid of every horse still alive in the stables - Use proper spells to summon Attumen and handle transitions - Now despawns on evade Video of encounter after changes: https://www.youtube.com/watch?v=KX0rqaBeSzw (cherry picked from commit4c4d92faa3) Scripts/Karazhan: Fix a warning (cherry picked from commit0cc33b5a42) Scripts/Karazhan: Register Midnight's summons * Solves issue with bosses not despawning after encounter (cherry picked from commit2d0fa2d020)
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
SET @ATTUMEN_UNMOUNTED := 15550;
|
||||
SET @ATTUMEN_MOUNTED := 16152;
|
||||
SET @MIDNIGHT := 16151;
|
||||
SET @GMIDNIGHT := 135159;
|
||||
|
||||
DELETE FROM `creature_text` WHERE `entry` IN (@MIDNIGHT, @ATTUMEN_UNMOUNTED, @ATTUMEN_MOUNTED);
|
||||
INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(@ATTUMEN_UNMOUNTED, 0, 0, 'It was... inevitable.', 14, 0, 100, 0, 0, 9169, 13460, 0, 'attumen SAY_KILL1'),
|
||||
(@ATTUMEN_UNMOUNTED, 0, 1, 'Another trophy to add to my collection!', 14, 0, 100, 0, 0, 9300, 15333, 0,'attumen SAY_KILL2'),
|
||||
(@ATTUMEN_UNMOUNTED, 1, 0, 'Such easy sport.', 14, 0, 100, 0, 0, 9170, 0, 0,'attumen SAY_RANDOM1'),
|
||||
(@ATTUMEN_UNMOUNTED, 1, 1, 'Amateurs! Do not think you can best me! I kill for a living.', 14, 0, 100, 0, 0, 9304, 0, 0, 'attumen SAY_RANDOM2'),
|
||||
(@ATTUMEN_UNMOUNTED, 2, 0, 'Weapons are merely a convenience for a warrior of my skill!', 14, 0, 100, 0, 0, 9166, 13490, 0, 'attumen SAY_DISARMED'),
|
||||
(@ATTUMEN_UNMOUNTED, 3, 0, 'Well done, Midnight!', 14, 0, 100, 0, 0, 9173, 15334, 0, 'attumen SAY_MIDNIGHT_KILL'),
|
||||
(@ATTUMEN_UNMOUNTED, 4, 0, 'Cowards! Wretches!', 14, 0, 100, 0, 0, 9167, 13459, 0, 'attumen SAY_APPEAR1'),
|
||||
(@ATTUMEN_UNMOUNTED, 4, 1, 'Who dares attack the steed of the Huntsman?', 14, 0, 100, 0, 0, 9298, 15378, 0, 'attumen SAY_APPEAR2'),
|
||||
(@ATTUMEN_UNMOUNTED, 4, 2, 'Perhaps you would rather test yourselves against a more formidable opponent?!', 14, 0, 100, 0, 0, 9299, 15379, 0, 'attumen SAY_APPEAR3'),
|
||||
(@ATTUMEN_UNMOUNTED, 5, 0, 'Come Midnight, let\'s disperse this petty rabble!', 14, 0, 100, 0, 0, 9168, 13456, 0, 'attumen SAY_MOUNT'),
|
||||
|
||||
(@ATTUMEN_MOUNTED, 0, 0, 'It was... inevitable.', 14, 0, 100, 0, 0, 9169, 13460, 0, 'attumen SAY_KILL1'),
|
||||
(@ATTUMEN_MOUNTED, 0, 1, 'Another trophy to add to my collection!', 14, 0, 100, 0, 0, 9300, 15333, 0,'attumen SAY_KILL2'),
|
||||
(@ATTUMEN_MOUNTED, 1, 0, 'Such easy sport.', 14, 0, 100, 0, 0, 9170, 0, 0,'attumen SAY_RANDOM1'),
|
||||
(@ATTUMEN_MOUNTED, 1, 1, 'Amateurs! Do not think you can best me! I kill for a living.', 14, 0, 100, 0, 0, 9304, 0, 0, 'attumen SAY_RANDOM2'),
|
||||
(@ATTUMEN_MOUNTED, 2, 0, 'Weapons are merely a convenience for a warrior of my skill!', 14, 0, 100, 0, 0, 9166, 13490, 0, 'attumen SAY_DISARMED'),
|
||||
(@ATTUMEN_MOUNTED, 3, 0, 'Always knew... someday I would become... the hunted.', 14, 0, 100, 0, 0, 9165, 13462, 0, 'attumen SAY_DEATH'),
|
||||
|
||||
(@MIDNIGHT, 0, 0, '%s calls for her master!', 16, 0, 100, 0, 0, 0, 13439, 0, 'midnight EMOTE_CALL_ATTUMEN'),
|
||||
(@MIDNIGHT, 1, 0, '%s rushes to her master\'s aid.', 16, 0, 100, 0, 0, 0, 13455, 0, 'midnight EMOTE_MOUNT_UP');
|
||||
|
||||
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` = 29770;
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 1, 29770, 0, 0, 31, 0, 3, 15550, 0, 0, 0, 0, '', 'Mount spell only hit Attumen the Huntsmen');
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` = 135159;
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
|
||||
(@GMIDNIGHT, @GMIDNIGHT, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135828, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135836, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135829, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135839, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135833, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135840, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135834, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135830, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135841, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135842, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135831, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135837, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135838, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135832, 0, 0, 1, 0, 0),
|
||||
(@GMIDNIGHT, 135835, 0, 0, 1, 0, 0);
|
||||
|
||||
UPDATE `creature_template` SET `ScriptName` = 'boss_attumen', `lootid` = @ATTUMEN_MOUNTED WHERE `entry` = @ATTUMEN_MOUNTED;
|
||||
UPDATE `creature_loot_template` SET `entry` = @ATTUMEN_MOUNTED WHERE `entry` = @ATTUMEN_UNMOUNTED;
|
||||
@@ -28,25 +28,42 @@ EndScriptData */
|
||||
#include "SpellInfo.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum Midnight
|
||||
enum Texts
|
||||
{
|
||||
SAY_MIDNIGHT_KILL = 0,
|
||||
SAY_APPEAR = 1,
|
||||
SAY_MOUNT = 2,
|
||||
SAY_KILL = 0,
|
||||
SAY_RANDOM = 1,
|
||||
SAY_DISARMED = 2,
|
||||
SAY_MIDNIGHT_KILL = 3,
|
||||
SAY_APPEAR = 4,
|
||||
SAY_MOUNT = 5,
|
||||
|
||||
SAY_KILL = 0,
|
||||
SAY_DISARMED = 1,
|
||||
SAY_DEATH = 2,
|
||||
SAY_RANDOM = 3,
|
||||
SAY_DEATH = 3,
|
||||
|
||||
SPELL_SHADOWCLEAVE = 29832,
|
||||
SPELL_INTANGIBLE_PRESENCE = 29833,
|
||||
SPELL_BERSERKER_CHARGE = 26561, //Only when mounted
|
||||
// Midnight
|
||||
EMOTE_CALL_ATTUMEN = 0,
|
||||
EMOTE_MOUNT_UP = 1
|
||||
};
|
||||
|
||||
MOUNTED_DISPLAYID = 16040,
|
||||
enum Spells
|
||||
{
|
||||
// Attumen
|
||||
SPELL_SHADOWCLEAVE = 29832,
|
||||
SPELL_INTANGIBLE_PRESENCE = 29833,
|
||||
SPELL_SPAWN_SMOKE = 10389,
|
||||
SPELL_CHARGE = 29847,
|
||||
|
||||
//Attumen (@todo Use the summoning spell instead of Creature id. It works, but is not convenient for us)
|
||||
SUMMON_ATTUMEN = 15550,
|
||||
// Midnight
|
||||
SPELL_KNOCKDOWN = 29711,
|
||||
SPELL_SUMMON_ATTUMEN = 29714,
|
||||
SPELL_MOUNT = 29770,
|
||||
SPELL_SUMMON_ATTUMEN_MOUNTED = 29799
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
PHASE_NONE,
|
||||
PHASE_ATTUMEN_ENGAGES,
|
||||
PHASE_MOUNTED
|
||||
};
|
||||
|
||||
class boss_attumen : public CreatureScript
|
||||
@@ -54,75 +71,212 @@ class boss_attumen : public CreatureScript
|
||||
public:
|
||||
boss_attumen() : CreatureScript("boss_attumen") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct boss_attumenAI : public BossAI
|
||||
{
|
||||
return new boss_attumenAI(creature);
|
||||
}
|
||||
|
||||
struct boss_attumenAI : public ScriptedAI
|
||||
{
|
||||
boss_attumenAI(Creature* creature) : ScriptedAI(creature)
|
||||
boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
Phase = 1;
|
||||
|
||||
CleaveTimer = urand(10000, 15000);
|
||||
CurseTimer = 30000;
|
||||
RandomYellTimer = urand(30000, 60000); //Occasionally yell
|
||||
ChargeTimer = 20000;
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
ResetTimer = 0;
|
||||
Midnight.Clear();
|
||||
_midnightGUID.Clear();
|
||||
_phase = PHASE_NONE;
|
||||
}
|
||||
|
||||
ObjectGuid Midnight;
|
||||
uint8 Phase;
|
||||
uint32 CleaveTimer;
|
||||
uint32 CurseTimer;
|
||||
uint32 RandomYellTimer;
|
||||
uint32 ChargeTimer; //only when mounted
|
||||
uint32 ResetTimer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
ResetTimer = 2000;
|
||||
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
|
||||
BossAI::_DespawnAtEvade(10, midnight);
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override { }
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWCLEAVE);
|
||||
task.Repeat(Seconds(15), Seconds(25));
|
||||
});
|
||||
|
||||
scheduler.Schedule(Seconds(25), Seconds(45), [this](TaskContext task)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target,SPELL_INTANGIBLE_PRESENCE);
|
||||
|
||||
task.Repeat(Seconds(25), Seconds(45));
|
||||
});
|
||||
|
||||
scheduler.Schedule(Seconds(30), Seconds(60), [this](TaskContext task)
|
||||
{
|
||||
Talk(SAY_RANDOM);
|
||||
task.Repeat(Seconds(30), Seconds(60));
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
|
||||
{
|
||||
// Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage.
|
||||
if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED)
|
||||
damage = me->GetHealth() - 1;
|
||||
|
||||
if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
|
||||
{
|
||||
_phase = PHASE_NONE;
|
||||
|
||||
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
|
||||
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
if (Unit* midnight = ObjectAccessor::GetUnit(*me, Midnight))
|
||||
midnight->KillSelf();
|
||||
if (summon->GetEntry() == NPC_ATTUMEN_MOUNTED)
|
||||
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
|
||||
{
|
||||
if (midnight->GetHealth() > me->GetHealth())
|
||||
summon->SetHealth(midnight->GetHealth());
|
||||
else
|
||||
summon->SetHealth(me->GetHealth());
|
||||
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
instance->SetBossState(DATA_ATTUMEN, DONE);
|
||||
summon->AI()->DoZoneInCombat();
|
||||
summon->AI()->SetGUID(_midnightGUID, NPC_MIDNIGHT);
|
||||
}
|
||||
|
||||
BossAI::JustSummoned(summon);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override;
|
||||
void IsSummonedBy(Unit* summoner) override
|
||||
{
|
||||
if (summoner->GetEntry() == NPC_MIDNIGHT)
|
||||
_phase = PHASE_ATTUMEN_ENGAGES;
|
||||
|
||||
if (summoner->GetEntry() == NPC_ATTUMEN_UNMOUNTED)
|
||||
{
|
||||
_phase = PHASE_MOUNTED;
|
||||
DoCastSelf(SPELL_SPAWN_SMOKE);
|
||||
|
||||
scheduler.Schedule(Seconds(10), Seconds(25), [this](TaskContext task)
|
||||
{
|
||||
Unit* target = nullptr;
|
||||
ThreatContainer::StorageType const &t_list = me->getThreatManager().getThreatList();
|
||||
std::vector<Unit*> target_list;
|
||||
|
||||
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
|
||||
{
|
||||
target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
|
||||
if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false))
|
||||
target_list.push_back(target);
|
||||
|
||||
target = nullptr;
|
||||
}
|
||||
|
||||
if (!target_list.empty())
|
||||
target = Trinity::Containers::SelectRandomContainerElement(target_list);
|
||||
|
||||
DoCast(target, SPELL_CHARGE);
|
||||
task.Repeat(Seconds(10), Seconds(25));
|
||||
});
|
||||
|
||||
scheduler.Schedule(Seconds(25), Seconds(35), [this](TaskContext task)
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
task.Repeat(Seconds(25), Seconds(35));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
if (Unit* midnight = ObjectAccessor::GetUnit(*me, _midnightGUID))
|
||||
midnight->KillSelf();
|
||||
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid guid, int32 data) override
|
||||
{
|
||||
if (data == NPC_MIDNIGHT)
|
||||
_midnightGUID = guid;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() && _phase != PHASE_NONE)
|
||||
return;
|
||||
|
||||
scheduler.Update(diff,
|
||||
std::bind(&BossAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*source*/, const SpellInfo* spell) override
|
||||
{
|
||||
if (spell->Mechanic == MECHANIC_DISARM)
|
||||
Talk(SAY_DISARMED);
|
||||
|
||||
if (spell->Id == SPELL_MOUNT)
|
||||
{
|
||||
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
|
||||
{
|
||||
_phase = PHASE_NONE;
|
||||
scheduler.CancelAll();
|
||||
|
||||
midnight->AttackStop();
|
||||
midnight->RemoveAllAttackers();
|
||||
midnight->SetReactState(REACT_PASSIVE);
|
||||
midnight->GetMotionMaster()->MoveChase(me);
|
||||
midnight->AI()->Talk(EMOTE_MOUNT_UP);
|
||||
|
||||
me->AttackStop();
|
||||
me->RemoveAllAttackers();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->GetMotionMaster()->MoveChase(midnight);
|
||||
Talk(SAY_MOUNT);
|
||||
|
||||
scheduler.Schedule(Seconds(3), [this](TaskContext task)
|
||||
{
|
||||
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
|
||||
{
|
||||
if (me->IsWithinMeleeRange(midnight))
|
||||
{
|
||||
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
|
||||
me->SetVisible(false);
|
||||
midnight->SetVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
midnight->GetMotionMaster()->MoveChase(me);
|
||||
me->GetMotionMaster()->MoveChase(midnight);
|
||||
task.Repeat(Seconds(3));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _midnightGUID;
|
||||
uint8 _phase;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new boss_attumenAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_midnight : public CreatureScript
|
||||
@@ -130,215 +284,103 @@ class boss_midnight : public CreatureScript
|
||||
public:
|
||||
boss_midnight() : CreatureScript("boss_midnight") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct boss_midnightAI : public BossAI
|
||||
{
|
||||
return new boss_midnightAI(creature);
|
||||
}
|
||||
|
||||
struct boss_midnightAI : public ScriptedAI
|
||||
{
|
||||
boss_midnightAI(Creature* creature) : ScriptedAI(creature)
|
||||
boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Phase = 1;
|
||||
Attumen.Clear();
|
||||
Mount_Timer = 0;
|
||||
_phase = PHASE_NONE;
|
||||
}
|
||||
|
||||
ObjectGuid Attumen;
|
||||
uint8 Phase;
|
||||
uint32 Mount_Timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
BossAI::Reset();
|
||||
me->SetVisible(true);
|
||||
me->SetReactState(REACT_DEFENSIVE);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
instance->SetBossState(DATA_ATTUMEN, IN_PROGRESS);
|
||||
// Midnight never dies, let health fall to 1 and prevent further damage.
|
||||
if (damage >= me->GetHealth())
|
||||
damage = me->GetHealth() - 1;
|
||||
|
||||
if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage))
|
||||
{
|
||||
_phase = PHASE_ATTUMEN_ENGAGES;
|
||||
Talk(EMOTE_CALL_ATTUMEN);
|
||||
DoCastAOE(SPELL_SUMMON_ATTUMEN);
|
||||
}
|
||||
else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
|
||||
{
|
||||
_phase = PHASE_MOUNTED;
|
||||
DoCastAOE(SPELL_MOUNT, true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (summon->GetEntry() == NPC_ATTUMEN_UNMOUNTED)
|
||||
{
|
||||
_attumenGUID = summon->GetGUID();
|
||||
summon->AI()->SetGUID(me->GetGUID(), NPC_MIDNIGHT);
|
||||
summon->AI()->AttackStart(me->GetVictim());
|
||||
summon->AI()->Talk(SAY_APPEAR);
|
||||
}
|
||||
|
||||
BossAI::JustSummoned(summon);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
|
||||
scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task)
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
task.Repeat(Seconds(15), Seconds(25));
|
||||
});
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
BossAI::_DespawnAtEvade(10);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (Phase == 2)
|
||||
if (_phase == PHASE_ATTUMEN_ENGAGES)
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, Attumen))
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, _attumenGUID))
|
||||
Talk(SAY_MIDNIGHT_KILL, unit);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
if (!UpdateVictim() || _phase == PHASE_MOUNTED)
|
||||
return;
|
||||
|
||||
if (Phase == 1 && HealthBelowPct(95))
|
||||
{
|
||||
Phase = 2;
|
||||
if (Creature* attumen = me->SummonCreature(SUMMON_ATTUMEN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000))
|
||||
{
|
||||
Attumen = attumen->GetGUID();
|
||||
attumen->AI()->AttackStart(me->GetVictim());
|
||||
SetMidnight(attumen, me->GetGUID());
|
||||
Talk(SAY_APPEAR, attumen);
|
||||
}
|
||||
}
|
||||
else if (Phase == 2 && HealthBelowPct(25))
|
||||
{
|
||||
if (Unit* pAttumen = ObjectAccessor::GetUnit(*me, Attumen))
|
||||
Mount(pAttumen);
|
||||
}
|
||||
else if (Phase == 3)
|
||||
{
|
||||
if (Mount_Timer)
|
||||
{
|
||||
if (Mount_Timer <= diff)
|
||||
{
|
||||
Mount_Timer = 0;
|
||||
me->SetVisible(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
if (Unit* pAttumen = ObjectAccessor::GetUnit(*me, Attumen))
|
||||
{
|
||||
pAttumen->SetDisplayId(MOUNTED_DISPLAYID);
|
||||
pAttumen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
if (pAttumen->GetVictim())
|
||||
{
|
||||
pAttumen->GetMotionMaster()->MoveChase(pAttumen->GetVictim());
|
||||
pAttumen->SetTarget(pAttumen->EnsureVictim()->GetGUID());
|
||||
}
|
||||
pAttumen->SetObjectScale(1);
|
||||
}
|
||||
} else Mount_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
if (Phase != 3)
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff,
|
||||
std::bind(&BossAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
|
||||
void Mount(Unit* pAttumen)
|
||||
{
|
||||
Talk(SAY_MOUNT, pAttumen);
|
||||
Phase = 3;
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
pAttumen->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
float angle = me->GetAngle(pAttumen);
|
||||
float distance = me->GetDistance2d(pAttumen);
|
||||
float newX = me->GetPositionX() + std::cos(angle)*(distance/2);
|
||||
float newY = me->GetPositionY() + std::sin(angle)*(distance/2);
|
||||
float newZ = 50;
|
||||
//me->Relocate(newX, newY, newZ, angle);
|
||||
//me->SendMonsterMove(newX, newY, newZ, 0, true, 1000);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MovePoint(0, newX, newY, newZ);
|
||||
distance += 10;
|
||||
newX = me->GetPositionX() + std::cos(angle)*(distance/2);
|
||||
newY = me->GetPositionY() + std::sin(angle)*(distance/2);
|
||||
pAttumen->GetMotionMaster()->Clear();
|
||||
pAttumen->GetMotionMaster()->MovePoint(0, newX, newY, newZ);
|
||||
//pAttumen->Relocate(newX, newY, newZ, -angle);
|
||||
//pAttumen->SendMonsterMove(newX, newY, newZ, 0, true, 1000);
|
||||
Mount_Timer = 1000;
|
||||
}
|
||||
|
||||
void SetMidnight(Creature* pAttumen, ObjectGuid value)
|
||||
{
|
||||
ENSURE_AI(boss_attumen::boss_attumenAI, pAttumen->AI())->Midnight = value;
|
||||
}
|
||||
private:
|
||||
ObjectGuid _attumenGUID;
|
||||
uint8 _phase;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new boss_midnightAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void boss_attumen::boss_attumenAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (ResetTimer)
|
||||
{
|
||||
if (ResetTimer <= diff)
|
||||
{
|
||||
ResetTimer = 0;
|
||||
Unit* pMidnight = ObjectAccessor::GetUnit(*me, Midnight);
|
||||
if (pMidnight)
|
||||
{
|
||||
pMidnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
pMidnight->SetVisible(true);
|
||||
}
|
||||
Midnight.Clear();
|
||||
me->SetVisible(false);
|
||||
me->KillSelf();
|
||||
} else ResetTimer -= diff;
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
|
||||
return;
|
||||
|
||||
if (CleaveTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWCLEAVE);
|
||||
CleaveTimer = urand(10000, 15000);
|
||||
} else CleaveTimer -= diff;
|
||||
|
||||
if (CurseTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_INTANGIBLE_PRESENCE);
|
||||
CurseTimer = 30000;
|
||||
} else CurseTimer -= diff;
|
||||
|
||||
if (RandomYellTimer <= diff)
|
||||
{
|
||||
Talk(SAY_RANDOM);
|
||||
RandomYellTimer = urand(30000, 60000);
|
||||
} else RandomYellTimer -= diff;
|
||||
|
||||
if (me->GetUInt32Value(UNIT_FIELD_DISPLAYID) == MOUNTED_DISPLAYID)
|
||||
{
|
||||
if (ChargeTimer <= diff)
|
||||
{
|
||||
Unit* target = NULL;
|
||||
ThreatContainer::StorageType const &t_list = me->getThreatManager().getThreatList();
|
||||
std::vector<Unit*> target_list;
|
||||
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
|
||||
{
|
||||
target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
|
||||
if (target && !target->IsWithinDist(me, ATTACK_DISTANCE, false))
|
||||
target_list.push_back(target);
|
||||
target = NULL;
|
||||
}
|
||||
if (!target_list.empty())
|
||||
target = *(target_list.begin() + rand32() % target_list.size());
|
||||
|
||||
DoCast(target, SPELL_BERSERKER_CHARGE);
|
||||
ChargeTimer = 20000;
|
||||
} else ChargeTimer -= diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HealthBelowPct(25))
|
||||
{
|
||||
Creature* pMidnight = ObjectAccessor::GetCreature(*me, Midnight);
|
||||
if (pMidnight && pMidnight->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
ENSURE_AI(boss_midnight::boss_midnightAI, (pMidnight->AI()))->Mount(me);
|
||||
me->SetHealth(pMidnight->GetHealth());
|
||||
DoResetThreat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void AddSC_boss_attumen()
|
||||
{
|
||||
new boss_attumen();
|
||||
|
||||
@@ -70,6 +70,9 @@ enum KZMiscCreatures
|
||||
NPC_SHADIKITH_THE_GLIDER = 16180,
|
||||
NPC_TERESTIAN_ILLHOOF = 15688,
|
||||
NPC_MOROES = 15687,
|
||||
NPC_ATTUMEN_UNMOUNTED = 15550,
|
||||
NPC_ATTUMEN_MOUNTED = 16152,
|
||||
NPC_MIDNIGHT = 16151,
|
||||
|
||||
// Trash
|
||||
NPC_COLDMIST_WIDOW = 16171,
|
||||
|
||||
Reference in New Issue
Block a user