Scripts/SFK: implement all bosses

This commit is contained in:
Ovalord
2017-12-18 22:38:38 +01:00
parent e43a015b83
commit bad49ddb83
11 changed files with 2732 additions and 538 deletions

View File

@@ -0,0 +1,350 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "shadowfang_keep.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Player.h"
enum Spells
{
// Baron Ashbury
SPELL_ASPHYXIATE = 93423,
SPELL_ASPHYXIATE_ROOT = 93422,
SPELL_ASPHYXIATE_DAMAGE = 93424,
SPELL_STAY_OF_EXECUTION = 93468,
SPELL_STAY_OF_EXECUTION_HC = 93705,
SPELL_PAIN_AND_SUFFERING = 93581,
SPELL_PAIN_AND_SUFFERING_DUMMY = 93605,
SPELL_WRACKING_PAIN = 93720,
SPELL_DARK_ARCHANGEL = 93757,
SPELL_CALAMITY_CHANNEL = 93812,
// Wings
SPELL_RIDE_VEHICLE_HARDCODED = 46598,
SPELL_CALAMITY_AURA = 93766,
};
enum Texts
{
SAY_AGGRO = 1,
SAY_ASPHYXIATE = 2,
SAY_ANNOUNCE_STAY = 3,
SAY_STAY_EXECUTION = 4,
SAY_ARCHANGEL = 5,
SAY_DEATH = 6,
};
enum Events
{
EVENT_ASPHYXIATE = 1,
EVENT_STAY_OF_EXECUTION,
EVENT_PAIN_AND_SUFFERING,
EVENT_WRACKING_PAIN,
EVENT_DARK_ARCHANGEL,
EVENT_APPLY_IMMUNITY,
EVENT_DISABLE_ACHIEVEMENT,
};
enum AchievementData
{
DATA_PARDON_DENIED = 1,
};
class boss_baron_ashbury : public CreatureScript
{
public:
boss_baron_ashbury() : CreatureScript("boss_baron_ashbury") { }
struct boss_baron_ashburyAI : public BossAI
{
boss_baron_ashburyAI(Creature* creature) : BossAI(creature, DATA_BARON_ASHBURY)
{
}
void Reset() override
{
_Reset();
_isArchangel = false;
_canAttack = true;
_pardonDenied = true;
me->SetReactState(REACT_PASSIVE);
MakeInterruptable(false);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_ASPHYXIATE, Seconds(20));
events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, Seconds(5) + Milliseconds(500));
if (IsHeroic())
events.ScheduleEvent(EVENT_WRACKING_PAIN, Seconds(14));
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WRACKING_PAIN);
Talk(SAY_DEATH);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_EnterEvadeMode();
summons.DespawnAll();
instance->SetBossState(DATA_BARON_ASHBURY, FAIL);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WRACKING_PAIN);
MakeInterruptable(false);
me->SetReactState(REACT_PASSIVE);
_DespawnAtEvade();
}
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override
{
if (me->HealthBelowPct(25) && !_isArchangel && IsHeroic())
{
events.Reset();
events.ScheduleEvent(EVENT_DARK_ARCHANGEL, Milliseconds(1));
_isArchangel = true;
}
}
void OnSpellCastInterrupt(SpellInfo const* spell) override
{
MakeInterruptable(false);
events.CancelEvent(EVENT_APPLY_IMMUNITY);
if (spell->Id == SPELL_STAY_OF_EXECUTION_HC && _pardonDenied)
events.CancelEvent(EVENT_DISABLE_ACHIEVEMENT);
}
void MakeInterruptable(bool apply)
{
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, !apply);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, !apply);
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_PARDON_DENIED:
return _pardonDenied;
default:
break;
}
return 0;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while(uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ASPHYXIATE:
Talk(SAY_ASPHYXIATE);
DoCastAOE(SPELL_ASPHYXIATE);
events.ScheduleEvent(EVENT_STAY_OF_EXECUTION, Seconds(7));
_canAttack = false;
break;
case EVENT_STAY_OF_EXECUTION:
if (IsHeroic())
{
MakeInterruptable(true);
events.ScheduleEvent(EVENT_APPLY_IMMUNITY, Seconds(8));
events.ScheduleEvent(EVENT_DISABLE_ACHIEVEMENT, Seconds(8));
}
Talk(SAY_STAY_EXECUTION);
Talk(SAY_ANNOUNCE_STAY);
DoCastAOE(SPELL_STAY_OF_EXECUTION);
events.ScheduleEvent(EVENT_ASPHYXIATE, Seconds(45));
_canAttack = true;
break;
case EVENT_PAIN_AND_SUFFERING:
MakeInterruptable(true);
me->StopMoving();
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_PAIN_AND_SUFFERING);
events.ScheduleEvent(EVENT_APPLY_IMMUNITY, IsHeroic() ? Seconds(6) : Seconds(8));
events.Repeat(Seconds(26) + Milliseconds(500));
break;
case EVENT_WRACKING_PAIN:
DoCastAOE(SPELL_WRACKING_PAIN);
events.Repeat(Seconds(26) + Milliseconds(500));
break;
case EVENT_DARK_ARCHANGEL:
Talk(SAY_ARCHANGEL);
me->CastStop();
DoCastAOE(SPELL_DARK_ARCHANGEL);
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
MakeInterruptable(false);
if (Creature* wings = DoSummon(NPC_ASHBURY_WINGS, me->GetPosition(), 0, TEMPSUMMON_MANUAL_DESPAWN))
wings->CastSpell(me, SPELL_RIDE_VEHICLE_HARDCODED);
break;
case EVENT_APPLY_IMMUNITY:
MakeInterruptable(true);
break;
case EVENT_DISABLE_ACHIEVEMENT:
_pardonDenied = false;
break;
default:
break;
}
}
if (_canAttack)
DoMeleeAttackIfReady();
}
private:
bool _isArchangel;
bool _canAttack;
bool _pardonDenied;
};
CreatureAI* GetAI(Creature *creature) const override
{
return GetShadowfangKeepAI<boss_baron_ashburyAI>(creature);
}
};
class spell_sfk_asphyxiate : public SpellScriptLoader
{
public:
spell_sfk_asphyxiate() : SpellScriptLoader("spell_sfk_asphyxiate") { }
class spell_sfk_asphyxiate_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_asphyxiate_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ASPHYXIATE_ROOT });
}
void HandleTriggerSpell(AuraEffect const* aurEff)
{
PreventDefaultAction();
if (Unit* caster = GetCaster())
{
if (Unit* target = GetTarget())
{
uint32 triggerSpell = GetSpellInfo()->Effects[EFFECT_2].TriggerSpell;
uint64 damage = target->GetMaxHealth() / GetSpellInfo()->GetMaxTicks();
if (damage > target->GetHealth())
damage = target->GetHealth() - 1;
if (!target->HasAura(SPELL_ASPHYXIATE_ROOT))
target->CastSpell(target, SPELL_ASPHYXIATE_ROOT, true);
target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, damage, target, true, nullptr, aurEff, caster->GetGUID());
}
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_asphyxiate_AuraScript::HandleTriggerSpell, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sfk_asphyxiate_AuraScript();
}
};
class spell_sfk_pain_and_suffering : public SpellScriptLoader
{
public:
spell_sfk_pain_and_suffering() : SpellScriptLoader("spell_sfk_pain_and_suffering") { }
class spell_sfk_pain_and_suffering_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_pain_and_suffering_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PAIN_AND_SUFFERING_DUMMY });
}
void OnPeriodic(AuraEffect const* aurEff)
{
if (Unit* owner = GetOwner()->ToUnit())
if (InstanceScript* instance = owner->GetInstanceScript())
if (Creature* ashbury = instance->GetCreature(DATA_BARON_ASHBURY))
owner->CastSpell(ashbury, SPELL_PAIN_AND_SUFFERING_DUMMY, true);
uint64 damage = aurEff->GetBaseAmount() * aurEff->GetTickNumber();
GetEffect(EFFECT_0)->ChangeAmount(damage);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_pain_and_suffering_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sfk_pain_and_suffering_AuraScript();
}
};
class achievement_pardon_denied : public AchievementCriteriaScript
{
public:
achievement_pardon_denied() : AchievementCriteriaScript("achievement_pardon_denied") { }
bool OnCheck(Player* /*source*/, Unit* target)
{
if (!target)
return false;
if (target->GetMap()->IsHeroic())
return target->GetAI()->GetData(DATA_PARDON_DENIED);
return false;
}
};
void AddSC_boss_baron_ashbury()
{
new boss_baron_ashbury();
new spell_sfk_asphyxiate();
new spell_sfk_pain_and_suffering();
new achievement_pardon_denied();
}

View File

