Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-07-24 14:43:27 +08:00
19 changed files with 1049 additions and 1179 deletions

View File

@@ -24,18 +24,18 @@
enum Texts
{
SAY_KILL = 0,
SAY_RANDOM = 1,
SAY_DISARMED = 2,
SAY_MIDNIGHT_KILL = 3,
SAY_APPEAR = 4,
SAY_MOUNT = 5,
SAY_KILL = 0,
SAY_RANDOM = 1,
SAY_DISARMED = 2,
SAY_MIDNIGHT_KILL = 3,
SAY_APPEAR = 4,
SAY_MOUNT = 5,
SAY_DEATH = 3,
SAY_DEATH = 3,
// Midnight
EMOTE_CALL_ATTUMEN = 0,
EMOTE_MOUNT_UP = 1
EMOTE_CALL_ATTUMEN = 0,
EMOTE_MOUNT_UP = 1
};
enum Spells
@@ -45,7 +45,6 @@ enum Spells
SPELL_INTANGIBLE_PRESENCE = 29833,
SPELL_SPAWN_SMOKE = 10389,
SPELL_CHARGE = 29847,
// Midnight
SPELL_KNOCKDOWN = 29711,
SPELL_SUMMON_ATTUMEN = 29714,
@@ -62,406 +61,357 @@ enum Phases
enum Actions
{
ACTION_SET_MIDNIGHT_PHASE,
ACTION_SET_MIDNIGHT_PHASE
};
class boss_attumen : public CreatureScript
struct boss_attumen : public BossAI
{
public:
boss_attumen() : CreatureScript("boss_attumen") { }
struct boss_attumenAI : public BossAI
boss_attumen(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
Initialize();
}
Initialize();
}
void Initialize()
void Initialize()
{
_phase = PHASE_NONE;
}
void Reset() override
{
Initialize();
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->EnterEvadeMode(why);
}
me->DespawnOrUnsummon();
}
void ScheduleTasks() override
{
scheduler.Schedule(15s, 25s, [this](TaskContext task)
{
DoCastVictim(SPELL_SHADOWCLEAVE);
task.Repeat(15s, 25s);
});
scheduler.Schedule(25s, 45s, [this](TaskContext task)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
DoCast(target, SPELL_INTANGIBLE_PRESENCE);
}
task.Repeat(25s, 45s);
});
scheduler.Schedule(30s, 1min, [this](TaskContext task)
{
Talk(SAY_RANDOM);
task.Repeat(30s, 1min);
});
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) 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;
}
void Reset() override
{
Initialize();
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->EnterEvadeMode(why);
}
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*/, SpellSchoolMask /*damageSchoolMask*/) 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 = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
}
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
}
}
}
void KilledUnit(Unit* /*victim*/) override
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL);
}
}
void JustSummoned(Creature* summon) override
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (midnight->GetHealth() > me->GetHealth())
{
summon->SetHealth(midnight->GetHealth());
}
else
{
summon->SetHealth(me->GetHealth());
}
summon->AI()->DoZoneInCombat();
}
}
BossAI::JustSummoned(summon);
}
void IsSummonedBy(WorldObject* summoner) override
{
if (summoner->GetEntry() == NPC_MIDNIGHT)
{
_phase = PHASE_ATTUMEN_ENGAGES;
}
if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
_phase = PHASE_MOUNTED;
DoCastSelf(SPELL_SPAWN_SMOKE);
scheduler.Schedule(Seconds(10), Seconds(25), [this](TaskContext task)
{
Unit* target = nullptr;
std::vector<Unit*> target_list;
for (auto* ref : me->GetThreatMgr().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 = Acore::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 (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->KillSelf();
if (midnight->GetHealth() > me->GetHealth())
{
summon->SetHealth(midnight->GetHealth());
}
else
{
summon->SetHealth(me->GetHealth());
}
summon->AI()->DoZoneInCombat();
}
}
BossAI::JustSummoned(summon);
}
_JustDied();
void IsSummonedBy(WorldObject* summoner) override
{
if (summoner->GetEntry() == NPC_MIDNIGHT)
{
_phase = PHASE_ATTUMEN_ENGAGES;
}
if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
_phase = PHASE_MOUNTED;
DoCastSelf(SPELL_SPAWN_SMOKE);
scheduler.Schedule(10s, 25s, [this](TaskContext task)
{
Unit* target = nullptr;
std::vector<Unit*> target_list;
for (auto* ref : me->GetThreatMgr().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 = Acore::Containers::SelectRandomContainerElement(target_list);
}
DoCast(target, SPELL_CHARGE);
task.Repeat(10s, 25s);
});
scheduler.Schedule(25s, 35s, [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(25s, 35s);
});
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->KillSelf();
}
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_NONE)
{
if (!UpdateVictim())
{
return;
}
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Mechanic == MECHANIC_DISARM)
{
Talk(SAY_DISARMED);
}
void UpdateAI(uint32 diff) override
if (spellInfo->Id == SPELL_MOUNT)
{
if (_phase != PHASE_NONE)
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (!UpdateVictim())
_phase = PHASE_NONE;
scheduler.CancelAll();
midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE);
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(1s, [this](TaskContext task)
{
return;
}
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (me->IsWithinDist2d(midnight, 5.0f))
{
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
me->DespawnOrUnsummon(1s, 0s);
midnight->SetVisible(false);
}
else
{
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
task.Repeat();
}
}
});
}
}
}
private:
uint8 _phase;
};
struct boss_midnight : public BossAI
{
boss_midnight(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { }
void Reset() override
{
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_DEFENSIVE);
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) 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_THE_HUNTSMAN)
{
summon->AI()->AttackStart(me->GetVictim());
summon->AI()->Talk(SAY_APPEAR);
}
BossAI::JustSummoned(summon);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SET_MIDNIGHT_PHASE)
{
_phase = PHASE_MOUNTED;
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
scheduler.Schedule(15s, 25s, [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(15s, 25s);
});
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOnEvade(10s);
_phase = PHASE_NONE;
}
void KilledUnit(Unit* /*victim*/) override
{
if (_phase == PHASE_ATTUMEN_ENGAGES)
{
if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN))
{
Talk(SAY_MIDNIGHT_KILL, attumen);
}
}
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_MOUNTED)
{
if (!UpdateVictim())
{
return;
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Mechanic == MECHANIC_DISARM)
{
Talk(SAY_DISARMED);
}
if (spellInfo->Id == SPELL_MOUNT)
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
_phase = PHASE_NONE;
scheduler.CancelAll();
midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE);
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 = instance->GetCreature(DATA_MIDNIGHT))
{
if (me->IsWithinDist2d(midnight, 5.0f))
{
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
me->DespawnOrUnsummon(1s, 0s);
midnight->SetVisible(false);
}
else
{
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
task.Repeat();
}
}
});
}
}
}
private:
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_attumenAI>(creature);
scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
private:
uint8 _phase;
};
class boss_midnight : public CreatureScript
class spell_midnight_fixate : public AuraScript
{
public:
boss_midnight() : CreatureScript("boss_midnight") { }
PrepareAuraScript(spell_midnight_fixate)
struct boss_midnightAI : public BossAI
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { }
void Reset() override
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_DEFENSIVE);
caster->TauntApply(target);
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) 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_THE_HUNTSMAN)
{
summon->AI()->AttackStart(me->GetVictim());
summon->AI()->Talk(SAY_APPEAR);
}
BossAI::JustSummoned(summon);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SET_MIDNIGHT_PHASE)
{
_phase = PHASE_MOUNTED;
}
}
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
{
me->DespawnOnEvade(10s);
_phase = PHASE_NONE;
}
void KilledUnit(Unit* /*victim*/) override
{
if (_phase == PHASE_ATTUMEN_ENGAGES)
{
if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN))
{
Talk(SAY_MIDNIGHT_KILL, attumen);
}
}
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_MOUNTED)
{
if (!UpdateVictim())
{
return;
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
}
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
private:
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_midnightAI>(creature);
}
};
class spell_midnight_fixate : public SpellScriptLoader
{
public:
spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { }
class spell_midnight_fixate_AuraScript : public AuraScript
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
PrepareAuraScript(spell_midnight_fixate_AuraScript);
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntApply(target);
caster->TauntFadeOut(target);
}
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntFadeOut(target);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
void Register() override
{
return new spell_midnight_fixate_AuraScript();
OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_attumen()
{
new boss_midnight();
new boss_attumen();
new spell_midnight_fixate();
RegisterKarazhanCreatureAI(boss_midnight);
RegisterKarazhanCreatureAI(boss_attumen);
RegisterSpellScript(spell_midnight_fixate);
}

View File

@@ -46,19 +46,15 @@ enum Spells
enum Misc
{
EVENT_GUEST_TALK = 1,
EVENT_GUEST_TALK2 = 2,
EVENT_SPELL_VANISH = 3,
EVENT_SPELL_GARROTE = 4,
EVENT_SPELL_BLIND = 5,
EVENT_SPELL_GOUGE = 6,
EVENT_SPELL_ENRAGE = 7,
EVENT_KILL_TALK = 8,
ACTIVE_GUEST_COUNT = 4,
MAX_GUEST_COUNT = 6
};
enum Groups
{
GROUP_PRECOMBAT_TALK = 0
};
const Position GuestsPosition[4] =
{
{-10987.38f, -1883.38f, 81.73f, 1.50f},
@@ -78,6 +74,10 @@ struct boss_moroes : public BossAI
boss_moroes(Creature* creature) : BossAI(creature, DATA_MOROES)
{
_activeGuests = 0;
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void InitializeAI() override
@@ -111,46 +111,83 @@ struct boss_moroes : public BossAI
me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);
}
}
_events2.Reset();
_events2.ScheduleEvent(EVENT_GUEST_TALK, 10s);
scheduler.Schedule(10s, GROUP_PRECOMBAT_TALK, [this](TaskContext context)
{
if(Creature* guest = GetRandomGuest())
{
guest->AI()->Talk(SAY_GUEST);
}
context.Repeat(5s);
}).Schedule(1min, 2min, GROUP_PRECOMBAT_TALK, [this](TaskContext context)
{
//this was not scheduled in the previous commit
//does this have to be removed?
Talk(SAY_OUT_OF_COMBAT);
context.Repeat(1min, 2min);
});
}
void Reset() override
{
BossAI::Reset();
DoCastSelf(SPELL_DUAL_WIELD, true);
_recentlySpoken = false;
_vanished = false;
ScheduleHealthCheckEvent(30, [&] {
DoCastSelf(SPELL_FRENZY, true);
});
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_VANISH, 30s);
events.ScheduleEvent(EVENT_SPELL_BLIND, 20s);
events.ScheduleEvent(EVENT_SPELL_GOUGE, 13s);
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 10min);
_events2.Reset();
me->CallForHelp(20.0f);
DoZoneInCombat();
}
scheduler.CancelGroup(GROUP_PRECOMBAT_TALK);
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (HealthBelowPct(30))
scheduler.Schedule(30s, [this](TaskContext context)
{
DoCastSelf(SPELL_FRENZY, true);
}
scheduler.DelayAll(9s);
_vanished = true;
Talk(SAY_SPECIAL);
DoCastSelf(SPELL_VANISH);
me->SetImmuneToAll(true);
scheduler.Schedule(5s, 7s, [this](TaskContext)
{
me->SetImmuneToAll(false);
DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true);
DoCastSelf(SPELL_VANISH_TELEPORT);
_vanished = false;
});
context.Repeat(30s);
}).Schedule(20s, [this](TaskContext context)
{
DoCastMaxThreat(SPELL_BLIND, 1, 10.0f, true);
context.Repeat(25s, 40s);
}).Schedule(13s, [this](TaskContext context)
{
DoCastVictim(SPELL_GOUGE);
context.Repeat(25s, 40s);
}).Schedule(10min, [this](TaskContext)
{
DoCastSelf(SPELL_BERSERK, true);
});
}
void KilledUnit(Unit* victim) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
if(!_recentlySpoken && victim->GetTypeId() == TYPEID_PLAYER)
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
_recentlySpoken = true;
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 5s);
}
_recentlySpoken = false;
});
}
}
@@ -176,66 +213,22 @@ struct boss_moroes : public BossAI
void UpdateAI(uint32 diff) override
{
_events2.Update(diff);
switch (_events2.ExecuteEvent())
{
case EVENT_GUEST_TALK:
if (Creature* guest = GetRandomGuest())
{
guest->AI()->Talk(SAY_GUEST);
}
_events2.Repeat(5s);
break;
case EVENT_GUEST_TALK2:
Talk(SAY_OUT_OF_COMBAT);
_events2.Repeat(1min, 2min);
break;
}
scheduler.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
if (_vanished == false)
{
case EVENT_SPELL_ENRAGE:
DoCastSelf(SPELL_BERSERK, true);
break;
case EVENT_SPELL_BLIND:
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 10.0f, true))
{
DoCast(target, SPELL_BLIND);
}
events.Repeat(25s, 40s);
break;
case EVENT_SPELL_GOUGE:
DoCastVictim(SPELL_GOUGE);
events.Repeat(25s, 40s);
return;
case EVENT_SPELL_VANISH:
events.DelayEvents(9s);
events.SetPhase(1);
DoCastSelf(SPELL_VANISH);
events.Repeat(30s);
events.ScheduleEvent(EVENT_SPELL_GARROTE, 5s, 7s);
return;
case EVENT_SPELL_GARROTE:
Talk(SAY_SPECIAL);
DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true);
DoCastSelf(SPELL_VANISH_TELEPORT);
events.SetPhase(0);
break;
}
if (events.GetPhaseMask() == 0) // Xinef: not in vanish
DoMeleeAttackIfReady();
}
}
private:
EventMap _events2;
uint8 _activeGuests;
bool _recentlySpoken;
bool _vanished;
};
class spell_moroes_vanish : public SpellScript

