aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/KulTiras/WaycrestManor/boss_heartsbane_triad.cpp1009
-rw-r--r--src/server/scripts/KulTiras/WaycrestManor/instance_waycrest_manor.cpp78
-rw-r--r--src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.h70
-rw-r--r--src/server/scripts/KulTiras/kultiras_script_loader.cpp8
4 files changed, 1165 insertions, 0 deletions
diff --git a/src/server/scripts/KulTiras/WaycrestManor/boss_heartsbane_triad.cpp b/src/server/scripts/KulTiras/WaycrestManor/boss_heartsbane_triad.cpp
new file mode 100644
index 00000000000..480c122bade
--- /dev/null
+++ b/src/server/scripts/KulTiras/WaycrestManor/boss_heartsbane_triad.cpp
@@ -0,0 +1,1009 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AreaTrigger.h"
+#include "AreaTriggerAI.h"
+#include "Creature.h"
+#include "GridNotifiers.h"
+#include "InstanceScript.h"
+#include "Map.h"
+#include "ObjectAccessor.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "waycrest_manor.h"
+
+enum HeartsbaneTriadSpells
+{
+ // Sister Briar
+ SPELL_BRAMBLE_BOLT = 260701,
+ SPELL_BRAMBLE_BOLT_ENHANCED = 260697,
+ SPELL_JAGGED_NETTLES = 260741,
+ SPELL_IRONBARK_SHIELD = 261265,
+ SPELL_AURA_OF_THORNS = 268122,
+ SPELL_AURA_OF_THORNS_CHECK_PROC = 268125,
+
+ // Sister Malady
+ SPELL_RUINOUS_BOLT = 260700,
+ SPELL_RUINOUS_BOLT_ENHANCED = 260696,
+ SPELL_RUNIC_WARD = 261266,
+ SPELL_UNSTABLE_RUNIC_MARK = 260703,
+ SPELL_UNSTABLE_RUNIC_MARK_DAMAGE = 260702,
+ SPELL_AURA_OF_DREAD = 268088,
+ SPELL_AURA_OF_DREAD_DAMAGE = 268086,
+ SPELL_AURA_OF_DREAD_MOVE_CHECK = 268085,
+
+ // Sister Solena
+ SPELL_SOUL_BOLT = 260699,
+ SPELL_SOUL_BOLT_ENHANCED = 260698,
+ SPELL_SOUL_ARMOR = 261264,
+ SPELL_SOUL_MANIPULATION_SELECTOR = 260907,
+ SPELL_SOUL_MANIPULATION_CHARM = 260900,
+ SPELL_SOUL_MANIPULATION_DAMAGE_REDUCTION = 260923,
+ SPELL_SOUL_MANIPULATION_VISUAL = 260926,
+ SPELL_AURA_OF_APATHY = 268077,
+ SPELL_AURA_OF_APATHY_DEBUFF = 268080,
+
+ SPELL_DIRE_RITUAL = 260773,
+ SPELL_CLAIM_THE_IRIS = 260852,
+ SPELL_DROP_THE_IRIS = 260853,
+ SPELL_FOCUSING_IRIS = 260805
+};
+
+enum HeartsbaneTriadTexts
+{
+ // Shared
+ SAY_AGGRO = 0,
+ SAY_CLAIM_THE_IRIS = 1,
+ SAY_SLAY = 3,
+ SAY_DEATH = 4,
+ SAY_DIRE_RITUAL_ALERT = 5,
+ SAY_DIRE_RITUAL = 6,
+
+ // Sister Solena
+ SAY_SOUL_MANIPULATION = 2,
+
+ // Sister Malady
+ SAY_UNSTABLE_RUNIC_MARK = 2,
+
+ // Sister Briar
+ SAY_JAGGED_NETTLES = 2
+};
+
+enum HeartsbaneTriadEvents
+{
+ // Sister Briar
+ EVENT_BRAMBLE_BOLT = 1,
+ EVENT_BRAMBLE_BOLT_ENHANCED,
+ EVENT_JAGGED_NETTLES,
+ EVENT_AURA_OF_THORNS,
+
+ // Sister Malady
+ EVENT_RUINOUS_BOLT,
+ EVENT_RUINOUS_BOLT_ENHANCED,
+ EVENT_UNSTABLE_RUNIC_MARK,
+ EVENT_AURA_OF_DREAD,
+
+ // Sister Solena
+ EVENT_SOUL_BOLT,
+ EVENT_SOUL_BOLT_ENHANCED,
+ EVENT_SOUL_MANIPULATION,
+ EVENT_AURA_OF_APATHY,
+
+ EVENT_CHECK_POWER,
+ EVENT_CLAIM_IRIS,
+};
+
+enum HeartsbaneTriadActions
+{
+ ACTION_CLAIM_THE_IRIS_INTRO = 1,
+ ACTION_CLAIM_THE_IRIS,
+};
+
+enum HeartsbaneTriadSummonGroups
+{
+ SUMMON_GROUP_TRIAD_FOCUSING_IRIS = 0
+};
+
+uint32 const HeartsbaneTriadData[3] =
+{
+ DATA_SISTER_BRIAR,
+ DATA_SISTER_MALADY,
+ DATA_SISTER_SOLENA
+};
+
+namespace
+{
+void HeartsbaneTriadEncounterStart(InstanceScript* instance)
+{
+ if (instance->GetBossState(DATA_HEARTSBANE_TRIAD) == IN_PROGRESS)
+ return;
+
+ instance->SetBossState(DATA_HEARTSBANE_TRIAD, IN_PROGRESS);
+
+ for (uint32 data : HeartsbaneTriadData)
+ {
+ if (Creature* sister = instance->GetCreature(data))
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, sister, 1);
+ sister->AI()->DoZoneInCombat();
+ }
+ }
+}
+
+void HeartsbaneTriadEncounterFail(InstanceScript* instance, EvadeReason why, Creature* invoker)
+{
+ if (instance->GetBossState(DATA_HEARTSBANE_TRIAD) == FAIL)
+ return;
+
+ instance->SetBossState(DATA_HEARTSBANE_TRIAD, FAIL);
+
+ for (uint32 data : HeartsbaneTriadData)
+ {
+ if (Creature* triad = instance->GetCreature(data))
+ {
+ if (triad == invoker)
+ continue;
+
+ triad->AI()->EnterEvadeMode(why);
+ }
+ }
+}
+
+void HeartsbaneTriadEncounterDone(InstanceScript* instance)
+{
+ if (instance->GetBossState(DATA_HEARTSBANE_TRIAD) == DONE)
+ return;
+
+ for (uint32 data : HeartsbaneTriadData)
+ {
+ if (Creature* sister = instance->GetCreature(data))
+ {
+ if (sister->IsAlive())
+ return;
+ }
+ }
+
+ for (uint32 data : HeartsbaneTriadData)
+ {
+ if (Creature* sister = instance->GetCreature(data))
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, sister);
+ }
+
+ instance->SetBossState(DATA_HEARTSBANE_TRIAD, DONE);
+}
+}
+
+struct HeartsbaneTriadSharedAI : public BossAI
+{
+ HeartsbaneTriadSharedAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _healthTriggered(false), _claimedIris(false)
+ {
+ SetBoundary(instance->GetBossBoundary(DATA_HEARTSBANE_TRIAD));
+ }
+
+ virtual void ScheduleEvents()
+ {
+ events.ScheduleEvent(EVENT_CHECK_POWER, 1000ms);
+ };
+
+ virtual void HandleDropIris(bool /*skipShieldPhase*/, bool /*skipIrisDrop*/)
+ {
+ _claimedIris = false;
+ }
+
+ virtual void HandleClaimIris()
+ {
+ _claimedIris = true;
+
+ Talk(SAY_CLAIM_THE_IRIS);
+
+ me->AttackStop();
+ me->InterruptNonMeleeSpells(true);
+
+ if (Creature* focusingIris = me->FindNearestCreature(NPC_FOCUSING_IRIS, 200.0f))
+ me->CastSpell(focusingIris, SPELL_CLAIM_THE_IRIS);
+
+ me->SetUnkillable(false);
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ _healthTriggered = false;
+ _claimedIris = false;
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ HeartsbaneTriadEncounterFail(instance, why, me);
+
+ me->RemoveAurasDueToSpell(SPELL_FOCUSING_IRIS);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ summons.DespawnAll();
+ _EnterEvadeMode();
+ _DespawnAtEvade();
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ {
+ if (me->HealthBelowPctDamaged(50, damage) && !_healthTriggered)
+ {
+ _healthTriggered = true;
+ me->AttackStop();
+ me->InterruptNonMeleeSpells(true);
+
+ me->SetUnkillable(true);
+
+ HandleDropIris(false, !_claimedIris);
+ }
+ }
+
+ void JustAppeared() override
+ {
+ me->SetPowerType(POWER_ENERGY);
+ me->SetPower(POWER_ENERGY, 0);
+
+ me->SetUnkillable(true);
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ HeartsbaneTriadEncounterStart(instance);
+ ScheduleEvents();
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CHECK_POWER:
+ {
+ if (me->GetPower(POWER_ENERGY) >= 100)
+ {
+ Talk(SAY_DIRE_RITUAL_ALERT);
+ Talk(SAY_DIRE_RITUAL);
+ DoCast(SPELL_DIRE_RITUAL);
+ }
+ events.Repeat(1000ms);
+ break;
+ }
+ case EVENT_CLAIM_IRIS:
+ {
+ HandleClaimIris();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ void DoAction(int32 actionId) override
+ {
+ switch (actionId)
+ {
+ case ACTION_CLAIM_THE_IRIS:
+ events.Reset();
+ events.ScheduleEvent(EVENT_CLAIM_IRIS, 1500ms);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+
+ Talk(SAY_DEATH);
+
+ HeartsbaneTriadEncounterDone(instance);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (!victim->IsPlayer())
+ return;
+
+ Talk(SAY_SLAY);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ ExecuteEvent(eventId);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+ }
+
+private:
+ bool _healthTriggered;
+
+protected:
+ bool _claimedIris; // to prevent dropping multiple iris if a sister dies during claim process
+};
+
+// 131825 - Sister Briar
+struct boss_sister_briar : public HeartsbaneTriadSharedAI
+{
+ boss_sister_briar(Creature* creature) : HeartsbaneTriadSharedAI(creature, DATA_SISTER_BRIAR) { }
+
+ void ScheduleEvents() override
+ {
+ HeartsbaneTriadSharedAI::ScheduleEvents();
+
+ events.ScheduleEvent(EVENT_BRAMBLE_BOLT, 2000ms);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ HeartsbaneTriadSharedAI::JustDied(killer);
+
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_JAGGED_NETTLES);
+ }
+
+ void HandleDropIris(bool skipShieldPhase, bool skipIrisDrop) override
+ {
+ HeartsbaneTriadSharedAI::HandleDropIris(skipIrisDrop, skipIrisDrop);
+
+ me->RemoveAurasDueToSpell(SPELL_AURA_OF_THORNS);
+
+ events.CancelEvent(EVENT_BRAMBLE_BOLT_ENHANCED);
+ events.CancelEvent(EVENT_JAGGED_NETTLES);
+
+ if (skipShieldPhase)
+ return;
+
+ if (!skipIrisDrop)
+ DoCastSelf(SPELL_DROP_THE_IRIS);
+ DoCastSelf(SPELL_IRONBARK_SHIELD);
+
+ if (Creature* solena = instance->GetCreature(DATA_SISTER_SOLENA))
+ solena->AI()->DoAction(ACTION_CLAIM_THE_IRIS);
+
+ events.ScheduleEvent(EVENT_BRAMBLE_BOLT, 3200ms);
+ }
+
+ void HandleClaimIris() override
+ {
+ HeartsbaneTriadSharedAI::HandleClaimIris();
+
+ if (IsHeroic() || IsMythic())
+ events.ScheduleEvent(EVENT_AURA_OF_THORNS, 1600ms);
+
+ me->RemoveAurasDueToSpell(SPELL_IRONBARK_SHIELD);
+ events.ScheduleEvent(EVENT_BRAMBLE_BOLT_ENHANCED, 4700ms);
+ events.ScheduleEvent(EVENT_JAGGED_NETTLES, 14600ms);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ HeartsbaneTriadSharedAI::EnterEvadeMode(why);
+
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_JAGGED_NETTLES);
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_BRAMBLE_BOLT:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_BRAMBLE_BOLT);
+ events.Repeat(2400ms);
+ break;
+ }
+ case EVENT_BRAMBLE_BOLT_ENHANCED:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_BRAMBLE_BOLT_ENHANCED);
+ events.Repeat(7300ms);
+ break;
+ }
+ case EVENT_JAGGED_NETTLES:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_JAGGED_NETTLES);
+ Talk(SAY_JAGGED_NETTLES);
+ events.Repeat(14600ms);
+ break;
+ }
+ case EVENT_AURA_OF_THORNS:
+ {
+ DoCastSelf(SPELL_AURA_OF_THORNS);
+ break;
+ }
+ default:
+ HeartsbaneTriadSharedAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+};
+
+// 131823 - Sister Malady
+struct boss_sister_malady : public HeartsbaneTriadSharedAI
+{
+ boss_sister_malady(Creature* creature) : HeartsbaneTriadSharedAI(creature, DATA_SISTER_MALADY) { }
+
+ void ScheduleEvents() override
+ {
+ HeartsbaneTriadSharedAI::ScheduleEvents();
+
+ events.ScheduleEvent(EVENT_RUINOUS_BOLT, 3200ms);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ HeartsbaneTriadSharedAI::JustDied(killer);
+
+ HandleDropIris(true, _claimedIris);
+ }
+
+ void HandleDropIris(bool skipShieldPhase, bool skipIrisDrop) override
+ {
+ me->RemoveAurasDueToSpell(SPELL_AURA_OF_DREAD);
+ if (!skipIrisDrop)
+ DoCastSelf(SPELL_DROP_THE_IRIS);
+
+ if (Creature* briar = instance->GetCreature(DATA_SISTER_BRIAR))
+ briar->AI()->DoAction(ACTION_CLAIM_THE_IRIS);
+
+ events.CancelEvent(EVENT_RUINOUS_BOLT_ENHANCED);
+ events.CancelEvent(EVENT_UNSTABLE_RUNIC_MARK);
+
+ if (skipShieldPhase)
+ return;
+
+ DoCastSelf(SPELL_RUNIC_WARD);
+ events.ScheduleEvent(EVENT_RUINOUS_BOLT, 3200ms);
+ }
+
+ void HandleClaimIris() override
+ {
+ HeartsbaneTriadSharedAI::HandleClaimIris();
+
+ if (IsHeroic() || IsMythic())
+ events.ScheduleEvent(EVENT_AURA_OF_DREAD, 1600ms);
+
+ me->RemoveAurasDueToSpell(SPELL_RUNIC_WARD);
+
+ events.ScheduleEvent(EVENT_RUINOUS_BOLT_ENHANCED, 4700ms);
+ events.ScheduleEvent(EVENT_UNSTABLE_RUNIC_MARK, 14600ms);
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_RUINOUS_BOLT:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_RUINOUS_BOLT);
+ events.Repeat(2400ms);
+ break;
+ }
+ case EVENT_RUINOUS_BOLT_ENHANCED:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_RUINOUS_BOLT_ENHANCED);
+ events.Repeat(7300ms);
+ break;
+ }
+ case EVENT_UNSTABLE_RUNIC_MARK:
+ {
+ Talk(SAY_UNSTABLE_RUNIC_MARK);
+ DoCast(SPELL_UNSTABLE_RUNIC_MARK);
+ events.Repeat(12100ms);
+ break;
+ }
+ case EVENT_CLAIM_IRIS:
+ {
+ HandleClaimIris();
+ break;
+ }
+ case EVENT_AURA_OF_DREAD:
+ {
+ DoCastSelf(SPELL_AURA_OF_DREAD);
+ break;
+ }
+ default:
+ HeartsbaneTriadSharedAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+};
+
+// 131824 - Sister Solena
+struct boss_sister_solena : public HeartsbaneTriadSharedAI
+{
+ boss_sister_solena(Creature* creature) : HeartsbaneTriadSharedAI(creature, DATA_SISTER_SOLENA) { }
+
+ void ScheduleEvents() override
+ {
+ HeartsbaneTriadSharedAI::ScheduleEvents();
+
+ events.ScheduleEvent(EVENT_SOUL_BOLT_ENHANCED, 4700ms);
+ events.ScheduleEvent(EVENT_SOUL_MANIPULATION, 12000ms);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ HeartsbaneTriadSharedAI::JustEngagedWith(who);
+
+ DoAction(ACTION_CLAIM_THE_IRIS_INTRO);
+
+ if (Creature* sister = me->GetInstanceScript()->GetCreature(RAND(DATA_SISTER_SOLENA, DATA_SISTER_BRIAR, DATA_SISTER_MALADY)))
+ sister->AI()->Talk(SAY_AGGRO);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ HeartsbaneTriadSharedAI::JustDied(killer);
+
+ HandleDropIris(true, _claimedIris);
+ }
+
+ void HandleDropIris(bool skipShieldPhase, bool skipIrisDrop) override
+ {
+ me->RemoveAurasDueToSpell(SPELL_AURA_OF_APATHY);
+ if (!skipIrisDrop)
+ DoCastSelf(SPELL_DROP_THE_IRIS);
+
+ if (Creature* malady = instance->GetCreature(DATA_SISTER_MALADY))
+ malady->AI()->DoAction(ACTION_CLAIM_THE_IRIS);
+
+ events.CancelEvent(EVENT_SOUL_BOLT_ENHANCED);
+ events.CancelEvent(EVENT_SOUL_MANIPULATION);
+
+ if (skipShieldPhase)
+ return;
+
+ DoCastSelf(SPELL_SOUL_ARMOR);
+ events.ScheduleEvent(EVENT_SOUL_BOLT, 3200ms);
+ }
+
+ void HandleClaimIris() override
+ {
+ HeartsbaneTriadSharedAI::HandleClaimIris();
+
+ if (IsHeroic() || IsMythic())
+ events.ScheduleEvent(EVENT_AURA_OF_APATHY, 1600ms);
+
+ me->RemoveAurasDueToSpell(SPELL_SOUL_ARMOR);
+
+ events.ScheduleEvent(EVENT_SOUL_BOLT_ENHANCED, 4700ms);
+ events.ScheduleEvent(EVENT_SOUL_MANIPULATION, 14600ms);
+ }
+
+ void DoAction(int32 actionId) override
+ {
+ switch (actionId)
+ {
+ case ACTION_CLAIM_THE_IRIS_INTRO:
+ {
+ _claimedIris = true;
+
+ if (Creature* focusingIris = me->FindNearestCreature(NPC_FOCUSING_IRIS, 100.0f))
+ DoCast(focusingIris, SPELL_CLAIM_THE_IRIS);
+
+ if (IsHeroic() || IsMythic())
+ events.ScheduleEvent(EVENT_AURA_OF_APATHY, 1600ms);
+ break;
+ }
+ default:
+ HeartsbaneTriadSharedAI::DoAction(actionId);
+ break;
+ }
+ }
+
+ void JustAppeared() override
+ {
+ HeartsbaneTriadSharedAI::JustAppeared();
+ me->SummonCreatureGroup(SUMMON_GROUP_TRIAD_FOCUSING_IRIS);
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_SOUL_BOLT_ENHANCED:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_SOUL_BOLT_ENHANCED);
+ events.Repeat(4900ms);
+ break;
+ }
+ case EVENT_SOUL_BOLT:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_SOUL_BOLT);
+ events.Repeat(2400ms);
+ break;
+ }
+ case EVENT_SOUL_MANIPULATION:
+ {
+ if (me->GetMap()->GetPlayersCountExceptGMs() > 1) // This event doesn't happen if you go solo because it resets boss
+ {
+ Talk(SAY_SOUL_MANIPULATION);
+ DoCast(SPELL_SOUL_MANIPULATION_SELECTOR);
+ events.RescheduleEvent(EVENT_SOUL_BOLT_ENHANCED, 12s + 100ms);
+ events.Repeat(23100ms, 24200ms);
+ }
+ break;
+ }
+ case EVENT_AURA_OF_APATHY:
+ {
+ DoCastSelf(SPELL_AURA_OF_APATHY);
+ break;
+ }
+ default:
+ HeartsbaneTriadSharedAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+};
+
+// 260741 - Jagged Nettles
+class spell_heartsbane_triad_jagged_nettles : public AuraScript
+{
+ void HandlePeriodic(AuraEffect const* aurEff)
+ {
+ if (aurEff->GetTickNumber() > 1)
+ {
+ if (GetTarget()->GetHealthPct() >= float(GetEffectInfo(EFFECT_2).CalcValue(GetCaster())))
+ Remove();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_heartsbane_triad_jagged_nettles::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+};
+
+// 260852 - Claim the Iris
+class spell_heartsbane_triad_claim_the_iris : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_FOCUSING_IRIS });
+ }
+
+ void HandleHitTarget(SpellEffIndex /*effIndex*/)
+ {
+ Creature* casterCreature = GetCaster()->ToCreature();
+ if (!casterCreature)
+ return;
+
+ if (Creature* hitCreature = GetHitCreature())
+ hitCreature->DespawnOrUnsummon();
+
+ casterCreature->CastSpell(casterCreature, SPELL_FOCUSING_IRIS, TRIGGERED_IGNORE_CAST_IN_PROGRESS);
+ casterCreature->SetSessile(false);
+ casterCreature->SetFloating(false);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_heartsbane_triad_claim_the_iris::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+};
+
+// 260854 - Drop the Iris
+class spell_heartsbane_triad_drop_the_iris : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_FOCUSING_IRIS });
+ }
+
+ void RemoveIris(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->RemoveAurasDueToSpell(SPELL_FOCUSING_IRIS);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_heartsbane_triad_drop_the_iris::RemoveIris, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+};
+
+// 260923 - Soul Manipulation
+class spell_heartsbane_triad_soul_manipulation_periodic : public AuraScript
+{
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (GetTarget()->GetHealthPct() > 50.0f)
+ return;
+
+ Remove();
+
+ if (Unit* caster = GetCaster())
+ caster->InterruptSpell(CURRENT_CHANNELED_SPELL);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_heartsbane_triad_soul_manipulation_periodic::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
+ }
+};
+
+// 260907 Soul Manipulation (Selector)
+class spell_heartsbane_triad_soul_manipulation_selector : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SOUL_MANIPULATION_CHARM, SPELL_SOUL_MANIPULATION_DAMAGE_REDUCTION, SPELL_SOUL_MANIPULATION_VISUAL });
+ }
+
+ void HandleHitTarget(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SOUL_MANIPULATION_CHARM, TRIGGERED_IGNORE_CAST_IN_PROGRESS);
+ GetCaster()->CastSpell(GetCaster(), SPELL_SOUL_MANIPULATION_DAMAGE_REDUCTION, TRIGGERED_IGNORE_CAST_IN_PROGRESS);
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SOUL_MANIPULATION_VISUAL, TRIGGERED_IGNORE_CAST_IN_PROGRESS);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_heartsbane_triad_soul_manipulation_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+};
+
+// 260703 - Unstable Runic Mark
+class spell_heartsbane_triad_unstable_runic_mark : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_UNSTABLE_RUNIC_MARK_DAMAGE });
+ }
+
+ void HandleDamage(AuraEffect const* /*aurEff*/ , AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL)
+ return;
+
+ GetTarget()->CastSpell(GetTarget(), SPELL_UNSTABLE_RUNIC_MARK_DAMAGE, true);
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_heartsbane_triad_unstable_runic_mark::HandleDamage, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 260773 - Dire Ritual
+class spell_heartsbane_triad_dire_ritual : public SpellScript
+{
+ void HandleAfterCast()
+ {
+ GetCaster()->SetPower(POWER_ENERGY, 0);
+ }
+
+ void Register() override
+ {
+ AfterCast += SpellCastFn(spell_heartsbane_triad_dire_ritual::HandleAfterCast);
+ }
+};
+
+// 17789 - Aura of Apathy
+struct at_heartsbane_triad_aura_of_apathy : AreaTriggerAI
+{
+ at_heartsbane_triad_aura_of_apathy(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ if (!unit->IsPlayer())
+ return;
+
+ unit->CastSpell(unit, SPELL_AURA_OF_APATHY_DEBUFF, true);
+ }
+
+ void OnUnitExit(Unit* unit) override
+ {
+ unit->RemoveAurasDueToSpell(SPELL_AURA_OF_APATHY_DEBUFF);
+ }
+
+ void OnRemove() override
+ {
+ for (ObjectGuid const& guid : at->GetInsideUnits())
+ {
+ Unit* unit = ObjectAccessor::GetUnit(*at, guid);
+ if (!unit)
+ continue;
+
+ OnUnitExit(unit);
+ }
+ }
+};
+
+// 17791 - Aura of Dread
+struct at_heartsbane_triad_aura_of_dread : AreaTriggerAI
+{
+ at_heartsbane_triad_aura_of_dread(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ if (!unit->IsPlayer())
+ return;
+
+ unit->CastSpell(unit, SPELL_AURA_OF_DREAD_MOVE_CHECK, true);
+ }
+
+ void OnUnitExit(Unit* unit) override
+ {
+ unit->RemoveAurasDueToSpell(SPELL_AURA_OF_DREAD_MOVE_CHECK);
+ unit->RemoveAurasDueToSpell(SPELL_AURA_OF_DREAD_DAMAGE);
+ }
+
+ void OnRemove() override
+ {
+ for (ObjectGuid const& guid : at->GetInsideUnits())
+ {
+ Unit* unit = ObjectAccessor::GetUnit(*at, guid);
+ if (!unit)
+ continue;
+
+ OnUnitExit(unit);
+ }
+ }
+};
+
+// 268088 - Aura of Dread
+class spell_heartsbane_triad_aura_of_dread : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_AURA_OF_DREAD_DAMAGE, SPELL_AURA_OF_DREAD_MOVE_CHECK });
+ }
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ for (MapReference const& players : caster->GetMap()->GetPlayers())
+ {
+ if (Player* player = players.GetSource())
+ {
+ if (!player->HasAura(SPELL_AURA_OF_DREAD_MOVE_CHECK))
+ continue;
+
+ player->CastSpell(player, SPELL_AURA_OF_DREAD_DAMAGE, true);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_heartsbane_triad_aura_of_dread::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
+ }
+};
+
+// 268085 - Aura of Dread
+class spell_heartsbane_triad_aura_of_dread_movement_check : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_AURA_OF_DREAD_DAMAGE });
+ }
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ if (caster->isMoving())
+ {
+ if (Aura* stack = caster->GetAura(SPELL_AURA_OF_DREAD_DAMAGE, caster->GetGUID()))
+ {
+ if (stack->GetStackAmount() > 1)
+ caster->RemoveAuraFromStack(SPELL_AURA_OF_DREAD_DAMAGE);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_heartsbane_triad_aura_of_dread_movement_check::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+};
+
+// 17807 - Aura of Thorns
+struct at_heartsbane_triad_aura_of_thorns : AreaTriggerAI
+{
+ at_heartsbane_triad_aura_of_thorns(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ if (!unit->IsPlayer())
+ return;
+
+ unit->CastSpell(unit, SPELL_AURA_OF_THORNS_CHECK_PROC, true);
+ }
+
+ void OnUnitExit(Unit* unit) override
+ {
+ unit->RemoveAurasDueToSpell(SPELL_AURA_OF_THORNS_CHECK_PROC);
+ }
+
+ void OnRemove() override
+ {
+ for (ObjectGuid const& guid : at->GetInsideUnits())
+ {
+ Unit* unit = ObjectAccessor::GetUnit(*at, guid);
+ if (!unit)
+ continue;
+
+ OnUnitExit(unit);
+ }
+ }
+};
+
+// 268122 - Aura of Thorns
+class spell_heartsbane_triad_aura_of_thorns : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_AURA_OF_THORNS_CHECK_PROC });
+ }
+
+ bool HandleCheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetActor()->HasAura(SPELL_AURA_OF_THORNS_CHECK_PROC);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_heartsbane_triad_aura_of_thorns::HandleCheckProc);
+ }
+};
+
+void AddSC_boss_heartsbane_triad()
+{
+ RegisterWaycrestManorCreatureAI(boss_sister_briar);
+ RegisterWaycrestManorCreatureAI(boss_sister_malady);
+ RegisterWaycrestManorCreatureAI(boss_sister_solena);
+
+ RegisterSpellScript(spell_heartsbane_triad_jagged_nettles);
+ RegisterSpellScript(spell_heartsbane_triad_claim_the_iris);
+ RegisterSpellScript(spell_heartsbane_triad_drop_the_iris);
+ RegisterSpellScript(spell_heartsbane_triad_soul_manipulation_periodic);
+ RegisterSpellScript(spell_heartsbane_triad_soul_manipulation_selector);
+ RegisterSpellScript(spell_heartsbane_triad_unstable_runic_mark);
+ RegisterSpellScript(spell_heartsbane_triad_dire_ritual);
+
+ RegisterAreaTriggerAI(at_heartsbane_triad_aura_of_apathy);
+ RegisterAreaTriggerAI(at_heartsbane_triad_aura_of_dread);
+ RegisterSpellScript(spell_heartsbane_triad_aura_of_dread);
+ RegisterSpellScript(spell_heartsbane_triad_aura_of_dread_movement_check);
+ RegisterAreaTriggerAI(at_heartsbane_triad_aura_of_thorns);
+ RegisterSpellScript(spell_heartsbane_triad_aura_of_thorns);
+}
diff --git a/src/server/scripts/KulTiras/WaycrestManor/instance_waycrest_manor.cpp b/src/server/scripts/KulTiras/WaycrestManor/instance_waycrest_manor.cpp
new file mode 100644
index 00000000000..00611f4ace4
--- /dev/null
+++ b/src/server/scripts/KulTiras/WaycrestManor/instance_waycrest_manor.cpp
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AreaBoundary.h"
+#include "InstanceScript.h"
+#include "ScriptMgr.h"
+#include "waycrest_manor.h"
+
+static BossBoundaryData const boundaries =
+{
+ { DATA_HEARTSBANE_TRIAD, new BoundaryIntersectionBoundary(new ZRangeBoundary(235.0f, 243.0f), new RectangleBoundary(-618.580f, -524.305f, -188.971f, -137.363f)) },
+};
+
+ObjectData const creatureData[] =
+{
+ { BOSS_SISTER_BRIAR, DATA_SISTER_BRIAR },
+ { BOSS_SISTER_MALADY, DATA_SISTER_MALADY },
+ { BOSS_SISTER_SOLENA, DATA_SISTER_SOLENA },
+ { 0, 0 } // END
+};
+
+DoorData const doorData[] =
+{
+ { GO_HEARTSBANE_TRIAD_DOOR, DATA_HEARTSBANE_TRIAD, EncounterDoorBehavior::OpenWhenNotInProgress },
+ { 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress } // END
+};
+
+DungeonEncounterData const encounters[] =
+{
+ { DATA_HEARTSBANE_TRIAD, {{ 2113 }} },
+ { DATA_SOULBOUND_GOLIATH, {{ 2114 }} },
+ { DATA_RAAL_THE_GLUTTONOUS, {{ 2115 }} },
+ { DATA_LORD_AND_LADY_WAYCREST, {{ 2116 }} },
+ { DATA_GORAK_TUL, {{ 2117 }} }
+};
+
+class instance_waycrest_manor : public InstanceMapScript
+{
+public:
+ instance_waycrest_manor() : InstanceMapScript("instance_waycrest_manor", 1862) { }
+
+ struct instance_waycrest_manor_InstanceMapScript : public InstanceScript
+ {
+ instance_waycrest_manor_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadObjectData(creatureData, nullptr);
+ LoadDoorData(doorData);
+ LoadBossBoundaries(boundaries);
+ LoadDungeonEncounterData(encounters);
+ }
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_waycrest_manor_InstanceMapScript(map);
+ }
+};
+
+void AddSC_instance_waycrest_manor()
+{
+ new instance_waycrest_manor();
+}
diff --git a/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.h b/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.h
new file mode 100644
index 00000000000..477be0bdcaf
--- /dev/null
+++ b/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _Waycrest_Manor_h__
+#define _Waycrest_Manor_h__
+
+#include "CreatureAIImpl.h"
+
+constexpr char const* DataHeader = "WM";
+constexpr char const* WaycrestManorScriptName = "instance_waycrest_manor";
+
+constexpr uint32 const EncounterCount = 5;
+
+enum WaycrestManorDataTypes
+{
+ // Encounters
+ DATA_HEARTSBANE_TRIAD = 0,
+ DATA_SOULBOUND_GOLIATH = 1,
+ DATA_RAAL_THE_GLUTTONOUS = 2,
+ DATA_LORD_AND_LADY_WAYCREST = 3,
+ DATA_GORAK_TUL = 4,
+
+ DATA_SISTER_BRIAR,
+ DATA_SISTER_MALADY,
+ DATA_SISTER_SOLENA
+};
+
+enum WaycrestManorCreatureIds
+{
+ // Bosses
+ BOSS_SISTER_BRIAR = 131825,
+ BOSS_SISTER_MALADY = 131823,
+ BOSS_SISTER_SOLENA = 131824,
+ BOSS_SOULBOUND_GOLIATH = 131667,
+ BOSS_RAAL_THE_GLUTTONOUS = 131863,
+ BOSS_LADY_WAYCREST = 136918,
+ BOSS_LORD_WAYCREST = 131527,
+ BOSS_GORAK_TUL = 131863,
+
+ NPC_FOCUSING_IRIS = 132361
+};
+
+enum WaycrestManorGameObjectIds
+{
+ GO_HEARTSBANE_TRIAD_DOOR = 282410
+};
+
+template <class AI, class T>
+inline AI* GetWaycrestManorAI(T* obj)
+{
+ return GetInstanceAI<AI>(obj, WaycrestManorScriptName);
+}
+
+#define RegisterWaycrestManorCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetWaycrestManorAI)
+
+#endif // _Waycrest_Manor_h__
diff --git a/src/server/scripts/KulTiras/kultiras_script_loader.cpp b/src/server/scripts/KulTiras/kultiras_script_loader.cpp
index e4ed7ba007f..d4f7d82f68f 100644
--- a/src/server/scripts/KulTiras/kultiras_script_loader.cpp
+++ b/src/server/scripts/KulTiras/kultiras_script_loader.cpp
@@ -19,9 +19,17 @@
void AddSC_zone_boralus();
+// Waycrest Manor
+void AddSC_boss_heartsbane_triad();
+void AddSC_instance_waycrest_manor();
+
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddKulTirasScripts()
{
AddSC_zone_boralus();
+
+ // Waycrest Manor
+ AddSC_boss_heartsbane_triad();
+ AddSC_instance_waycrest_manor();
}