@@ -0,0 +1,606 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "shadowfang_keep.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Player.h"
enum Texts
{
SAY_AGGRO = 0,
SAY_DEATH = 1,
SAY_SLAY = 2,
};
enum Events
{
// Baron Silverlaine
EVENT_VEIL_OF_SHADOW = 1,
EVENT_CURSED_VEIL,
EVENT_SUMMON_WORGEN_SPIRIT,
// Odo the Blindwatcher
EVENT_HOWLING_RAGE,
// Wolf Master Nandos
EVENT_CLAW,
// Razorclaw the Butcher
EVENT_SPECTRAL_RUSH,
EVENT_SPECTRAL_RAVAGING,
EVENT_BUTCHER_DRAIN,
// Rethilgore
EVENT_SOUL_DRAIN
};
enum Actions
{
ACTION_DESPAWN = 1
};
enum Spells
{
SPELL_VEIL_OF_SHADOWS = 23224,
SPELL_CURSED_VEIL = 93956,
SPELL_SUMMON_WORGEN_SPIRIT = 93857,
SPELL_SUMMON_WORGEN_SPIRIT_NANDOS_DUMMY = 93896, // Dummy Summon
SPELL_SUMMON_WORGEN_SPIRIT_NANDOS_SUMMON = 93899,
SPELL_SUMMON_WORGEN_SPIRIT_ODO_DUMMY = 93859, // Dummy Summon
SPELL_SUMMON_WORGEN_SPIRIT_ODO_SUMMON = 93899,
SPELL_SUMMON_WORGEN_SPIRIT_RAZORCLAW_DUMMY = 93921, // Dummy Summon
SPELL_SUMMON_WORGEN_SPIRIT_RAZORCLAW_SUMMON = 93924,
SPELL_SUMMON_WORGEN_SPIRIT_RETHILGORE_DUMMY = 93925, // Dummy Summon
SPELL_SUMMON_WORGEN_SPIRIT_RETHILGORE_SUMMON = 93927,
// Odo the Blindwatcher
SPELL_HOWLING_RAGE = 93931,
SPELL_BLINDING_SHADOWS = 93952,
// Wolf Master Nandos
SPELL_CLAW = 16827,
SPELL_SUMMON_LUPINE_SPECTRE = 94199,
// Razorclaw the Butcher
SPELL_SPECTRAL_RAVAGING = 93930,
SPELL_SPECTRAL_RUSH = 93914,
SPELL_BUTCHER_DRAIN = 7485,
// Rethilgore
SPELL_SOUL_DRAIN = 93863
};
class boss_baron_silverlaine : public CreatureScript
{
public:
boss_baron_silverlaine() : CreatureScript("boss_baron_silverlaine") { }
struct boss_baron_silverlaineAI : public BossAI
{
boss_baron_silverlaineAI(Creature* creature) : BossAI(creature, DATA_BARON_SILVERLAINE) { }
void Reset() override
{
_Reset();
_worgenCounter = 0;
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_EnterCombat();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
if (IsHeroic())
events.ScheduleEvent(EVENT_CURSED_VEIL, Seconds(6));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
DespawnWorgenSpirits();
_JustDied();
}
void KilledUnit(Unit* target) override
{
if (target->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_EnterEvadeMode();
summons.DespawnAll();
instance->SetBossState(DATA_BARON_SILVERLAINE, FAIL);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
DespawnWorgenSpirits();
_DespawnAtEvade();
}
void DespawnWorgenSpirits()
{
EntryCheckPredicate nandos(NPC_WOLF_MASTER_NANDOS);
summons.DoAction(ACTION_DESPAWN, nandos);
EntryCheckPredicate odo(NPC_ODO_THE_BLINDWATCHER);
summons.DoAction(ACTION_DESPAWN, odo);
EntryCheckPredicate razorclaw(NPC_RAZORCLAW_THE_BUTCHER);
summons.DoAction(ACTION_DESPAWN, razorclaw);
EntryCheckPredicate rethilgore(NPC_RETHILGORE);
summons.DoAction(ACTION_DESPAWN, rethilgore);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_ODO_DUMMY:
summon->CastSpell(summon, SPELL_SUMMON_WORGEN_SPIRIT_ODO_SUMMON);
break;
case NPC_NANDOS_DUMMY:
summon->CastSpell(summon, SPELL_SUMMON_WORGEN_SPIRIT_NANDOS_SUMMON);
break;
case NPC_RAZORCLAW_DUMMY:
summon->CastSpell(summon, SPELL_SUMMON_WORGEN_SPIRIT_RAZORCLAW_SUMMON);
break;
case NPC_RETHILGORE_DUMMY:
summon->CastSpell(summon, SPELL_SUMMON_WORGEN_SPIRIT_RETHILGORE_SUMMON);
break;
default:
break;
}
}
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override
{
switch (IsHeroic())
{
case true:
{
if (me->HealthBelowPct(90) && _worgenCounter == 0)
{
events.ScheduleEvent(EVENT_SUMMON_WORGEN_SPIRIT, (Milliseconds(1)));
_worgenCounter++;
}
else if (me->HealthBelowPct(60) && _worgenCounter == 1)
{
events.ScheduleEvent(EVENT_SUMMON_WORGEN_SPIRIT, (Milliseconds(1)));
_worgenCounter++;
}
else if (me->HealthBelowPct(30) && _worgenCounter == 2)
{
events.ScheduleEvent(EVENT_SUMMON_WORGEN_SPIRIT, (Milliseconds(1)));
_worgenCounter++;
}
break;
}
case false:
{
if (me->HealthBelowPct(75) && _worgenCounter == 0)
{
events.ScheduleEvent(EVENT_SUMMON_WORGEN_SPIRIT, (Milliseconds(1)));
_worgenCounter++;
}
else if (me->HealthBelowPct(35) && _worgenCounter == 1)
{
events.ScheduleEvent(EVENT_SUMMON_WORGEN_SPIRIT, (Milliseconds(1)));
_worgenCounter++;
}
break;
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while(uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CURSED_VEIL:
DoCastAOE(SPELL_CURSED_VEIL);
events.Repeat(Seconds(26) + Milliseconds(500));
break;
case EVENT_SUMMON_WORGEN_SPIRIT:
DoCastAOE(SPELL_SUMMON_WORGEN_SPIRIT);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 _worgenCounter;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<boss_baron_silverlaineAI>(creature);
}
};
class npc_wolf_master_nandos : public CreatureScript
{
public:
npc_wolf_master_nandos() : CreatureScript("npc_wolf_master_nandos") { }
struct npc_wolf_master_nandosAI : public ScriptedAI
{
npc_wolf_master_nandosAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
if (Creature* silverlaine = _instance->GetCreature(DATA_BARON_SILVERLAINE))
silverlaine->AI()->JustSummoned(me);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
DoZoneInCombat();
events.ScheduleEvent(EVENT_CLAW, Seconds(1) + Milliseconds(600));
for (uint8 i = 0; i < 3; i++);
DoCast(me, SPELL_SUMMON_LUPINE_SPECTRE, true);
}
void JustDied(Unit* /*killer*/) override
{
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Seconds(5));
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DESPAWN:
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Milliseconds(1));
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CLAW:
DoCastVictim(SPELL_CLAW);
events.Repeat(Seconds(3));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_wolf_master_nandosAI>(creature);
}
};
class npc_odo_the_blindwatcher : public CreatureScript
{
public:
npc_odo_the_blindwatcher() : CreatureScript("npc_odo_the_blindwatcher") { }
struct npc_odo_the_blindwatcherAI : public ScriptedAI
{
npc_odo_the_blindwatcherAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
if (Creature* silverlaine = _instance->GetCreature(DATA_BARON_SILVERLAINE))
silverlaine->AI()->JustSummoned(me);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_HOWLING_RAGE, Seconds(5) + Milliseconds(500));
}
void JustDied(Unit* /*killer*/) override
{
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Seconds(5));
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DESPAWN:
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Milliseconds(1));
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_HOWLING_RAGE:
DoCastVictim(SPELL_BLINDING_SHADOWS);
DoCastAOE(SPELL_HOWLING_RAGE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_odo_the_blindwatcherAI>(creature);
}
};
class npc_razorclaw_the_butcher : public CreatureScript
{
public:
npc_razorclaw_the_butcher() : CreatureScript("npc_razorclaw_the_butcher") { }
struct npc_razorclaw_the_butcherAI : public ScriptedAI
{
npc_razorclaw_the_butcherAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
_player = ObjectGuid::Empty;
if (Creature* silverlaine = _instance->GetCreature(DATA_BARON_SILVERLAINE))
silverlaine->AI()->JustSummoned(me);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_SPECTRAL_RUSH, Seconds(16));
_events.ScheduleEvent(EVENT_BUTCHER_DRAIN, Seconds(2) + Milliseconds(500));
}
void JustDied(Unit* /*killer*/) override
{
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Seconds(5));
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DESPAWN:
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Milliseconds(1));
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPECTRAL_RUSH:
if (Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 0.0f, true))
{
_events.ScheduleEvent(EVENT_SPECTRAL_RAVAGING, Milliseconds(500));
DoCast(target, SPELL_SPECTRAL_RUSH);
_player = target->GetGUID();
}
break;
case EVENT_SPECTRAL_RAVAGING:
if (Unit* target = ObjectAccessor::GetPlayer(*me, _player))
DoCast(target, SPELL_SPECTRAL_RAVAGING);
break;
case EVENT_BUTCHER_DRAIN:
DoCastVictim(SPELL_BUTCHER_DRAIN);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
ObjectGuid _player;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_razorclaw_the_butcherAI>(creature);
}
};
class npc_rethilgore : public CreatureScript
{
public:
npc_rethilgore() : CreatureScript("npc_rethilgore") { }
struct npc_rethilgoreAI : public ScriptedAI
{
npc_rethilgoreAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
if (Creature* silverlaine = _instance->GetCreature(DATA_BARON_SILVERLAINE))
silverlaine->AI()->JustSummoned(me);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_SOUL_DRAIN, Seconds(10));
}
void JustDied(Unit* /*killer*/) override
{
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Seconds(5));
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DESPAWN:
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->DespawnOrUnsummon(Milliseconds(1));
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SOUL_DRAIN:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_SOUL_DRAIN);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const
{
return GetShadowfangKeepAI<npc_rethilgoreAI>(creature);
}
};
class spell_sfk_summon_worgen_spirit : public SpellScriptLoader
{
public:
spell_sfk_summon_worgen_spirit() : SpellScriptLoader("spell_sfk_summon_worgen_spirit") { }
class spell_sfk_summon_worgen_spirit_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_summon_worgen_spirit_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_SUMMON_WORGEN_SPIRIT_NANDOS_DUMMY,
SPELL_SUMMON_WORGEN_SPIRIT_ODO_DUMMY,
SPELL_SUMMON_WORGEN_SPIRIT_RAZORCLAW_DUMMY,
SPELL_SUMMON_WORGEN_SPIRIT_RETHILGORE_DUMMY
});
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
switch (RAND(0, 3))
{
case 0: // Nandos
caster->CastSpell((Unit*)NULL, SPELL_SUMMON_WORGEN_SPIRIT_NANDOS_DUMMY, true);
break;
case 1: // Odo
caster->CastSpell((Unit*)NULL, SPELL_SUMMON_WORGEN_SPIRIT_ODO_DUMMY, true);
break;
case 2: // Razorclaw
caster->CastSpell((Unit*)NULL, SPELL_SUMMON_WORGEN_SPIRIT_RAZORCLAW_DUMMY, true);
break;
case 3: // Rethilgore
caster->CastSpell((Unit*)NULL, SPELL_SUMMON_WORGEN_SPIRIT_RETHILGORE_DUMMY, true);
break;
}
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_sfk_summon_worgen_spirit_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_summon_worgen_spirit_SpellScript();
}
};
void AddSC_boss_baron_silverlaine()
{
new boss_baron_silverlaine();
new npc_wolf_master_nandos();
new npc_odo_the_blindwatcher();
new npc_razorclaw_the_butcher();
new npc_rethilgore();
new spell_sfk_summon_worgen_spirit();
}