View File

@@ -19,7 +19,7 @@
#include "ScriptedCreature.h"
#include "karazhan.h"
enum ServantQuartersSpells
enum Spells
{
SPELL_SNEAK = 22766,
SPELL_ACIDIC_FANG = 29901,
@@ -33,41 +33,37 @@ enum ServantQuartersSpells
SPELL_RAVAGE = 29906
};
enum ServantQuertersMisc
{
EVENT_SPELL_ACIDIC_FANG = 1,
EVENT_SPELL_HYAKISS_WEB = 2,
EVENT_SPELL_DIVE = 10,
EVENT_SPELL_SONIC_BURST = 11,
EVENT_SPELL_WING_BUFFET = 12,
EVENT_SPELL_FEAR = 13,
EVENT_SPELL_RAVAGE = 20,
EVENT_CHECK_VISIBILITY = 30
};
struct boss_servant_quarters : public BossAI
{
boss_servant_quarters(Creature* creature) : BossAI(creature, DATA_SERVANT_QUARTERS) { }
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
me->SetVisible(false);
me->SetReactState(REACT_PASSIVE);
me->SetFaction(FACTION_FRIENDLY);
_events2.Reset();
_events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s);
_scheduler.Schedule(5s, [this](TaskContext context)
{
if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE)
{
me->SetVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
else
{
context.Repeat(5s);
}
});
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
{
DoCastSelf(SPELL_SNEAK, true);
}
if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry())
{
me->DespawnOrUnsummon(1);
}
}
void JustEngagedWith(Unit* /*who*/) override
@@ -75,18 +71,42 @@ struct boss_servant_quarters : public BossAI
me->setActive(true);
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
{
events.ScheduleEvent(EVENT_SPELL_ACIDIC_FANG, 5s);
events.ScheduleEvent(EVENT_SPELL_HYAKISS_WEB, 9s);
_scheduler.Schedule(5s, [this](TaskContext context)
{
DoCastVictim(SPELL_ACIDIC_FANG);
context.Repeat(12s, 18s);
}).Schedule(9s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f);
context.Repeat(15s);
});
}
else if (me->GetEntry() == NPC_SHADIKITH_THE_GLIDER)
{
events.ScheduleEvent(EVENT_SPELL_SONIC_BURST, 4s);
events.ScheduleEvent(EVENT_SPELL_WING_BUFFET, 7s);
events.ScheduleEvent(EVENT_SPELL_DIVE, 10s);
_scheduler.Schedule(4s, [this](TaskContext context)
{
DoCastSelf(SPELL_SONIC_BURST);
context.Repeat(12s, 18s);
}).Schedule(7s, [this](TaskContext context)
{
DoCastSelf(SPELL_WING_BUFFET);
context.Repeat(12s, 18s);
}).Schedule(10s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
{
me->CastSpell(target, SPELL_DIVE);
}
context.Repeat(20s);
});
}
else // if (me->GetEntry() == NPC_ROKAD_THE_RAVAGER)
{
events.ScheduleEvent(EVENT_SPELL_RAVAGE, 3s);
_scheduler.Schedule(3s, [this](TaskContext context)
{
DoCastVictim(SPELL_RAVAGE);
context.Repeat(10500ms);
});
}
}
@@ -97,70 +117,28 @@ struct boss_servant_quarters : public BossAI
void MovementInform(uint32 type, uint32 point) override
{
if (type == POINT_MOTION_TYPE && point == EVENT_CHARGE)
events.ScheduleEvent(EVENT_SPELL_FEAR, 0);
{
_scheduler.Schedule(1ms, [this](TaskContext /*context*/)
{
DoCastVictim(SPELL_FEAR);
});
}
}
void UpdateAI(uint32 diff) override
{
_events2.Update(diff);
switch (_events2.ExecuteEvent())
{
case EVENT_CHECK_VISIBILITY:
if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE)
{
me->SetVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
else
_events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s);
break;
}
if (!UpdateVictim())
return;
events.Update(diff);
_scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_ACIDIC_FANG:
me->CastSpell(me->GetVictim(), SPELL_ACIDIC_FANG, false);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_HYAKISS_WEB:
DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f);
events.Repeat(15s);
break;
case EVENT_SPELL_SONIC_BURST:
DoCastSelf(SPELL_SONIC_BURST);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_WING_BUFFET:
DoCastSelf(SPELL_WING_BUFFET);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_DIVE:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
me->CastSpell(target, SPELL_DIVE, false);
events.Repeat(20s);
break;
case EVENT_SPELL_FEAR:
DoCastVictim(SPELL_FEAR);
break;
case EVENT_SPELL_RAVAGE:
me->CastSpell(me->GetVictim(), SPELL_RAVAGE, false);
events.ScheduleEvent(EVENT_SPELL_RAVAGE, 10500);
break;
}
DoMeleeAttackIfReady();
}
private:
EventMap _events2;
TaskScheduler _scheduler;
};
void AddSC_boss_servant_quarters()

