/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
/* ScriptData
SDName: Boss_Midnight
SD%Complete: 100
SDComment:
SDCategory: Karazhan
EndScriptData */
#include "ScriptMgr.h"
#include "Containers.h"
#include "karazhan.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
enum Texts
{
SAY_KILL = 0,
SAY_RANDOM = 1,
SAY_DISARMED = 2,
SAY_MIDNIGHT_KILL = 3,
SAY_APPEAR = 4,
SAY_MOUNT = 5,
SAY_DEATH = 3,
// Midnight
EMOTE_CALL_ATTUMEN = 0,
EMOTE_MOUNT_UP = 1
};
enum Spells
{
// Attumen
SPELL_SHADOWCLEAVE = 29832,
SPELL_INTANGIBLE_PRESENCE = 29833,
SPELL_SPAWN_SMOKE = 10389,
SPELL_CHARGE = 29847,
// 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
{
public:
boss_attumen() : CreatureScript("boss_attumen") { }
struct boss_attumenAI : public BossAI
{
boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
Initialize();
}
void Initialize()
{
_midnightGUID.Clear();
_phase = PHASE_NONE;
}
void Reset() override
{
Initialize();
BossAI::Reset();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
BossAI::_DespawnAtEvade(Seconds(10), midnight);
me->DespawnOrUnsummon();
}
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(SelectTargetMethod::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, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) 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 JustSummoned(Creature* summon) override
{
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());
summon->AI()->DoZoneInCombat();
summon->AI()->SetGUID(_midnightGUID, NPC_MIDNIGHT);
}
BossAI::JustSummoned(summon);
}
void IsSummonedBy(WorldObject* 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;
std::vector target_list;
for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
{
target = ref->GetVictim();
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();
_JustDied();
}
void SetGUID(ObjectGuid const& guid, int32 id) override
{
if (id == NPC_MIDNIGHT)
_midnightGUID = guid;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && _phase != PHASE_NONE)
return;
scheduler.Update(diff);
}
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Mechanic == MECHANIC_DISARM)
Talk(SAY_DISARMED);
if (spellInfo->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()->MoveFollow(me, 2.0f, 0.0f);
midnight->AI()->Talk(EMOTE_MOUNT_UP);
me->AttackStop();
me->RemoveAllAttackers();
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
Talk(SAY_MOUNT);
scheduler.Schedule(Seconds(1), [this](TaskContext task)
{
if (Creature* midnight = ObjectAccessor::GetCreature(*me, _midnightGUID))
{
if (me->IsWithinDist2d(midnight, 5.0f))
{
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
me->SetVisible(false);
me->GetMotionMaster()->Clear();
midnight->SetVisible(false);
}
else
{
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
task.Repeat();
}
}
});
}
}
}
private:
ObjectGuid _midnightGUID;
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI(creature);
}
};
class boss_midnight : public CreatureScript
{
public:
boss_midnight() : CreatureScript("boss_midnight") { }
struct boss_midnightAI : public BossAI
{
boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
Initialize();
}
void Initialize()
{
_phase = PHASE_NONE;
}
void Reset() override
{
Initialize();
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_DEFENSIVE);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
// 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 JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(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(Seconds(10));
}
void KilledUnit(Unit* /*victim*/) override
{
if (_phase == PHASE_ATTUMEN_ENGAGES)
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, _attumenGUID))
Talk(SAY_MIDNIGHT_KILL, unit);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() || _phase == PHASE_MOUNTED)
return;
scheduler.Update(diff);
}
private:
ObjectGuid _attumenGUID;
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI(creature);
}
};
void AddSC_boss_attumen()
{
new boss_attumen();
new boss_midnight();
}