View File

@@ -0,0 +1,583 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "shadowfang_keep.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Player.h"
enum Spells
{
// Commander Springvale
SPELL_MALEFIC_STRIKE = 93685,
SPELL_UNHOLY_POWER = 93686,
SPELL_UNHOLY_POWER_HC = 93735,
SPELL_SHIELD_OF_THE_PERFIDIOUS_DUMMY = 93716,
SPELL_SHIELD_OF_THE_PERFIDIOUS = 93693,
SPELL_DESECRATION_DUMMY = 93688,
SPELL_DESECRATION = 93687,
SPELL_DESECRATION_ARM_AURA = 67803,
SPELL_WORD_OF_SHAME = 93852,
// Wailing Guardsman
SPELL_UNHOLY_EMPOWERMENT = 93844,
SPELL_SCREAMS_OF_THE_PAST = 7074,
SPELL_MORTAL_STRIKE = 91801,
//Tormented Officer
SPELL_FORSAKEN_ABILITY = 7054,
SPELL_FORSAKEN_ABILITY_DAMAGE = 7038,
SPELL_FORSAKEN_ABILITY_ARMOR = 7039,
SPELL_FORSAKEN_ABILITY_HEAL = 7041,
SPELL_FORSAKEN_ABILITY_SPEED = 7042,
SPELL_FORSAKEN_ABILITY_HEALTH = 7040,
SPELL_SHIELD_WALL = 91463
};
enum Texts
{
SAY_AGGRO = 0,
SAY_ADDS = 1,
SAY_SLAY = 2,
SAY_DEATH = 3
};
enum Events
{
// Commander Springvale
EVENT_MALEFIC_STRIKE = 1,
EVENT_SHIELD_OF_THE_PERFIDIOUS,
EVENT_DESECRATION,
EVENT_SUMMON_ADDS,
EVENT_WORD_OF_SHAME,
// Wailing Guardsman
EVENT_UNHOLY_EMPOWERMENT,
EVENT_SCREAMS_OF_THE_PAST,
EVENT_MORTAL_STRIKE,
// Tormented Officer
EVENT_FORSAKEN_ABILITY
};
enum Actions
{
ACTION_UNHOLY_POWER = 1,
ACTION_TO_THE_GROUND
};
enum AchievementData
{
DATA_TO_THE_GROUND = 1
};
// Heroic additional adds
Position const OfficerPos = {-229.681f, 2260.03f, 102.84f, 3.45575f};
Position const GuardsmanPos = {-228.33f, 2254.39f, 102.84f, 3.36848f};
// Encounter spawn positions
Position const SpawnPos[] =
{
{-235.5069f, 2230.76f, 93.70721f, 0.0f}, // Wailing Guardsman
{-266.2257f, 2270.207f, 96.51828f, 0.0f} // Tormented Officer
};
class boss_commander_springvale : public CreatureScript
{
public:
boss_commander_springvale() : CreatureScript("boss_commander_springvale") { }
struct boss_commander_springvaleAI : public BossAI
{
boss_commander_springvaleAI(Creature* creature) : BossAI(creature, DATA_COMMANDER_SPRINGVALE) { }
void Reset() override
{
_Reset();
_toTheGround = true;
if (IsHeroic())
{
DoSummon(NPC_WAILING_GUARDSMAN, GuardsmanPos, 4000, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
DoSummon(NPC_TORMENTED_OFFICER, OfficerPos, 4000, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
}
/*
else
{
// Fill this case with the path that Commander Springvale is walking in normal mode
}
*/
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_EnterCombat();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
events.ScheduleEvent(EVENT_MALEFIC_STRIKE, Seconds(5));
events.ScheduleEvent(EVENT_DESECRATION, Seconds(9) + Milliseconds(500));
if (IsHeroic())
events.ScheduleEvent(EVENT_SUMMON_ADDS, Seconds(41));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WORD_OF_SHAME);
}
void KilledUnit(Unit* target) override
{
if (target->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_EnterEvadeMode();
summons.DespawnAll();
instance->SetBossState(DATA_COMMANDER_SPRINGVALE, FAIL);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WORD_OF_SHAME);
_DespawnAtEvade();
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_TORMENTED_OFFICER:
case NPC_WAILING_GUARDSMAN:
if (me->IsInCombat())
summon->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true);
break;
case NPC_SHIELD_FOCUS:
me->StopMoving();
me->SetFacingToObject(summon);
DoCast(summon, SPELL_SHIELD_OF_THE_PERFIDIOUS);
default:
break;
}
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_TO_THE_GROUND:
return _toTheGround;
default:
break;
}
return 0;
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_UNHOLY_POWER:
if (IsHeroic())
{
switch (RAND(0, 1))
{
case 0:
events.ScheduleEvent(EVENT_SHIELD_OF_THE_PERFIDIOUS, Seconds(1));
break;
case 1:
events.ScheduleEvent(EVENT_WORD_OF_SHAME, Seconds(1));
break;
default:
break;
}
}
else
events.ScheduleEvent(EVENT_SHIELD_OF_THE_PERFIDIOUS, Seconds(1));
break;
case ACTION_TO_THE_GROUND:
_toTheGround = false;
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while(uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MALEFIC_STRIKE:
if (!me->HasAura(SPELL_SHIELD_OF_THE_PERFIDIOUS))
DoCastVictim(SPELL_MALEFIC_STRIKE);
events.Repeat(Seconds(5), Seconds(6));
break;
case EVENT_SHIELD_OF_THE_PERFIDIOUS:
me->RemoveAurasDueToSpell(SPELL_UNHOLY_POWER);
me->RemoveAurasDueToSpell(SPELL_UNHOLY_POWER_HC);
DoCast(SPELL_SHIELD_OF_THE_PERFIDIOUS_DUMMY);
break;
case EVENT_DESECRATION:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_DESECRATION);
events.Repeat(Seconds(28));
break;
case EVENT_SUMMON_ADDS:
Talk(SAY_ADDS);
DoSummon(NPC_WAILING_GUARDSMAN, SpawnPos[0], 4000, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
DoSummon(NPC_TORMENTED_OFFICER, SpawnPos[1], 4000, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
events.Repeat(Seconds(41));
break;
case EVENT_WORD_OF_SHAME:
me->RemoveAurasDueToSpell(SPELL_UNHOLY_POWER);
me->RemoveAurasDueToSpell(SPELL_UNHOLY_POWER_HC);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_WORD_OF_SHAME))
DoCast(target, SPELL_WORD_OF_SHAME, true);
else
events.ScheduleEvent(EVENT_SHIELD_OF_THE_PERFIDIOUS, Milliseconds(1));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _toTheGround;
};
CreatureAI* GetAI(Creature *creature) const override
{
return GetShadowfangKeepAI<boss_commander_springvaleAI>(creature);
}
};
class npc_wailing_guardsman : public CreatureScript
{
public:
npc_wailing_guardsman() : CreatureScript("npc_wailing_guardsman") { }
struct npc_wailing_guardsmanAI : public ScriptedAI
{
npc_wailing_guardsmanAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void EnterCombat(Unit* who) override
{
if (Creature* tormentedOfficer = me->FindNearestCreature(NPC_TORMENTED_OFFICER, 20.0f))
tormentedOfficer->AI()->AttackStart(who);
_events.ScheduleEvent(EVENT_MORTAL_STRIKE, Seconds(11));
_events.ScheduleEvent(EVENT_SCREAMS_OF_THE_PAST, Seconds(14));
_events.ScheduleEvent(EVENT_UNHOLY_EMPOWERMENT, Seconds(28), Seconds(30));
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTAL_STRIKE);
_events.Repeat(Seconds(12));
break;
case EVENT_SCREAMS_OF_THE_PAST:
DoCastAOE(SPELL_SCREAMS_OF_THE_PAST);
break;
case EVENT_UNHOLY_EMPOWERMENT:
if (Creature* springvale = _instance->GetCreature(DATA_COMMANDER_SPRINGVALE))
DoCast(springvale, SPELL_UNHOLY_EMPOWERMENT);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_wailing_guardsmanAI>(creature);
}
};
class npc_tormented_officer : public CreatureScript
{
public:
npc_tormented_officer() : CreatureScript("npc_tormented_officer") { }
struct npc_tormented_officerAI : public ScriptedAI
{
npc_tormented_officerAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void EnterCombat(Unit* who) override
{
if (Creature* wailingGuardsman = me->FindNearestCreature(NPC_WAILING_GUARDSMAN, 20.0f))
wailingGuardsman->AI()->AttackStart(who);
_shielded = false;
_events.ScheduleEvent(EVENT_UNHOLY_EMPOWERMENT, Seconds(28), Seconds(30));
_events.ScheduleEvent(EVENT_FORSAKEN_ABILITY, Seconds(17));
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (me->HealthBelowPct(20) && !_shielded)
{
DoCast(me, SPELL_SHIELD_WALL);
_shielded = true;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FORSAKEN_ABILITY:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_FORSAKEN_ABILITY);
break;
case EVENT_UNHOLY_EMPOWERMENT:
if (Creature* springvale = _instance->GetCreature(DATA_COMMANDER_SPRINGVALE))
DoCast(springvale, SPELL_UNHOLY_EMPOWERMENT);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
bool _shielded;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_tormented_officerAI>(creature);
}
};
class spell_sfk_forsaken_ability : public SpellScriptLoader
{
public:
spell_sfk_forsaken_ability() : SpellScriptLoader("spell_sfk_forsaken_ability") { }
class spell_sfk_forsaken_ability_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_forsaken_ability_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_FORSAKEN_ABILITY_DAMAGE,
SPELL_FORSAKEN_ABILITY_ARMOR,
SPELL_FORSAKEN_ABILITY_SPEED,
SPELL_FORSAKEN_ABILITY_HEAL,
SPELL_FORSAKEN_ABILITY_HEALTH
});
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
if (Unit* owner = GetOwner()->ToUnit())
{
switch (RAND(0, 4))
{
case 0: // Damage
owner->CastSpell(owner, SPELL_FORSAKEN_ABILITY_DAMAGE, true);
break;
case 1: // Armor
owner->CastSpell(owner, SPELL_FORSAKEN_ABILITY_ARMOR, true);
break;
case 2: // Speed
owner->CastSpell(owner, SPELL_FORSAKEN_ABILITY_SPEED, true);
break;
case 3: // Heal
owner->CastSpell(owner, SPELL_FORSAKEN_ABILITY_HEAL, true);
break;
case 4: // Health
owner->CastSpell(owner, SPELL_FORSAKEN_ABILITY_HEALTH, true);
break;
}
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_forsaken_ability_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sfk_forsaken_ability_AuraScript();
}
};
class spell_sfk_unholy_power : public SpellScriptLoader
{
public:
spell_sfk_unholy_power() : SpellScriptLoader("spell_sfk_unholy_power") { }
class spell_sfk_unholy_power_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_unholy_power_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_UNHOLY_POWER_HC,
SPELL_UNHOLY_POWER
});
}
void HandleStacks()
{
if (Unit* target = GetHitUnit())
{
Aura* aura = nullptr;
aura = target->GetAura(SPELL_UNHOLY_POWER_HC);
if (!aura)
target->GetAura(SPELL_UNHOLY_POWER);
if (aura)
if (aura->GetStackAmount() == 3)
if (target->GetTypeId() == TYPEID_UNIT && target->IsAIEnabled)
target->ToCreature()->AI()->DoAction(ACTION_UNHOLY_POWER);
}
}
void Register() override
{
AfterHit += SpellHitFn(spell_sfk_unholy_power_SpellScript::HandleStacks);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_unholy_power_SpellScript();
}
};
class spell_sfk_unholy_empowerment : public SpellScriptLoader
{
public:
spell_sfk_unholy_empowerment() : SpellScriptLoader("spell_sfk_unholy_empowerment") { }
class spell_sfk_unholy_empowerment_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_unholy_empowerment_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_UNHOLY_POWER_HC,
SPELL_UNHOLY_POWER
});
return true;
}
void HandleStacks()
{
if (Unit* target = GetHitUnit())
{
Aura* aura = nullptr;
aura = target->GetAura(SPELL_UNHOLY_POWER_HC);
if (!aura)
target->GetAura(SPELL_UNHOLY_POWER);
if (aura)
if (aura->GetStackAmount() == 3)
if (target->GetTypeId() == TYPEID_UNIT && target->IsAIEnabled)
target->ToCreature()->AI()->DoAction(ACTION_UNHOLY_POWER);
if (target->GetTypeId() == TYPEID_UNIT && target->IsAIEnabled)
target->ToCreature()->AI()->DoAction(ACTION_TO_THE_GROUND);
}
}
void Register() override
{
AfterHit += SpellHitFn(spell_sfk_unholy_empowerment_SpellScript::HandleStacks);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_unholy_empowerment_SpellScript();
}
};
class achievement_to_the_ground : public AchievementCriteriaScript
{
public:
achievement_to_the_ground() : AchievementCriteriaScript("achievement_to_the_ground") { }
bool OnCheck(Player* /*source*/, Unit* target)
{
if (!target)
return false;
if (target->GetMap()->IsHeroic())
return target->GetAI()->GetData(DATA_TO_THE_GROUND);
return false;
}
};
void AddSC_boss_commander_springvale()
{
new boss_commander_springvale();
new npc_wailing_guardsman();
new npc_tormented_officer();
new spell_sfk_forsaken_ability();
new spell_sfk_unholy_power();
new spell_sfk_unholy_empowerment();
new achievement_to_the_ground();
}