View File

@@ -20,6 +20,7 @@
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "karazhan.h"
#include "TaskScheduler.h"
enum ShadeOfAran
{
@@ -58,9 +59,9 @@ enum ShadeOfAran
SPELL_SHADOW_PYRO = 29978,
//Creatures
CREATURE_WATER_ELEMENTAL = 17167,
CREATURE_SHADOW_OF_ARAN = 18254,
CREATURE_ARAN_BLIZZARD = 17161,
NPC_WATER_ELEMENTAL = 17167,
NPC_SHADOW_OF_ARAN = 18254,
NPC_ARAN_BLIZZARD = 17161,
};
enum SuperSpell
@@ -70,560 +71,458 @@ enum SuperSpell
SUPER_AE,
};
class boss_shade_of_aran : public CreatureScript
enum Groups
{
public:
boss_shade_of_aran() : CreatureScript("boss_shade_of_aran") { }
GROUP_FLAMEWREATH = 0,
GROUP_DRINKING = 1
};
struct boss_aranAI : public BossAI
Position const elementalPos[4] =
{
{-11168.1f, -1939.29f, 232.092f, 1.46f},
{-11138.2f, -1915.38f, 232.092f, 3.00f},
{-11161.7f, -1885.36f, 232.092f, 4.59f},
{-11192.4f, -1909.36f, 232.092f, 6.19f}
};
struct boss_shade_of_aran : public BossAI
{
boss_shade_of_aran(Creature* creature) : BossAI(creature, DATA_ARAN)
{
boss_aranAI(Creature* creature) : BossAI(creature, DATA_ARAN)
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
uint8 LastSuperSpell;
ObjectGuid FlameWreathTarget[3];
float FWTargPosX[3];
float FWTargPosY[3];
uint32 CurrentNormalSpell;
bool Drinking;
void Reset() override
{
BossAI::Reset();
drinkScheduler.CancelAll();
LastSuperSpell = rand() % 3;
for (uint8 i = 0; i < 3; ++i)
FlameWreathTarget[i].Clear();
CurrentNormalSpell = 0;
_arcaneCooledDown = true;
_fireCooledDown = true;
_frostCooledDown = true;
Drinking = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
uint32 SecondarySpellTimer;
uint32 NormalCastTimer;
uint32 SuperCastTimer;
uint32 BerserkTimer;
uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering.
ScheduleHealthCheckEvent(40, [&]{
Talk(SAY_ELEMENTALS);
uint8 LastSuperSpell;
uint32 FlameWreathTimer;
uint32 FlameWreathCheckTime;
ObjectGuid FlameWreathTarget[3];
float FWTargPosX[3];
float FWTargPosY[3];
uint32 CurrentNormalSpell;
uint32 ArcaneCooldown;
uint32 FireCooldown;
uint32 FrostCooldown;
uint32 DrinkInterruptTimer;
bool ElementalsSpawned;
bool Drinking;
bool DrinkInturrupted;
void Reset() override
{
SecondarySpellTimer = 5000;
NormalCastTimer = 0;
SuperCastTimer = 35000;
BerserkTimer = 720000;
CloseDoorTimer = 15000;
LastSuperSpell = rand() % 3;
FlameWreathTimer = 0;
FlameWreathCheckTime = 0;
for (uint8 i = 0; i < 3; ++i)
FlameWreathTarget[i].Clear();
CurrentNormalSpell = 0;
ArcaneCooldown = 0;
FireCooldown = 0;
FrostCooldown = 0;
DrinkInterruptTimer = 10000;
ElementalsSpawned = false;
Drinking = false;
DrinkInturrupted = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
for(Position pos : elementalPos)
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if(Creature* elemental = me->SummonCreature(NPC_WATER_ELEMENTAL, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000))
{
if(Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true))
{
DoStartNoMovement(target);
elemental->SetInCombatWithZone();
elemental->CombatStart(target);
}
}
}
}
});
}
void KilledUnit(Unit* /*victim*/) override
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
}
void TriggerArcaneCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_KILL);
}
_arcaneCooledDown = true;
});
}
void JustDied(Unit* /*killer*/) override
void TriggerFireCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_DEATH);
_fireCooledDown = true;
});
}
instance->SetData(DATA_ARAN, DONE);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
}
void JustEngagedWith(Unit* /*who*/) override
void TriggerFrostCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_AGGRO);
_frostCooledDown = true;
});
}
instance->SetData(DATA_ARAN, IN_PROGRESS);
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SetData(DATA_ARAN, DONE);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
instance->SetData(DATA_ARAN, IN_PROGRESS);
DoZoneInCombat();
//handle timed closing door
scheduler.Schedule(15s, [this](TaskContext)
{
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_READY);
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
DoZoneInCombat();
}
void FlameWreathEffect()
}).Schedule(1ms, [this](TaskContext context)
{
std::vector<Unit*> targets;
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
if (t_list.empty())
return;
//store the threat list in a different container
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
if (!me->IsNonMeleeSpellCast(false))
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
//only on alive players
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
targets.push_back(target);
}
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
return;
//cut down to size if we have more than 3 targets
while (targets.size() > 3)
targets.erase(targets.begin() + rand() % targets.size());
uint32 Spells[3];
uint8 AvailableSpells = 0;
uint32 i = 0;
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (*itr)
//Check for what spells are not on cooldown
if (_arcaneCooledDown)
{
FlameWreathTarget[i] = (*itr)->GetGUID();
FWTargPosX[i] = (*itr)->GetPositionX();
FWTargPosY[i] = (*itr)->GetPositionY();
DoCast((*itr), SPELL_FLAME_WREATH, true);
++i;
Spells[AvailableSpells] = SPELL_ARCMISSLE;
++AvailableSpells;
}
if (_fireCooledDown)
{
Spells[AvailableSpells] = SPELL_FIREBALL;
++AvailableSpells;
}
if (_frostCooledDown)
{
Spells[AvailableSpells] = SPELL_FROSTBOLT;
++AvailableSpells;
}
//If no available spells wait 1 second and try again
if (AvailableSpells)
{
CurrentNormalSpell = Spells[rand() % AvailableSpells];
DoCast(target, CurrentNormalSpell);
}
}
}
void UpdateAI(uint32 diff) override
context.Repeat(10s);
}).Schedule(5s, [this](TaskContext context)
{
if (!UpdateVictim())
return;
if (CloseDoorTimer)
switch (urand(0, 1))
{
if (CloseDoorTimer <= diff)
{
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
case 0:
DoCastSelf(SPELL_AOE_CS);
break;
case 1:
DoCastRandomTarget(SPELL_CHAINSOFICE);
break;
}
context.Repeat(5s, 20s);
}).Schedule(35s, [this](TaskContext context)
{
uint8 Available[2];
switch (LastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
LastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
DoCastSelf(SPELL_BLINK_CENTER, true);
DoCastSelf(SPELL_PLAYERPULL, true);
DoCastSelf(SPELL_MASSSLOW, true);
DoCastSelf(SPELL_AEXPLOSION, false);
break;
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
{
libraryDoor->SetGoState(GO_STATE_READY);
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
CloseDoorTimer = 0;
}
else
CloseDoorTimer -= diff;
}
//Cooldowns for casts
if (ArcaneCooldown)
{
if (ArcaneCooldown >= diff)
ArcaneCooldown -= diff;
else
ArcaneCooldown = 0;
}
if (FireCooldown)
{
if (FireCooldown >= diff)
FireCooldown -= diff;
else
FireCooldown = 0;
}
if (FrostCooldown)
{
if (FrostCooldown >= diff)
FrostCooldown -= diff;
else
FrostCooldown = 0;
}
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
Drinking = true;
me->InterruptNonMeleeSpells(false);
Talk(SAY_DRINK);
if (!DrinkInturrupted)
{
DoCast(me, SPELL_MASS_POLY, true);
DoCast(me, SPELL_CONJURE, false);
DoCast(me, SPELL_DRINK, false);
me->SetStandState(UNIT_STAND_STATE_SIT);
DrinkInterruptTimer = 10000;
}
}
//Drink Interrupt
if (Drinking && DrinkInturrupted)
{
Drinking = false;
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCast(me, SPELL_POTION, false);
}
//Drink Interrupt Timer
if (Drinking && !DrinkInturrupted)
{
if (DrinkInterruptTimer >= diff)
DrinkInterruptTimer -= diff;
else
{
me->SetStandState(UNIT_STAND_STATE_STAND);
DoCast(me, SPELL_POTION, true);
DoCast(me, SPELL_AOE_PYROBLAST, false);
DrinkInturrupted = true;
Drinking = false;
}
}
//Don't execute any more code if we are drinking
if (Drinking)
return;
//Normal casts
if (NormalCastTimer <= diff)
{
if (!me->IsNonMeleeSpellCast(false))
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
return;
uint32 Spells[3];
uint8 AvailableSpells = 0;
//Check for what spells are not on cooldown
if (!ArcaneCooldown)
scheduler.CancelGroup(GROUP_FLAMEWREATH);
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
{
Spells[AvailableSpells] = SPELL_ARCMISSLE;
++AvailableSpells;
}
if (!FireCooldown)
{
Spells[AvailableSpells] = SPELL_FIREBALL;
++AvailableSpells;
}
if (!FrostCooldown)
{
Spells[AvailableSpells] = SPELL_FROSTBOLT;
++AvailableSpells;
}
//If no available spells wait 1 second and try again
if (AvailableSpells)
{
CurrentNormalSpell = Spells[rand() % AvailableSpells];
DoCast(target, CurrentNormalSpell);
}
}
NormalCastTimer = 1000;
}
else
NormalCastTimer -= diff;
if (SecondarySpellTimer <= diff)
{
switch (urand(0, 1))
{
case 0:
DoCast(me, SPELL_AOE_CS);
break;
case 1:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_CHAINSOFICE);
break;
}
SecondarySpellTimer = urand(5000, 20000);
}
else
SecondarySpellTimer -= diff;
if (SuperCastTimer <= diff)
{
uint8 Available[2];
switch (LastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
LastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
DoCast(me, SPELL_BLINK_CENTER, true);
DoCast(me, SPELL_PLAYERPULL, true);
DoCast(me, SPELL_MASSSLOW, true);
DoCast(me, SPELL_AEXPLOSION, false);
break;
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
FlameWreathTimer = 20000;
FlameWreathCheckTime = 500;
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
FlameWreathEffect();
break;
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (Creature* pSpawn = me->SummonCreature(CREATURE_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
for (uint8 i = 0; i < 3; ++i)
{
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false);
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
unit->CastSpell(unit, 11027, true);
FlameWreathTarget[i].Clear();
}
}
break;
}
context.Repeat(500ms);
});
SuperCastTimer = urand(35000, 40000);
}
else
SuperCastTimer -= diff;
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
if (!ElementalsSpawned && HealthBelowPct(40))
{
ElementalsSpawned = true;
FlameWreathEffect();
break;
Creature* ElementalOne = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11168.1f, -1939.29f, 232.092f, 1.46f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalTwo = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11138.2f, -1915.38f, 232.092f, 3.00f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalThree = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11161.7f, -1885.36f, 232.092f, 4.59f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalFour = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11192.4f, -1909.36f, 232.092f, 6.19f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (ElementalOne)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalOne->SetInCombatWithZone();
ElementalOne->CombatStart(target);
ElementalOne->SetFaction(me->GetFaction());
ElementalOne->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalOne->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalTwo)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalTwo->SetInCombatWithZone();
ElementalTwo->CombatStart(target);
ElementalTwo->SetFaction(me->GetFaction());
ElementalTwo->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalTwo->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalThree)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalThree->SetInCombatWithZone();
ElementalThree->CombatStart(target);
ElementalThree->SetFaction(me->GetFaction());
ElementalThree->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalThree->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalFour)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalFour->SetInCombatWithZone();
ElementalFour->CombatStart(target);
ElementalFour->SetFaction(me->GetFaction());
ElementalFour->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalFour->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
Talk(SAY_ELEMENTALS);
}
if (BerserkTimer <= diff)
{
for (uint32 i = 0; i < 5; ++i)
{
if (Creature* unit = me->SummonCreature(CREATURE_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
{
unit->Attack(me->GetVictim(), true);
unit->SetFaction(me->GetFaction());
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
}
}
Talk(SAY_TIMEOVER);
BerserkTimer = 60000;
break;
}
else
BerserkTimer -= diff;
//Flame Wreath check
if (FlameWreathTimer)
context.Repeat(35s, 40s);
}).Schedule(12min, [this](TaskContext context)
{
for (uint32 i = 0; i < 5; ++i)
{
if (FlameWreathTimer >= diff)
FlameWreathTimer -= diff;
else
FlameWreathTimer = 0;
if (FlameWreathCheckTime <= diff)
if (Creature* unit = me->SummonCreature(NPC_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
{
for (uint8 i = 0; i < 3; ++i)
{
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
unit->CastSpell(unit, 11027, true);
FlameWreathTarget[i].Clear();
}
}
FlameWreathCheckTime = 500;
unit->Attack(me->GetVictim(), true);
unit->SetFaction(me->GetFaction());
}
else
FlameWreathCheckTime -= diff;
}
if (ArcaneCooldown && FireCooldown && FrostCooldown)
DoMeleeAttackIfReady();
Talk(SAY_TIMEOVER);
context.Repeat(1min);
});
}
void FlameWreathEffect()
{
std::vector<Unit*> targets;
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
if (t_list.empty())
return;
//store the threat list in a different container
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
//only on alive players
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
targets.push_back(target);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
//cut down to size if we have more than 3 targets
while (targets.size() > 3)
targets.erase(targets.begin() + rand() % targets.size());
uint32 i = 0;
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (!DrinkInturrupted && Drinking && damage)
DrinkInturrupted = true;
if (*itr)
{
FlameWreathTarget[i] = (*itr)->GetGUID();
FWTargPosX[i] = (*itr)->GetPositionX();
FWTargPosY[i] = (*itr)->GetPositionY();
DoCast((*itr), SPELL_FLAME_WREATH, true);
++i;
}
}
}
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
drinkScheduler.Update(diff);
if (!UpdateVictim())
return;
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
//We only care about interrupt effects and only if they are durring a spell currently being cast
if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
return;
//Interrupt effect
Drinking = true;
me->InterruptNonMeleeSpells(false);
//Normally we would set the cooldown equal to the spell duration
//but we do not have access to the DurationStore
Talk(SAY_DRINK);
switch (CurrentNormalSpell)
scheduler.DelayAll(10s);
DoCastSelf(SPELL_MASS_POLY, true);
DoCastSelf(SPELL_CONJURE, false);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK, true);
_currentHealth = me->GetHealth();
drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
{
case SPELL_ARCMISSLE:
ArcaneCooldown = 5000;
break;
case SPELL_FIREBALL:
FireCooldown = 5000;
break;
case SPELL_FROSTBOLT:
FrostCooldown = 5000;
break;
//check for damage to interrupt
if(CheckDamageDuringDrinking(_currentHealth))
{
Drinking = false;
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, false);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
drinkScheduler.CancelGroup(GROUP_DRINKING);
} else {
context.Repeat(500ms);
}
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, true);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
Drinking = false;
drinkScheduler.CancelGroup(GROUP_DRINKING);
});
}
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !Drinking)
DoMeleeAttackIfReady();
}
bool CheckDamageDuringDrinking(uint32 oldHealth)
{
if (Drinking)
{
if (me->GetHealth() < oldHealth)
{
return true;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_aranAI>(creature);
return false;
}
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
{
//We only care about interrupt effects and only if they are durring a spell currently being cast
if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
return;
//Interrupt effect
me->InterruptNonMeleeSpells(false);
//Normally we would set the cooldown equal to the spell duration
//but we do not have access to the DurationStore
switch (CurrentNormalSpell)
{
case SPELL_ARCMISSLE:
TriggerArcaneCooldown();
break;
case SPELL_FIREBALL:
TriggerFireCooldown();
break;
case SPELL_FROSTBOLT:
TriggerFrostCooldown();
break;
}
}
private:
TaskScheduler drinkScheduler;
bool _arcaneCooledDown;
bool _fireCooledDown;
bool _frostCooledDown;
uint32 _currentHealth;
};
class npc_aran_elemental : public CreatureScript
struct npc_aran_elemental : public ScriptedAI
{
public:
npc_aran_elemental() : CreatureScript("npc_aran_elemental") { }
CreatureAI* GetAI(Creature* creature) const override
npc_aran_elemental(Creature* creature) : ScriptedAI(creature)
{
return new water_elementalAI(creature);
SetCombatMovement(false);
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct water_elementalAI : public ScriptedAI
void Reset() override
{
water_elementalAI(Creature* creature) : ScriptedAI(creature)
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(2s, [this](TaskContext context)
{
}
DoCastVictim(SPELL_WATERBOLT);
context.Repeat(2s);
});
}
uint32 CastTimer;
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
void Reset() override
{
CastTimer = 2000 + (rand() % 3000);
}
void JustEngagedWith(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (CastTimer <= diff)
{
DoCastVictim(SPELL_WATERBOLT);
CastTimer = urand(2000, 5000);
}
else
CastTimer -= diff;
}
};
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_shade_of_aran()
{
new boss_shade_of_aran();
new npc_aran_elemental();
RegisterKarazhanCreatureAI(boss_shade_of_aran);
RegisterKarazhanCreatureAI(npc_aran_elemental);
}

View File

@@ -242,7 +242,11 @@ struct boss_eye_of_cthun : public BossAI
{
scheduler.Schedule(5s, [this](TaskContext task)
{
DoCastRandomTarget(SPELL_GREEN_BEAM);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
DoCast(target, SPELL_GREEN_BEAM);
DarkGlareAngle = me->GetAngle(target); //keep as the location dark glare will be at
}
task.SetGroup(GROUP_BEAM_PHASE);
task.Repeat(3s);
@@ -284,21 +288,18 @@ struct boss_eye_of_cthun : public BossAI
scheduler.Schedule(1s, [this](TaskContext /*task*/)
{
//Select random target for dark beam to start on
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
//Face our target
DarkGlareAngle = me->GetAngle(target);
DarkGlareTick = 0;
ClockWise = RAND(true, false);
//Select last target that had a beam cast on it
//Face our target
//Add red coloration to C'thun
DoCast(me, SPELL_RED_COLORATION, true);
DarkGlareTick = 0;
ClockWise = RAND(true, false);
me->StopMoving();
me->SetFacingToObject(target);
me->SetOrientation(DarkGlareAngle);
}
//Add red coloration to C'thun
DoCast(me, SPELL_RED_COLORATION, true);
me->StopMoving();
me->SetOrientation(DarkGlareAngle);
me->SetFacingTo(DarkGlareAngle);
scheduler.Schedule(3s, [this](TaskContext tasker)
{

View File

@@ -59,7 +59,13 @@ enum Spells
enum Groups
{
GROUP_INTERRUPT_CHECK = 0
GROUP_INTERRUPT_CHECK = 0,
GROUP_EARLY_RELEASE_CHECK = 1
};
enum Actions
{
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1
};
class DealDebrisDamage : public BasicEvent
@@ -92,8 +98,10 @@ struct boss_magtheridon : public BossAI
void Reset() override
{
BossAI::Reset();
_channelersKilled = 0;
_currentPhase = 0;
_recentlySpoken = false;
_magReleased = false;
_interruptScheduler.CancelAll();
scheduler.Schedule(90s, [this](TaskContext context)
{
@@ -154,60 +162,86 @@ struct boss_magtheridon : public BossAI
BossAI::JustDied(killer);
}
void ScheduleCombatEvents()
{
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_ACTIVATE_CUBES, 1);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
scheduler.Schedule(9s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(1200ms, 16300ms);
}).Schedule(20s, [this](TaskContext context)
{
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
context.Repeat(11s, 39s);
}).Schedule(40s, [this](TaskContext context)
{
DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell
scheduler.Schedule(7s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BLAST_NOVA);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
});
context.Repeat(53s, 56s);
}).Schedule(22min, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BERSERK, true);
});
}
void DoAction(int32 action) override
{
if (action == ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT)
{
_channelersKilled++;
if (_channelersKilled >= 5 && !_magReleased)
{
Talk(SAY_EMOTE_FREE);
Talk(SAY_FREE);
scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown
scheduler.Schedule(3s, [this](TaskContext)
{
_magReleased = true; //redundancy
ScheduleCombatEvents();
});
}
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_EMOTE_BEGIN);
scheduler.Schedule(60s, [this](TaskContext /*context*/)
scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
Talk(SAY_EMOTE_NEARLY);
}).Schedule(120s, [this](TaskContext /*context*/)
}).Schedule(120s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
Talk(SAY_EMOTE_FREE);
}).Schedule(123s, [this](TaskContext /*context*/)
Talk(SAY_FREE);
}).Schedule(123s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_ACTIVATE_CUBES, 1);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
scheduler.Schedule(9s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(1200ms, 16300ms);
}).Schedule(20s, [this](TaskContext context)
{
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
context.Repeat(11s, 39s);
}).Schedule(40s, [this](TaskContext context)
{
DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell
scheduler.Schedule(7s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BLAST_NOVA);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
});
context.Repeat(53s, 56s);
}).Schedule(1320s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BERSERK, true);
});
ScheduleCombatEvents();
});
}
@@ -227,7 +261,9 @@ struct boss_magtheridon : public BossAI
private:
bool _recentlySpoken;
bool _magReleased;
uint8 _currentPhase;
uint8 _channelersKilled;
TaskScheduler _interruptScheduler;
};

