mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-24 02:46:33 +01:00
Scripts/SFK: implement all bosses
This commit is contained in:
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user