View File

@@ -0,0 +1,485 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "shadowfang_keep.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Player.h"
enum Texts
{
SAY_AGGRO_ALLIANCE = 0,
SAY_AGGRO_HORDE = 1,
SAY_SLAY = 2,
SAY_ANNOUNCE_PISTOL_BARRAGE = 3,
SAY_DEATH = 4
};
enum Events
{
// Lord Godfrey
EVENT_CURSED_BULLETS = 1,
EVENT_MORTAL_WOUND,
EVENT_SUMMON_BLOODTHIRSTY_GHOULS,
EVENT_PISTOL_BARRAGE,
EVENT_PISTOL_BARRAGE_CAST,
EVENT_APPLY_IMMUNITY,
// Bloodthirsty Ghoul
EVENT_ATTACK
};
enum Spells
{
SPELL_CURSED_BULLETS = 93629,
SPELL_CURSED_BULLETS_HC = 93761,
SPELL_MORTAL_WOUND = 93675,
SPELL_SUMMON_BLOODTHIRSTY_GHOULS_AURA = 93707,
SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_1 = 93709,
SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_2 = 93714,
SPELL_PISTOL_BARRAGE_FORCE_CAST = 96344,
SPELL_PISTOL_BARRAGE_CAST = 93520,
SPELL_BULLET_TIME_CREDIT = 95929,
SPELL_PISTOL_BARRAGE_TRIGGER_1 = 93566,
SPELL_PISTOL_BARRAGE_TRIGGER_2 = 93558
};
enum AchievementData
{
DATA_BULLET_TIME = 1,
};
class boss_lord_godfrey : public CreatureScript
{
public:
boss_lord_godfrey() : CreatureScript("boss_lord_godfrey") { }
struct boss_lord_godfreyAI : public BossAI
{
boss_lord_godfreyAI(Creature* creature) : BossAI(creature, DATA_LORD_GODFREY)
{
}
void Reset() override
{
_Reset();
_killedGhoulCounter = 0;
MakeInterruptable(false);
}
void EnterCombat(Unit* /*who*/) override
{
if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
Talk(SAY_AGGRO_ALLIANCE);
else
Talk(SAY_AGGRO_HORDE);
_EnterCombat();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
events.ScheduleEvent(EVENT_CURSED_BULLETS, Seconds(10) + Milliseconds(800));
events.ScheduleEvent(EVENT_MORTAL_WOUND, Seconds(3) + Milliseconds(500));
events.ScheduleEvent(EVENT_SUMMON_BLOODTHIRSTY_GHOULS, Seconds(6));
if (IsHeroic())
events.ScheduleEvent(EVENT_PISTOL_BARRAGE, Seconds(12) + Milliseconds(500));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_JustDied();
}
void SummonedCreatureDies(Creature* summon, Unit* killer) override
{
switch (summon->GetEntry())
{
case NPC_BLOODTHIRSTY_GHOUL:
if (killer->GetEntry() == BOSS_LORD_GODFREY && IsHeroic())
{
DoCastAOE(SPELL_BULLET_TIME_CREDIT, true);
_killedGhoulCounter++;
}
break;
default:
break;
}
}
void KilledUnit(Unit* target) override
{
if (target->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_EnterEvadeMode();
summons.DespawnAll();
me->SetReactState(REACT_AGGRESSIVE);
instance->SetBossState(DATA_LORD_GODFREY, FAIL);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_DespawnAtEvade();
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_BULLET_TIME:
return _killedGhoulCounter;;
default:
break;
}
return 0;
}
void MakeInterruptable(bool apply)
{
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, !apply);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, !apply);
}
void OnSpellCastInterrupt(SpellInfo const* spell) override
{
switch (spell->Id)
{
case SPELL_CURSED_BULLETS:
case SPELL_CURSED_BULLETS_HC:
events.CancelEvent(EVENT_APPLY_IMMUNITY);
MakeInterruptable(false);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CURSED_BULLETS:
MakeInterruptable(true);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_CURSED_BULLETS);
events.ScheduleEvent(EVENT_CURSED_BULLETS, Seconds(12));
events.ScheduleEvent(EVENT_APPLY_IMMUNITY, Seconds(1) + Milliseconds(500));
break;
case EVENT_MORTAL_WOUND:
DoCastVictim(SPELL_MORTAL_WOUND);
events.Repeat(Seconds(6));
break;
case EVENT_SUMMON_BLOODTHIRSTY_GHOULS:
DoCastAOE(SPELL_SUMMON_BLOODTHIRSTY_GHOULS_AURA, true);
events.Repeat(Seconds(30));
break;
case EVENT_PISTOL_BARRAGE:
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
DoCastAOE(SPELL_PISTOL_BARRAGE_FORCE_CAST);
events.ScheduleEvent(EVENT_PISTOL_BARRAGE_CAST, Milliseconds(500));
break;
case EVENT_PISTOL_BARRAGE_CAST:
if (Creature* target = me->FindNearestCreature(NPC_PISTOL_BARRAGE_DUMMY, 500.0f, true))
{
Talk(SAY_ANNOUNCE_PISTOL_BARRAGE);
me->SetFacingToObject(target);
DoCastAOE(SPELL_PISTOL_BARRAGE_CAST);
}
events.ScheduleEvent(EVENT_PISTOL_BARRAGE, Seconds(30) + Milliseconds(100));
break;
case EVENT_APPLY_IMMUNITY:
MakeInterruptable(false);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 _killedGhoulCounter;
};
CreatureAI* GetAI(Creature *creature) const override
{
return GetShadowfangKeepAI<boss_lord_godfreyAI>(creature);
}
};
class npc_sfk_bloodthirsty_ghoul : public CreatureScript
{
public:
npc_sfk_bloodthirsty_ghoul() : CreatureScript("npc_sfk_bloodthirsty_ghoul") { }
struct npc_sfk_bloodthirsty_ghoulAI : public ScriptedAI
{
npc_sfk_bloodthirsty_ghoulAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void IsSummonedBy(Unit* summoner) override
{
if (!summoner->IsInCombat())
me->DespawnOrUnsummon();
me->SetReactState(REACT_PASSIVE);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_ATTACK, Seconds(4));
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(Seconds(5));
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
if (Unit* target = me->SelectNearestPlayer(100.0f))
me->AI()->AttackStart(target);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* _instance;
EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_sfk_bloodthirsty_ghoulAI>(creature);
}
};
class spell_sfk_summon_bloodthirsty_ghouls : public SpellScriptLoader
{
public:
spell_sfk_summon_bloodthirsty_ghouls() : SpellScriptLoader("spell_sfk_summon_bloodthirsty_ghouls") { }
class spell_sfk_summon_bloodthirsty_ghouls_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_summon_bloodthirsty_ghouls_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_1,
SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_2
});
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
switch (RAND(0, 1))
{
case 0:
GetCaster()->CastSpell((Unit*)NULL, SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_1, true);
break;
case 1:
GetCaster()->CastSpell((Unit*)NULL, SPELL_SUMMON_BLOODTHIRSTY_GHOULS_TRIGGERED_2, true);
break;
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_summon_bloodthirsty_ghouls_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
AuraScript* GetAuraScript() const
{
return new spell_sfk_summon_bloodthirsty_ghouls_AuraScript();
}
};
class spell_sfk_pistol_barrage : public SpellScriptLoader
{
public:
spell_sfk_pistol_barrage() : SpellScriptLoader("spell_sfk_pistol_barrage") { }
class spell_sfk_pistol_barrage_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_pistol_barrage_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PISTOL_BARRAGE_TRIGGER_1,
SPELL_PISTOL_BARRAGE_TRIGGER_2
});
}
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
caster->CastSpell(caster, SPELL_PISTOL_BARRAGE_TRIGGER_1, true);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
{
if (caster->ToCreature())
caster->ToCreature()->SetReactState(REACT_AGGRESSIVE);
caster->RemoveAurasDueToSpell(SPELL_PISTOL_BARRAGE_TRIGGER_1);
}
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
if (Unit* caster = GetCaster())
{
float ori = caster->GetOrientation() + frand(-0.5236f, 0.5236f);
float posX = caster->GetPositionX() + cos(ori) * 60;
float posY = caster->GetPositionY() + sin(ori) * 60;
float posZ = caster->GetPositionZ();
GetCaster()->CastSpell(posX, posY, posZ, SPELL_PISTOL_BARRAGE_TRIGGER_2, true);
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_sfk_pistol_barrage_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_sfk_pistol_barrage_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_pistol_barrage_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const
{
return new spell_sfk_pistol_barrage_AuraScript();
}
};
class spell_sfk_pistol_barrage_summon : public SpellScriptLoader
{
public:
spell_sfk_pistol_barrage_summon() : SpellScriptLoader("spell_sfk_pistol_barrage_summon") { }
class spell_sfk_pistol_barrage_summon_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_pistol_barrage_summon_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
Trinity::Containers::RandomResize(targets, 1);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sfk_pistol_barrage_summon_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_pistol_barrage_summon_SpellScript();
}
};
class spell_sfk_cursed_bullets : public SpellScriptLoader
{
public:
spell_sfk_cursed_bullets() : SpellScriptLoader("spell_sfk_cursed_bullets") { }
class spell_sfk_cursed_bullets_AuraScript : public AuraScript
{
PrepareAuraScript(spell_sfk_cursed_bullets_AuraScript);
void OnPeriodic(AuraEffect const* aurEff)
{
uint64 damage;
damage = aurEff->GetBaseAmount() * aurEff->GetTickNumber();
GetEffect(EFFECT_1)->ChangeAmount(damage);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sfk_cursed_bullets_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sfk_cursed_bullets_AuraScript();
}
};
class achievement_bullet_time : public AchievementCriteriaScript
{
public:
achievement_bullet_time() : AchievementCriteriaScript("achievement_bullet_time") { }
bool OnCheck(Player* /*source*/, Unit* target)
{
if (!target)
return false;
if (target->GetMap()->IsHeroic())
return target->GetAI()->GetData(DATA_BULLET_TIME) >= 12;
return false;
}
};
void AddSC_boss_lord_godfrey()
{
new boss_lord_godfrey();
new npc_sfk_bloodthirsty_ghoul();
new spell_sfk_summon_bloodthirsty_ghouls();
new spell_sfk_pistol_barrage();
new spell_sfk_pistol_barrage_summon();
new spell_sfk_cursed_bullets();
new achievement_bullet_time();
}

View File

@@ -0,0 +1,257 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "shadowfang_keep.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Player.h"
enum Texts
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2
};
enum Spells
{
// Lord Walden
SPELL_ICE_SHARDS = 93527,
SPELL_CONJURE_FROST_MIXTURE = 93505,
SPELL_CONJURE_POISONOUS_MIXTURE = 93697,
SPELL_CONJURE_MYSTERY_MIXTURE = 93695,
SPELL_CONJURE_MYSTERY_MIXTURE_CHANNEL = 93562,
SPELL_FULLY_COAGULATED = 93660,
// Mystery Toxine
SPELL_TOXIC_COAGULANT = 93572,
SPELL_TOXIC_COAGULANT_SLOW = 93617,
SPELL_TOXIC_CATALYST = 93573,
SPELL_TOXIC_CATALYST_AURA = 93689
};
enum Events
{
EVENT_ICE_SHARDS = 1,
EVENT_CONJURE_FROST_MIXTURE,
EVENT_CONJURE_POISONOUS_MIXTURE,
EVENT_CONJURE_MYSTERY_TOXINE,
EVENT_ADD_CATALYST
};
class boss_lord_walden : public CreatureScript
{
public:
boss_lord_walden() : CreatureScript("boss_lord_walden") { }
struct boss_lord_waldenAI : public BossAI
{
boss_lord_waldenAI(Creature* creature) : BossAI(creature, DATA_LORD_WALDEN) { }
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_EnterCombat();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
events.ScheduleEvent(EVENT_ICE_SHARDS, Seconds(23));
events.ScheduleEvent(EVENT_CONJURE_FROST_MIXTURE, Seconds(8));
events.ScheduleEvent(EVENT_CONJURE_POISONOUS_MIXTURE, Seconds(21));
if (IsHeroic())
events.ScheduleEvent(EVENT_CONJURE_MYSTERY_TOXINE, Seconds(10) + Milliseconds(500));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void KilledUnit(Unit* target) override
{
if (target->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_EnterEvadeMode();
summons.DespawnAll();
instance->SetBossState(DATA_LORD_WALDEN, FAIL);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_DespawnAtEvade();
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_MYSTERY_MIXTURE:
if (!me->HealthBelowPct(35))
summon->CastSpell((Unit*)NULL, SPELL_TOXIC_COAGULANT, true);
else
{
summon->CastSpell((Unit*)NULL, SPELL_TOXIC_CATALYST, true);
events.ScheduleEvent(EVENT_ADD_CATALYST, Seconds(2));
}
// Since summon above caster is not implemented yet
summon->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4.5f, me->GetOrientation());
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while(uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ICE_SHARDS:
me->StopMoving();
DoCastAOE(SPELL_ICE_SHARDS);
events.Repeat(Seconds(21) + Milliseconds(500));
break;
case EVENT_CONJURE_FROST_MIXTURE:
me->StopMoving();
DoCastAOE(SPELL_CONJURE_FROST_MIXTURE);
events.Repeat(Seconds(21) + Milliseconds(500));
break;
case EVENT_CONJURE_POISONOUS_MIXTURE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_CONJURE_POISONOUS_MIXTURE);
events.Repeat(Seconds(21) + Milliseconds(500));
break;
case EVENT_CONJURE_MYSTERY_TOXINE:
DoCast(SPELL_CONJURE_MYSTERY_MIXTURE);
DoCast(SPELL_CONJURE_MYSTERY_MIXTURE_CHANNEL);
events.Repeat(Seconds(21) + Milliseconds(500));
break;
case EVENT_ADD_CATALYST:
if (Unit* mixture = me->FindNearestCreature(NPC_MYSTERY_MIXTURE, 20.0f, true))
mixture->CastSpell(mixture, SPELL_TOXIC_CATALYST_AURA, false);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature *creature) const override
{
return GetShadowfangKeepAI<boss_lord_waldenAI>(creature);
}
};
class spell_sfk_toxic_coagulant : public SpellScriptLoader
{
public:
spell_sfk_toxic_coagulant() : SpellScriptLoader("spell_sfk_toxic_coagulant") { }
class spell_sfk_toxic_coagulant_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_toxic_coagulant_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_FULLY_COAGULATED,
SPELL_TOXIC_COAGULANT_SLOW
});
}
void HandleStacks()
{
if (Unit* target = GetHitUnit())
{
Aura* aura = nullptr;
aura = target->GetAura(SPELL_TOXIC_COAGULANT_SLOW);
if (aura)
{
if (aura->GetStackAmount() == 3)
{
target->RemoveAurasDueToSpell(SPELL_TOXIC_COAGULANT_SLOW);
target->CastSpell(target, SPELL_FULLY_COAGULATED, true);
}
}
}
}
void Register() override
{
AfterHit += SpellHitFn(spell_sfk_toxic_coagulant_SpellScript::HandleStacks);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_toxic_coagulant_SpellScript();
}
};
class spell_sfk_conjure_poisonous_mixture : public SpellScriptLoader
{
public:
spell_sfk_conjure_poisonous_mixture() : SpellScriptLoader("spell_sfk_conjure_poisonous_mixture") { }
class spell_sfk_conjure_poisonous_mixture_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sfk_conjure_poisonous_mixture_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
Trinity::Containers::RandomResize(targets, 1);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sfk_conjure_poisonous_mixture_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sfk_conjure_poisonous_mixture_SpellScript();
}
};
void AddSC_boss_lord_walden()
{
new boss_lord_walden();
new spell_sfk_toxic_coagulant();
new spell_sfk_conjure_poisonous_mixture();
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* 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
@@ -16,269 +15,119 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Instance_Shadowfang_Keep
SD%Complete: 90
SDComment:
SDCategory: Shadowfang Keep
EndScriptData */
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "shadowfang_keep.h"
#include "TemporarySummon.h"
#include "Player.h"
#define MAX_ENCOUNTER 4
enum Yells
ObjectData const creatureData[] =
{
SAY_BOSS_DIE_AD = 4,
SAY_BOSS_DIE_AS = 3,
SAY_ARCHMAGE = 0
{ BOSS_BARON_ASHBURY, DATA_BARON_ASHBURY },
{ BOSS_BARON_SILVERLAINE, DATA_BARON_SILVERLAINE },
{ BOSS_COMMANDER_SPRINGVALE, DATA_COMMANDER_SPRINGVALE },
{ BOSS_LORD_WALDEN, DATA_LORD_WALDEN },
{ BOSS_LORD_GODFREY, DATA_LORD_GODFREY },
};
enum Creatures
DoorData const doorData[] =
{
NPC_ASH = 3850,
NPC_ADA = 3849,
NPC_ARCHMAGE_ARUGAL = 4275,
NPC_ARUGAL_VOIDWALKER = 4627
{ GO_ARUGAL_DOOR, DATA_LORD_GODFREY, DOOR_TYPE_ROOM },
{ 0, 0, DOOR_TYPE_ROOM }, // END
};
enum GameObjects
BossBoundaryData const boundaries =
{
GO_COURTYARD_DOOR = 18895, //door to open when talking to NPC's
GO_SORCERER_DOOR = 18972, //door to open when Fenrus the Devourer
GO_ARUGAL_DOOR = 18971 //door to open when Wolf Master Nandos
{ DATA_COMMANDER_SPRINGVALE, new ParallelogramBoundary(Position(-222.75f, 2269.03f), Position(-217.60f, 2249.65f), Position(-267.47f, 2256.10f)) },
{ DATA_LORD_WALDEN, new CircleBoundary(Position(-146.58f, 2173.037f), 17.0) },
};
enum Spells
{
SPELL_ASHCROMBE_TELEPORT = 15742
};
const Position SpawnLocation[] =
{
{-148.199f, 2165.647f, 128.448f, 1.026f},
{-153.110f, 2168.620f, 128.448f, 1.026f},
{-145.905f, 2180.520f, 128.448f, 4.183f},
{-140.794f, 2178.037f, 128.448f, 4.090f},
{-138.640f, 2170.159f, 136.577f, 2.737f}
};
class instance_shadowfang_keep : public InstanceMapScript
{
public:
instance_shadowfang_keep() : InstanceMapScript("instance_shadowfang_keep", 33) { }
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_shadowfang_keep_InstanceMapScript(map);
}
instance_shadowfang_keep() : InstanceMapScript(SKScriptName, 33) { }
struct instance_shadowfang_keep_InstanceMapScript : public InstanceScript
{
instance_shadowfang_keep_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
uiPhase = 0;
uiTimer = 0;
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
LoadBossBoundaries(boundaries);
LoadObjectData(creatureData, nullptr);
_teamInInstance = 0;
}
uint32 m_auiEncounter[MAX_ENCOUNTER];
std::string str_data;
ObjectGuid uiAshGUID;
ObjectGuid uiAdaGUID;
ObjectGuid uiArchmageArugalGUID;
ObjectGuid DoorCourtyardGUID;
ObjectGuid DoorSorcererGUID;
ObjectGuid DoorArugalGUID;
uint8 uiPhase;
uint16 uiTimer;
void OnCreatureCreate(Creature* creature) override
void OnPlayerEnter(Player* player) override
{
switch (creature->GetEntry())
if (!_teamInInstance)
{
case NPC_ASH: uiAshGUID = creature->GetGUID(); break;
case NPC_ADA: uiAdaGUID = creature->GetGUID(); break;
case NPC_ARCHMAGE_ARUGAL: uiArchmageArugalGUID = creature->GetGUID(); break;
_teamInInstance = player->GetTeam();
SetData(DATA_TEAM_IN_INSTANCE, _teamInInstance);
}
}
void OnGameObjectCreate(GameObject* go) override
bool SetBossState(uint32 type, EncounterState state) override
{
switch (go->GetEntry())
{
case GO_COURTYARD_DOOR:
DoorCourtyardGUID = go->GetGUID();
if (m_auiEncounter[0] == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_SORCERER_DOOR:
DoorSorcererGUID = go->GetGUID();
if (m_auiEncounter[2] == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_ARUGAL_DOOR:
DoorArugalGUID = go->GetGUID();
if (m_auiEncounter[3] == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
}
}
if (!InstanceScript::SetBossState(type, state))
return false;
void DoSpeech()
{
Creature* pAda = instance->GetCreature(uiAdaGUID);
Creature* pAsh = instance->GetCreature(uiAshGUID);
if (pAda && pAda->IsAlive() && pAsh && pAsh->IsAlive())
{
pAda->AI()->Talk(SAY_BOSS_DIE_AD);
pAsh->AI()->Talk(SAY_BOSS_DIE_AS);
}
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case TYPE_FREE_NPC:
if (data == DONE)
DoUseDoorOrButton(DoorCourtyardGUID);
m_auiEncounter[0] = data;
break;
case TYPE_RETHILGORE:
if (data == DONE)
DoSpeech();
m_auiEncounter[1] = data;
break;
case TYPE_FENRUS:
switch (data)
{
case DONE:
uiTimer = 1000;
uiPhase = 1;
break;
case 7:
DoUseDoorOrButton(DoorSorcererGUID);
break;
}
m_auiEncounter[2] = data;
break;
case TYPE_NANDOS:
if (data == DONE)
DoUseDoorOrButton(DoorArugalGUID);
m_auiEncounter[3] = data;
break;
}
if (data == DONE)
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
saveStream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3];
str_data = saveStream.str();
SaveToDB();
OUT_SAVE_INST_DATA_COMPLETE;
}
return true;
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case TYPE_FREE_NPC:
return m_auiEncounter[0];
case TYPE_RETHILGORE:
return m_auiEncounter[1];
case TYPE_FENRUS:
return m_auiEncounter[2];
case TYPE_NANDOS:
return m_auiEncounter[3];
case DATA_TEAM_IN_INSTANCE:
return _teamInInstance;
default:
break;
}
return 0;
}
std::string GetSaveData() override
void SetData(uint32 type, uint32 data) override
{
return str_data;
}
void Load(const char* in) override
{
if (!in)
switch (type)
{
OUT_LOAD_INST_DATA_FAIL;
return;
}
OUT_LOAD_INST_DATA(in);
std::istringstream loadStream(in);
loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3];
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
{
if (m_auiEncounter[i] == IN_PROGRESS)
m_auiEncounter[i] = NOT_STARTED;
}
OUT_LOAD_INST_DATA_COMPLETE;
}
void Update(uint32 uiDiff) override
{
if (GetData(TYPE_FENRUS) != DONE)
return;
Creature* pArchmage = instance->GetCreature(uiArchmageArugalGUID);
if (!pArchmage || !pArchmage->IsAlive())
return;
if (uiPhase)
{
if (uiTimer <= uiDiff)
{
switch (uiPhase)
{
case 1:
{
Creature* summon = pArchmage->SummonCreature(pArchmage->GetEntry(), SpawnLocation[4], TEMPSUMMON_TIMED_DESPAWN, 10000);
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
summon->SetReactState(REACT_DEFENSIVE);
summon->CastSpell(summon, SPELL_ASHCROMBE_TELEPORT, true);
summon->AI()->Talk(SAY_ARCHMAGE);
uiTimer = 2000;
uiPhase = 2;
break;
}
case 2:
{
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
uiPhase = 0;
break;
}
}
} else uiTimer -= uiDiff;
case DATA_TEAM_IN_INSTANCE:
_teamInInstance = data;
SaveToDB();
break;
default:
break;
}
}
void WriteSaveDataMore(std::ostringstream& data) override
{
data << _teamInInstance;
}
void ReadSaveDataMore(std::istringstream& data) override
{
data >> _teamInInstance;
uint32 temp = 0;
data >> temp;
if (temp)
SetData(DATA_TEAM_IN_INSTANCE, temp);
}
protected:
EventMap events;
uint32 _teamInInstance;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_shadowfang_keep_InstanceMapScript(map);
}
};
void AddSC_instance_shadowfang_keep()