View File

@@ -259,127 +259,6 @@ public:
};
};
/*######
## go_corkis_prison and npc_corki
######*/
enum CorkiData
{
// first quest
QUEST_HELP = 9923,
NPC_CORKI = 18445,
NPC_CORKI_CREDIT_1 = 18369,
GO_CORKIS_PRISON = 182349,
CORKI_SAY_THANKS = 0,
// 2nd quest
QUEST_CORKIS_GONE_MISSING_AGAIN = 9924,
NPC_CORKI_2 = 20812,
GO_CORKIS_PRISON_2 = 182350,
CORKI_SAY_PROMISE = 0,
// 3rd quest
QUEST_CHOWAR_THE_PILLAGER = 9955,
NPC_CORKI_3 = 18369,
NPC_CORKI_CREDIT_3 = 18444,
GO_CORKIS_PRISON_3 = 182521,
CORKI_SAY_LAST = 0
};
class go_corkis_prison : public GameObjectScript
{
public:
go_corkis_prison() : GameObjectScript("go_corkis_prison") { }
bool OnGossipHello(Player* player, GameObject* go) override
{
go->SetGoState(GO_STATE_READY);
if (go->GetEntry() == GO_CORKIS_PRISON)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 5, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_CREDIT_1);
}
}
if (go->GetEntry() == GO_CORKIS_PRISON_2)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI_2, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() - 5, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_2);
}
}
if (go->GetEntry() == GO_CORKIS_PRISON_3)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI_3, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 4, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_CREDIT_3);
}
}
return true;
}
};
class npc_corki : public CreatureScript
{
public:
npc_corki() : CreatureScript("npc_corki") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_corkiAI(creature);
}
struct npc_corkiAI : public ScriptedAI
{
npc_corkiAI(Creature* creature) : ScriptedAI(creature) { }
uint32 Say_Timer;
bool ReleasedFromCage;
void Reset() override
{
Say_Timer = 5000;
ReleasedFromCage = false;
}
void UpdateAI(uint32 diff) override
{
if (ReleasedFromCage)
{
if (Say_Timer <= diff)
{
me->DespawnOrUnsummon();
ReleasedFromCage = false;
}
else
Say_Timer -= diff;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == 1)
{
Say_Timer = 5000;
ReleasedFromCage = true;
if (me->GetEntry() == NPC_CORKI)
Talk(CORKI_SAY_THANKS);
if (me->GetEntry() == NPC_CORKI_2)
Talk(CORKI_SAY_PROMISE);
if (me->GetEntry() == NPC_CORKI_3)
Talk(CORKI_SAY_LAST);
}
};
};
};
/*#####
## npc_kurenai_captive
#####*/
@@ -608,8 +487,6 @@ void AddSC_nagrand()
{
new npc_maghar_captive();
new npc_creditmarker_visit_with_ancestors();
new npc_corki();
new go_corkis_prison();
new npc_kurenai_captive();
new go_warmaul_prison();
}