View File

@@ -16,17 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Shadowfang_Keep
SD%Complete: 75
SDComment: npc_shadowfang_prisoner using escortAI for movement to door. Might need additional code in case being attacked. Add proper texts/say().
SDCategory: Shadowfang Keep
EndScriptData */
/* ContentData
npc_shadowfang_prisoner
EndContentData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
@@ -36,334 +25,45 @@ EndContentData */
#include "shadowfang_keep.h"
#include "Player.h"
/*######
## npc_shadowfang_prisoner
######*/
enum Yells
enum SKShieldOfBones
{
SAY_FREE_AS = 0,
SAY_OPEN_DOOR_AS = 1,
SAY_POST_DOOR_AS = 2,
SAY_FREE_AD = 0,
SAY_OPEN_DOOR_AD = 1,
SAY_POST1_DOOR_AD = 2,
SAY_POST2_DOOR_AD = 3
SPELL_SHIELD_OF_BONES_TRIGGERED = 91631,
};
enum Spells
{
SPELL_UNLOCK = 6421,
SPELL_DARK_OFFERING = 7154
};
enum Creatures
{
NPC_ASH = 3850
};
class npc_shadowfang_prisoner : public CreatureScript
{
public:
npc_shadowfang_prisoner() : CreatureScript("npc_shadowfang_prisoner") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_shadowfang_prisonerAI>(creature);
}
struct npc_shadowfang_prisonerAI : public npc_escortAI
{
npc_shadowfang_prisonerAI(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
Start(false, false);
}
return true;
}
bool GossipHello(Player* player) override
{
InstanceScript* instance = me->GetInstanceScript();
if (instance && instance->GetData(TYPE_FREE_NPC) != DONE && instance->GetData(TYPE_RETHILGORE) == DONE)
AddGossipItemFor(player, Player::GetDefaultGossipMenuForSource(me), 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID());
return true;
}
void WaypointReached(uint32 waypointId) override
{
switch (waypointId)
{
case 0:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_FREE_AS);
else
Talk(SAY_FREE_AD);
break;
case 10:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_OPEN_DOOR_AS);
else
Talk(SAY_OPEN_DOOR_AD);
break;
case 11:
if (me->GetEntry() == NPC_ASH)
DoCast(me, SPELL_UNLOCK);
break;
case 12:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_POST_DOOR_AS);
else
Talk(SAY_POST1_DOOR_AD);
instance->SetData(TYPE_FREE_NPC, DONE);
break;
case 13:
if (me->GetEntry() != NPC_ASH)
Talk(SAY_POST2_DOOR_AD);
break;
}
}
void Reset() override { }
void EnterCombat(Unit* /*who*/) override { }
};
};
class npc_arugal_voidwalker : public CreatureScript
{
public:
npc_arugal_voidwalker() : CreatureScript("npc_arugal_voidwalker") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_arugal_voidwalkerAI>(creature);
}
struct npc_arugal_voidwalkerAI : public ScriptedAI
{
npc_arugal_voidwalkerAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
uiDarkOffering = urand(200, 1000);
}
InstanceScript* instance;
uint32 uiDarkOffering;
void Reset() override
{
Initialize();
}
void UpdateAI(uint32 uiDiff) override
{
if (!UpdateVictim())
return;
if (uiDarkOffering <= uiDiff)
{
if (Creature* pFriend = me->FindNearestCreature(me->GetEntry(), 25.0f, true))
DoCast(pFriend, SPELL_DARK_OFFERING);
else
DoCast(me, SPELL_DARK_OFFERING);
uiDarkOffering = urand(4400, 12500);
} else uiDarkOffering -= uiDiff;
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
instance->SetData(TYPE_FENRUS, instance->GetData(TYPE_FENRUS) + 1);
}
};
};
enum ArugalSpells
{
SPELL_TELE_UPPER = 7587,
SPELL_TELE_SPAWN = 7586,
SPELL_TELE_STAIRS = 7136,
NUM_TELEPORT_SPELLS = 3,
SPELL_ARUGAL_CURSE = 7621,
SPELL_THUNDERSHOCK = 7803,
SPELL_VOIDBOLT = 7588
};
enum ArugalTexts
{
SAY_AGGRO = 1, // You, too, shall serve!
SAY_TRANSFORM = 2, // Release your rage!
SAY_SLAY = 3 // Another falls!
};
enum ArugalEvents
{
EVENT_VOID_BOLT = 1,
EVENT_TELEPORT,
EVENT_THUNDERSHOCK,
EVENT_CURSE
};
class boss_archmage_arugal : public CreatureScript
class spell_sfk_shield_of_bones: public SpellScriptLoader
{
public:
boss_archmage_arugal() : CreatureScript("boss_archmage_arugal") { }
spell_sfk_shield_of_bones() : SpellScriptLoader("spell_sfk_shield_of_bones") { }
struct boss_archmage_arugalAI : public BossAI
class spell_sfk_shield_of_bones_AuraScript : public AuraScript
{
boss_archmage_arugalAI(Creature* creature) : BossAI(creature, BOSS_ARUGAL) { }
PrepareAuraScript(spell_sfk_shield_of_bones_AuraScript);
uint32 teleportSpells[NUM_TELEPORT_SPELLS] =
bool Validate(SpellInfo const* /*spellInfo*/) override
{
SPELL_TELE_SPAWN,
SPELL_TELE_UPPER,
SPELL_TELE_STAIRS
};
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
return ValidateSpellInfo({ SPELL_SHIELD_OF_BONES_TRIGGERED });
}
void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
void OnAuraRemoveHandler(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (spell->Id == SPELL_ARUGAL_CURSE)
Talk(SAY_TRANSFORM);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_CURSE, Seconds(7));
events.ScheduleEvent(EVENT_TELEPORT, Seconds(15));
events.ScheduleEvent(EVENT_VOID_BOLT, Seconds(1));
events.ScheduleEvent(EVENT_THUNDERSHOCK, Seconds(10));
}
void AttackStart(Unit* who) override
{
AttackStartCaster(who, 100.0f); // void bolt range is 100.f
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CURSE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 30.0f, true))
DoCast(target, SPELL_ARUGAL_CURSE);
events.Repeat(Seconds(15));
break;
case EVENT_TELEPORT:
{
// ensure we never cast the same teleport twice in a row
uint8 spellIndex = urand(1, NUM_TELEPORT_SPELLS-1);
std::swap(teleportSpells[0], teleportSpells[spellIndex]);
DoCast(teleportSpells[0]);
events.Repeat(Seconds(20));
break;
}
case EVENT_THUNDERSHOCK:
DoCastAOE(SPELL_THUNDERSHOCK);
events.Repeat(Seconds(30));
break;
case EVENT_VOID_BOLT:
DoCastVictim(SPELL_VOIDBOLT);
events.Repeat(Seconds(5));
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_archmage_arugalAI>(creature);
}
};
class spell_shadowfang_keep_haunting_spirits : public SpellScriptLoader
{
public:
spell_shadowfang_keep_haunting_spirits() : SpellScriptLoader("spell_shadowfang_keep_haunting_spirits") { }
class spell_shadowfang_keep_haunting_spirits_AuraScript : public AuraScript
{
PrepareAuraScript(spell_shadowfang_keep_haunting_spirits_AuraScript);
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
{
isPeriodic = true;
amplitude = (irand(0, 60) + 30) * IN_MILLISECONDS;
}
void HandleDummyTick(AuraEffect const* aurEff)
{
GetTarget()->CastSpell((Unit*)NULL, aurEff->GetAmount(), true);
}
void HandleUpdatePeriodic(AuraEffect* aurEff)
{
aurEff->CalculatePeriodic(GetCaster());
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL)
if (Unit* caster = GetCaster())
caster->CastSpell(caster, SPELL_SHIELD_OF_BONES_TRIGGERED, true);
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::CalcPeriodic, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::HandleDummyTick, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_sfk_shield_of_bones_AuraScript::OnAuraRemoveHandler, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_shadowfang_keep_haunting_spirits_AuraScript();
return new spell_sfk_shield_of_bones_AuraScript();
}
};
void AddSC_shadowfang_keep()
{
new npc_shadowfang_prisoner();
new npc_arugal_voidwalker();
new boss_archmage_arugal();
new spell_shadowfang_keep_haunting_spirits();
new spell_sfk_shield_of_bones();
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* 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
@@ -19,16 +18,72 @@
#ifndef DEF_SHADOWFANG_H
#define DEF_SHADOWFANG_H
#include "SpellScript.h"
#define DataHeader "SK"
#define SKScriptName "instance_shadowfang_keep"
uint32 const EncounterCount = 7;
enum SKCreatures
{
// Baron Ashbury
BOSS_BARON_ASHBURY = 46962,
NPC_ASHBURY_WINGS = 50604,
// Baron Silverlaine
BOSS_BARON_SILVERLAINE = 3887,
NPC_NANDOS_DUMMY = 51047,
NPC_WOLF_MASTER_NANDOS = 50851,
NPC_LUPINE_SPECTRE = 50923,
NPC_ODO_DUMMY = 50934,
NPC_ODO_THE_BLINDWATCHER = 50857,
NPC_RAZORCLAW_DUMMY = 51080,
NPC_RAZORCLAW_THE_BUTCHER = 50869,
NPC_RETHILGORE_DUMMY = 51085,
NPC_RETHILGORE = 50834,
// Commander Springvale
BOSS_COMMANDER_SPRINGVALE = 4278,
NPC_TORMENTED_OFFICER = 50615,
NPC_WAILING_GUARDSMAN = 50613,
NPC_SHIELD_FOCUS = 50547,
NPC_DESECRATION_STALKER = 50503,
// Lord Walden
BOSS_LORD_WALDEN = 46963,
NPC_MYSTERY_MIXTURE = 50522,
// Lord Godfrey
BOSS_LORD_GODFREY = 46964,
NPC_BLOODTHIRSTY_GHOUL = 50561,
NPC_PISTOL_BARRAGE_DUMMY = 52065,
};
enum SKGameObjectIds
{
GO_COURTYARD_DOOR = 18895,
GO_SORCERER_DOOR = 18972,
GO_ARUGAL_DOOR = 18971
};
enum SKDataTypes
{
TYPE_FREE_NPC = 1,
TYPE_RETHILGORE = 2,
TYPE_FENRUS = 3,
TYPE_NANDOS = 4,
BOSS_ARUGAL = 5,
DATA_APOTHECARY_HUMMEL = 6
DATA_BARON_ASHBURY = 1,
DATA_BARON_SILVERLAINE = 2,
DATA_COMMANDER_SPRINGVALE = 3,
DATA_LORD_WALDEN = 4,
DATA_LORD_GODFREY = 5,
DATA_APOTHECARY_HUMMEL = 6,
DATA_TEAM_IN_INSTANCE = 7
};
template<class AI>
AI* GetShadowfangKeepAI(Creature* creature)
{
return GetInstanceAI<AI>(creature, SKScriptName);
}
#endif

View File

@@ -131,6 +131,11 @@ void AddSC_boss_vectus();
void AddSC_boss_kirtonos_the_herald();
void AddSC_instance_scholomance();
void AddSC_shadowfang_keep(); //Shadowfang keep
void AddSC_boss_baron_ashbury();
void AddSC_boss_baron_silverlaine();
void AddSC_boss_commander_springvale();
void AddSC_boss_lord_walden();
void AddSC_boss_lord_godfrey();
void AddSC_instance_shadowfang_keep();
void AddSC_boss_apothecary_hummel();
void AddSC_boss_magistrate_barthilas(); //Stratholme
@@ -321,6 +326,11 @@ void AddEasternKingdomsScripts()
AddSC_boss_kirtonos_the_herald();
AddSC_instance_scholomance();
AddSC_shadowfang_keep(); //Shadowfang keep
AddSC_boss_baron_ashbury();
AddSC_boss_baron_silverlaine();
AddSC_boss_commander_springvale();
AddSC_boss_lord_walden();
AddSC_boss_lord_godfrey();
AddSC_instance_shadowfang_keep();
AddSC_boss_apothecary_hummel();
AddSC_boss_magistrate_barthilas(); //Stratholme