View File

@@ -774,6 +774,49 @@ struct npc_pet_gen_moth : public NullCreatureAI
}
};
// Darting Hatchling
enum Darting
{
SPELL_DARTING_ON_SPAWN = 62586, // Applied on spawn via creature_template_addon
SPELL_DARTING_FEAR = 62585, // Applied every 20s from SPELL_DARTING_ON_SPAWN
};
struct npc_pet_darting_hatchling : public NullCreatureAI
{
npc_pet_darting_hatchling(Creature* c) : NullCreatureAI(c)
{
goFast = false;
checkTimer = 0;
}
bool goFast;
uint32 checkTimer;
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_DARTING_FEAR)
{
goFast = true;
}
}
void UpdateAI(uint32 diff) override
{
if (!goFast)
{
return;
}
checkTimer += diff;
if (checkTimer >= 2000)
{
me->RemoveAurasDueToSpell(SPELL_DARTING_FEAR);
checkTimer = 0;
goFast = false;
}
}
};
void AddSC_generic_pet_scripts()
{
RegisterCreatureAI(npc_pet_gen_soul_trader_beacon);
@@ -788,4 +831,5 @@ void AddSC_generic_pet_scripts()
RegisterCreatureAI(npc_pet_gen_toxic_wasteling);
RegisterCreatureAI(npc_pet_gen_fetch_ball);
RegisterCreatureAI(npc_pet_gen_moth);
RegisterCreatureAI(npc_pet_darting_hatchling);
}