diff --git a/sql/updates/world/master/2026_04_08_01_world.sql b/sql/updates/world/master/2026_04_08_01_world.sql
new file mode 100644
index 0000000000..ff5432884f
--- /dev/null
+++ b/sql/updates/world/master/2026_04_08_01_world.sql
@@ -0,0 +1,111 @@
+SET @CGUID := 11000647;
+SET @OGUID := 11000019;
+
+-- Creatures
+DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+1;
+INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `PhaseId`, `PhaseGroup`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `MovementType`, `npcflag`, `unit_flags`, `unit_flags2`, `unit_flags3`, `VerifiedBuild`) VALUES
+(@CGUID+0, 234648, 2813, 16091, 16091, '1,2,8,23,205', '0', 0, 0, 0, 8858.5732421875, -4841.0869140625, -6.9904031753540039, 4.624201774597167968, 7200, 0, 0, 0, NULL, NULL, NULL, NULL, 66220), -- Kystia Manaheart (Area: Murder Row - Difficulty: 0) CreateObject1 (Auras: 474365 - Fel Crazed, 422356 - Bot AI Follow Advert, 1217989 - Felshield, 1217464 - Illicit Infusion) (possible waypoints or random movement)
+(@CGUID+1, 234660, 2813, 16091, 16091, '1,2,8,23,205', '0', 0, 0, 0, 8858.5732421875, -4850.85400390625, -6.9904031753540039, 1.564232110977172851, 7200, 0, 0, 0, NULL, NULL, NULL, NULL, 66220); -- Nibbles (Area: Murder Row - Difficulty: 0) CreateObject1 (Auras: 1230289 - Illicit Infusion)
+
+DELETE FROM `creature_template_addon` WHERE `entry` IN (234648, 255050, 234660);
+INSERT INTO `creature_template_addon` (`entry`, `PathId`, `mount`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvpFlags`, `emote`, `aiAnimKit`, `movementAnimKit`, `meleeAnimKit`, `visibilityDistanceType`, `auras`) VALUES
+(234648, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, '422356'), -- 234648 (Kystia Manaheart) - Bot AI Follow Advert
+(255050, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, '1264103'), -- 255050 (Kystia Manaheart) - VFX
+(234660, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, '1230289'); -- 234660 (Nibbles) - Illicit Infusion
+
+DELETE FROM `creature_template_difficulty` WHERE (`DifficultyID`=1 AND `Entry` IN (234648, 234660, 255050));
+INSERT INTO `creature_template_difficulty` (`Entry`, `DifficultyID`, `HealthScalingExpansion`, `HealthModifier`, `ManaModifier`, `CreatureDifficultyID`, `TypeFlags`, `TypeFlags2`, `TypeFlags3`) VALUES
+(255050, 1, 11, 10, 1, 335959, 0x1000000, 128, 0), -- Kystia Manaheart
+(234648, 1, 11, 30, 1, 286375, 0x200068, 4224, 0), -- Kystia Manaheart
+(234660, 1, 11, 12, 1, 286387, 0x200068, 128, 0); -- Nibbles
+
+UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2, `LevelScalingDeltaMax`=2, `ContentTuningID`=3233, `StaticFlags1`=0x10000000, `VerifiedBuild`=66220 WHERE (`Entry`=234660 AND `DifficultyID`=1); -- 234660 (Nibbles) - CanSwim
+UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2, `LevelScalingDeltaMax`=2, `ContentTuningID`=3233, `StaticFlags1`=0x10000000, `VerifiedBuild`=66220 WHERE (`Entry`=234648 AND `DifficultyID`=1); -- 234648 (Kystia Manaheart) - CanSwim
+UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2, `LevelScalingDeltaMax`=2, `ContentTuningID`=3233, `VerifiedBuild`=66220 WHERE (`Entry`=255050 AND `DifficultyID`=1); -- 255050 (Kystia Manaheart) -
+
+UPDATE `creature_template` SET `faction`=14, `BaseAttackTime`=2000, `unit_flags`=0x40, `ScriptName`='boss_kystia_manaheart' WHERE `entry`=234648; -- Kystia Manaheart
+UPDATE `creature_template` SET `faction`=16, `speed_run`=1, `BaseAttackTime`=2400, `unit_flags`=0x000, `unit_flags3`=0x800001, `ScriptName`='boss_kystia_manaheart_nibbles' WHERE `entry`=234660; -- Nibbles
+UPDATE `creature_template` SET `faction`=16, `BaseAttackTime`=2000, `unit_flags2`=0x800, `AIName`= 'SmartAI' WHERE `entry`=255050; -- Kystia Manaheart
+
+DELETE FROM `creature_equip_template` WHERE (`ID`=1 AND `CreatureID` IN (234648));
+INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `AppearanceModID1`, `ItemVisual1`, `ItemID2`, `AppearanceModID2`, `ItemVisual2`, `ItemID3`, `AppearanceModID3`, `ItemVisual3`, `VerifiedBuild`) VALUES
+(234648, 1, 208225, 0, 0, 0, 0, 0, 0, 0, 0, 66220); -- Kystia Manaheart
+
+DELETE FROM `creature_model_info` WHERE `DisplayID` IN (126199, 124578, 138932);
+INSERT INTO `creature_model_info` (`DisplayID`, `BoundingRadius`, `CombatReach`, `DisplayID_Other_Gender`, `VerifiedBuild`) VALUES
+(124578, 0.765999972820281982, 3, 0, 66220),
+(138932, 0.765999972820281982, 3, 0, 66220),
+(126199, 2.475043296813964843, 4, 0, 66220);
+
+-- Gameobjects
+DELETE FROM `gameobject` WHERE `guid` = @OGUID+0;
+INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `PhaseId`, `PhaseGroup`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES
+(@OGUID+0, 618401, 2813, 16091, 16091, '1,2,8,23,205', '0', 0, 8817.5693359375, -4840.35400390625, -9.61550140380859375, 3.132858037948608398, 0, 0, 0.999990463256835937, 0.004367320332676172, 7200, 255, 0, 66220); -- Fel Door (Area: Murder Row - Difficulty: 0) CreateObject1
+
+DELETE FROM `gameobject_template` WHERE `entry` = 618401;
+INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `Data24`, `Data25`, `Data26`, `Data27`, `Data28`, `Data29`, `Data30`, `Data31`, `Data32`, `Data33`, `Data34`, `RequiredLevel`, `ContentTuningId`, `VerifiedBuild`) VALUES
+(618401, 0, 118294,'Fel Door', '', '', 1.800000429153442382, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66220); -- Fel Door
+
+DELETE FROM `gameobject_template_addon` WHERE `entry` = 618401;
+INSERT INTO `gameobject_template_addon` (`entry`, `faction`, `flags`, `WorldEffectID`, `AIAnimKitID`) VALUES
+(618401, 0, 0x30, 0, 0); -- Fel Door
+
+-- Areatrigger
+DELETE FROM `areatrigger_create_properties` WHERE (`IsCustom`=0 AND `Id` IN (36175,36260,36030,36393,2329,39934,36242,36356,36048,39560,36081,39834,26730,23866,2442,32530,30795,41463,41462));
+INSERT INTO `areatrigger_create_properties` (`Id`, `IsCustom`, `AreaTriggerId`, `IsAreatriggerCustom`, `Flags`, `MoveCurveId`, `ScaleCurveId`, `MorphCurveId`, `FacingCurveId`, `AnimId`, `AnimKitId`, `DecalPropertiesId`, `SpellForVisuals`, `TimeToTargetScale`, `Speed`, `Shape`, `ShapeData0`, `ShapeData1`, `ShapeData2`, `ShapeData3`, `ShapeData4`, `ShapeData5`, `ShapeData6`, `ShapeData7`, `ScriptName`, `VerifiedBuild`) VALUES
+(39560, 0, 41022, 0, 2, 0, 0, 0, 0, -1, 0, 0, NULL, 5000, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 'at_kystia_manaheart_fel_spray', 66220); -- Spell: 1253811 (Fel Spray)
+
+DELETE FROM `areatrigger_create_properties_polygon_vertex` WHERE (`AreaTriggerCreatePropertiesId`=39560 AND `IsCustom`=0 AND `Idx`=0) OR (`AreaTriggerCreatePropertiesId`=39560 AND `IsCustom`=0 AND `Idx`=1) OR (`AreaTriggerCreatePropertiesId`=39560 AND `IsCustom`=0 AND `Idx`=2) OR (`AreaTriggerCreatePropertiesId`=39560 AND `IsCustom`=0 AND `Idx`=3);
+INSERT INTO `areatrigger_create_properties_polygon_vertex` (`AreaTriggerCreatePropertiesId`, `IsCustom`, `Idx`, `VerticeX`, `VerticeY`, `VerticeTargetX`, `VerticeTargetY`, `VerifiedBuild`) VALUES
+(39560, 0, 0, 0, 1, NULL, NULL, 66220), -- Spell: 1253811 (Fel Spray)
+(39560, 0, 1, 0, -1, NULL, NULL, 66220), -- Spell: 1253811 (Fel Spray)
+(39560, 0, 2, 60, -45, NULL, NULL, 66220), -- Spell: 1253811 (Fel Spray)
+(39560, 0, 3, 60, 45, NULL, NULL, 66220); -- Spell: 1253811 (Fel Spray)
+
+DELETE FROM `areatrigger_template` WHERE (`IsCustom`=0 AND `Id` IN (41022));
+INSERT INTO `areatrigger_template` (`Id`, `IsCustom`, `VerifiedBuild`) VALUES
+(41022, 0, 66220);
+
+-- Conditions
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=2 AND `SourceEntry`=1217464;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 2, 1217464, 0, 0, 51, 0, 5, 234660, 0, '', 0, 0, 0, '', 'Spell \'Illicit Infusion\' can only hit \'Nibbles\'');
+
+-- Instance
+DELETE FROM `instance_template` WHERE `map`=2813;
+INSERT INTO `instance_template` (`map`, `parent`, `script`) VALUES
+(2813, 0, 'instance_murder_row');
+
+-- SAI
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 255050 AND `source_type`=0;
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `Difficulties`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param_string`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `action_param7`, `action_param_string`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_param_string`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(255050, 0, 0, 0, '', 11, 0, 100, 0, 0, 0, 0, 0, 0, '', 11, 1264106, 0, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Kystia Manaheart (copy) - On Respawn - Cast \'Felstorm\'');
+
+-- Spells
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_kystia_manaheart_felstorm', 'spell_kystia_manaheart_mirror_images', 'spell_kystia_manaheart_mirror_image', 'spell_kystia_manaheart_light_infusion', 'spell_kystia_manaheart_fel_crazed', 'spell_kystia_manaheart_fel_nova_selector', 'spell_kystia_manaheart_blink');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(1264095, 'spell_kystia_manaheart_mirror_images'),
+(1264098, 'spell_kystia_manaheart_mirror_image'),
+(1230304, 'spell_kystia_manaheart_light_infusion'),
+(474365, 'spell_kystia_manaheart_fel_crazed'),
+(474240, 'spell_kystia_manaheart_fel_nova_selector'),
+(1264106, 'spell_kystia_manaheart_felstorm'),
+(474183, 'spell_kystia_manaheart_blink');
+
+-- Texts
+DELETE FROM `creature_text` WHERE `CreatureID` IN (234648, 234660);
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(234648, 0, 0, 'Let\'s make an example of you.', 14, 0, 100, 0, 0, 306490, 281368, 0, 'Kystia Manaheart'),
+(234648, 1, 0, 'Flee the flame!', 14, 0, 50, 0, 0, 299094, 297213, 0, 'Kystia Manaheart'),
+(234648, 1, 1, 'Fear the fel!', 14, 0, 50, 0, 0, 299095, 297214, 0, 'Kystia Manaheart'),
+(234648, 2, 0, 'Learn your place!', 14, 0, 50, 0, 0, 299093, 297210, 0, 'Kystia Manaheart'),
+(234648, 2, 1, 'Back, you mongrels!', 14, 0, 50, 0, 0, 299092, 297209, 0, 'Kystia Manaheart'),
+(234648, 3, 0, 'Naughty little Nibbles!', 14, 0, 50, 0, 0, 299096, 297215, 0, 'Kystia Manaheart to Nibbles'),
+(234648, 3, 1, 'Nibbles! Drop it!', 14, 0, 50, 0, 0, 299097, 297216, 0, 'Kystia Manaheart to Nibbles'),
+(234648, 4, 0, 'Ahh, just what I needed.', 14, 0, 50, 0, 0, 299091, 297208, 0, 'Kystia Manaheart'),
+(234648, 4, 1, 'Nibbles, give mother a taste!', 14, 0, 50, 0, 0, 299090, 297206, 0, 'Kystia Manaheart'),
+(234648, 5, 0, 'But... my... magic...', 14, 0, 100, 0, 0, 299088, 297202, 0, 'Kystia Manaheart to Player'),
+(234648, 6, 0, 'Fel conquers all.', 14, 0, 100, 0, 0, 299087, 297199, 0, 'Kystia Manaheart'),
+(234660, 0, 0, '|TInterface\\ICONS\\Spell_Paladin_Lightofdawn.blp:20|t %s casts |cFFFF0000|Hspell:1230304|h[Light Infusion]|h|r at Kystia!', 68, 0, 100, 0, 0, 0, 0, 0, 'Nibbles to Kystia Manaheart'),
+(234660, 1, 0, '|TInterface\\ICONS\\Spell_Fire_FelFlameBreath.blp:20|t %s begins casting |cFFFF0000|Hspell:1253811|h[Fel Spray]|h|r!', 68, 0, 100, 0, 0, 0, 0, 0, 'Nibbles to Player'),
+(234660, 2, 0, '%s makes her escape.', 68, 0, 100, 0, 0, 299088, 280475, 0, 'Nibbles to Nibbles');
diff --git a/src/server/scripts/QuelThalas/MurderRow/boss_kystia_manaheart.cpp b/src/server/scripts/QuelThalas/MurderRow/boss_kystia_manaheart.cpp
new file mode 100644
index 0000000000..43a24c6da2
--- /dev/null
+++ b/src/server/scripts/QuelThalas/MurderRow/boss_kystia_manaheart.cpp
@@ -0,0 +1,558 @@
+/*
+ * 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 .
+ */
+
+#include "AreaTrigger.h"
+#include "AreaTriggerAI.h"
+#include "Creature.h"
+#include "InstanceScript.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellAuras.h"
+#include "SpellInfo.h"
+#include "SpellMgr.h"
+#include "SpellScript.h"
+#include "murder_row.h"
+
+namespace Scripts::QuelThalas::MurderRow::KystiaManaheart
+{
+ namespace Spells
+ {
+ static constexpr uint32 IllicitInfusionVisual = 1217464;
+ static constexpr uint32 FelCrazed = 474365;
+ static constexpr uint32 Felshield = 1217989;
+ static constexpr uint32 MirrorImages = 1264095;
+ static constexpr uint32 MirrorImage = 1264098;
+ static constexpr uint32 ChaosBarrage = 1230298;
+ static constexpr uint32 IllicitInfusion = 1230289;
+ static constexpr uint32 IllicitInfusionCast = 474238;
+ static constexpr uint32 FelNova = 1223906;
+ static constexpr uint32 FelNovaSelector = 474240;
+ static constexpr uint32 Blink = 474183;
+
+ // Nibbles
+ static constexpr uint32 FelSpray = 1253811;
+ static constexpr uint32 FelSprayDamage = 1253813;
+ static constexpr uint32 CorrodingSpittle = 1228198;
+ static constexpr uint32 LightInfusion = 1230304;
+ static constexpr uint32 Destabilized = 1265412;
+ static constexpr uint32 Escape = 1248184;
+ }
+
+ namespace Texts
+ {
+ // Kystia
+ static constexpr uint8 Aggro = 0;
+ static constexpr uint8 MirrorImages = 1;
+ static constexpr uint8 FelNova = 2;
+ static constexpr uint8 Destabilized = 3;
+ static constexpr uint8 IllicitInfusion = 4;
+ static constexpr uint8 Death = 5;
+ static constexpr uint8 Wipe = 6;
+
+ // Nibbles
+ static constexpr uint8 LightInfusion = 0;
+ static constexpr uint8 FelSprayWarning = 1;
+ static constexpr uint8 Escape = 2;
+ }
+
+ namespace Events
+ {
+ // Kystia
+ static constexpr uint8 ChaosBarrage = 1;
+ static constexpr uint8 MirrorImages = 2;
+ static constexpr uint8 FelNova = 3;
+
+ // Nibbles
+ static constexpr uint8 FelSpray = 4;
+ static constexpr uint8 CorrodingSpittle = 5;
+ static constexpr uint8 CheckHealth = 6;
+ }
+
+ namespace Positions
+ {
+ static constexpr Position NibblesEscapePosition = { 8861.71f, -4843.24f, 13.0376f };
+ }
+
+ namespace Points
+ {
+ static constexpr uint8 PointEscape = 0;
+ }
+
+ namespace SpellVisuals
+ {
+ static constexpr uint32 SpellVisualNibblesFriendly = 229191;
+ static constexpr uint32 SpellVisualNibblesUnfriendly = 249081;
+ }
+
+ namespace DisplayIds
+ {
+ static constexpr uint32 DisplayFriendly = 128332;
+ static constexpr uint32 DisplayUnfriendly = 126199;
+ }
+
+// 234648 - Kystia Manaheart
+struct boss_kystia_manaheart : public BossAI
+{
+ boss_kystia_manaheart(Creature* creature) : BossAI(creature, DATA_KYSTIA_MANAHEART), _felshieldCount(0) { }
+
+ void JustAppeared() override
+ {
+ DoCastSelf(Spells::FelCrazed, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ DoCast(Spells::IllicitInfusionVisual);
+ }
+
+ void Reset() override
+ {
+ _Reset();
+ _felshieldCount = 0;
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(Texts::Death);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ instance->SetBossState(DATA_KYSTIA_MANAHEART, DONE);
+
+ if (Creature* nibbles = instance->GetCreature(DATA_NIBBLES))
+ {
+ nibbles->SetDisplayId(DisplayIds::DisplayFriendly);
+ nibbles->SetAnimTier(AnimTier::Fly, true);
+ nibbles->SetDisableGravity(true);
+ nibbles->SetPlayHoverAnim(true);
+ nibbles->CastSpell(nibbles, Spells::Escape, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ nibbles->AI()->Talk(Texts::Escape);
+ nibbles->GetMotionMaster()->MovePoint(Points::PointEscape, Positions::NibblesEscapePosition);
+ }
+ }
+
+ void OnChannelFinished(SpellInfo const* spell) override
+ {
+ if (spell->Id != Spells::IllicitInfusionCast)
+ return;
+
+ uint8 stackAmount = 3 - _felshieldCount;
+ if (stackAmount == 0)
+ stackAmount = 1;
+
+ DoCastSelf(Spells::Felshield, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_AURA_STACK, stackAmount));
+ _felshieldCount++;
+
+ if (Creature* nibbles = instance->GetCreature(DATA_NIBBLES))
+ {
+ nibbles->SendPlaySpellVisualKit(SpellVisuals::SpellVisualNibblesUnfriendly, 0, 0);
+ nibbles->SetDisplayId(DisplayIds::DisplayUnfriendly);
+ nibbles->ClearUnitState(UNIT_STATE_ROOT);
+ nibbles->CastSpell(nibbles, Spells::IllicitInfusion, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ }
+ }
+
+ void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == Spells::Destabilized)
+ Talk(Texts::Destabilized);
+ }
+
+ void OnSpellStart(SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == Spells::IllicitInfusionCast)
+ {
+ Talk(Texts::IllicitInfusion);
+
+ if (Creature* nibbles = instance->GetCreature(DATA_NIBBLES))
+ nibbles->AddUnitState(UNIT_STATE_ROOT);
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ instance->SetBossState(DATA_KYSTIA_MANAHEART, FAIL);
+
+ Talk(Texts::Wipe);
+
+ summons.DespawnAll();
+ _EnterEvadeMode();
+ _DespawnAtEvade();
+
+ if (Creature* nibbles = instance->GetCreature(DATA_NIBBLES))
+ nibbles->AI()->EnterEvadeMode(why);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(Texts::Aggro);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ instance->SetBossState(DATA_KYSTIA_MANAHEART, IN_PROGRESS);
+
+ if (Creature* nibbles = instance->GetCreature(DATA_NIBBLES))
+ nibbles->AI()->DoZoneInCombat();
+
+ events.ScheduleEvent(Events::ChaosBarrage, 1s);
+ events.ScheduleEvent(Events::MirrorImages, 14s);
+
+ if (IsHeroicOrHigher())
+ events.ScheduleEvent(Events::FelNova, 12s);
+ }
+
+ 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 Events::ChaosBarrage:
+ {
+ DoCastVictim(Spells::ChaosBarrage, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ events.Repeat(3500ms);
+ break;
+ }
+ case Events::MirrorImages:
+ {
+ Talk(Texts::MirrorImages);
+ DoCastSelf(Spells::MirrorImages, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ events.Repeat(30500ms);
+ break;
+ }
+ case Events::FelNova:
+ {
+ Talk(Texts::FelNova);
+ DoCast(Spells::FelNovaSelector);
+ events.Repeat(15s);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+ }
+
+private:
+ uint8 _felshieldCount;
+};
+
+// 234660 - Nibbles
+struct boss_kystia_manaheart_nibbles : public BossAI
+{
+ boss_kystia_manaheart_nibbles(Creature* creature) : BossAI(creature, DATA_NIBBLES)
+ {
+ SetBoundary(instance->GetBossBoundary(DATA_KYSTIA_MANAHEART));
+ me->SetUnkillable(true);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ _EnterEvadeMode();
+ _DespawnAtEvade();
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 id) override
+ {
+ if (id == Points::PointEscape)
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ me->DespawnOrUnsummon();
+ }
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
+
+ if (Creature* kystia = instance->GetCreature(DATA_KYSTIA_MANAHEART))
+ kystia->AI()->DoZoneInCombat();
+
+ events.ScheduleEvent(Events::CheckHealth, 1s);
+ events.ScheduleEvent(Events::FelSpray, 8s);
+ events.ScheduleEvent(Events::CorrodingSpittle, 4500ms);
+ }
+
+ void OnChannelFinished(SpellInfo const* spell) override
+ {
+ if (spell->Id != Spells::LightInfusion)
+ return;
+
+ if (Creature* kystia = instance->GetCreature(DATA_KYSTIA_MANAHEART))
+ kystia->CastSpell(me, Spells::IllicitInfusionCast, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (me->GetFaction() == FACTION_FRIENDLY)
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case Events::FelSpray:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, Spells::FelSpray, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ Talk(Texts::FelSprayWarning);
+ events.Repeat(51s);
+ break;
+ }
+ case Events::CorrodingSpittle:
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, Spells::CorrodingSpittle, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ events.Repeat(14500ms);
+ break;
+ }
+ case Events::CheckHealth:
+ {
+ SpellInfo const* illicitInfusion = sSpellMgr->AssertSpellInfo(Spells::IllicitInfusion, DIFFICULTY_NONE);
+ if (me->GetHealthPct() < illicitInfusion->GetEffect(EFFECT_0).CalcValue(me))
+ {
+ me->RemoveAurasDueToSpell(Spells::IllicitInfusion);
+ me->InterruptNonMeleeSpells(true);
+ me->AttackStop();
+ me->SetFaction(FACTION_FRIENDLY);
+ me->SendPlaySpellVisualKit(SpellVisuals::SpellVisualNibblesFriendly, 0, 0);
+ me->SetDisplayId(DisplayIds::DisplayFriendly);
+
+ if (Creature* kystia = instance->GetCreature(DATA_KYSTIA_MANAHEART))
+ {
+ DoCast(kystia, Spells::LightInfusion, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ Talk(Texts::LightInfusion);
+ }
+
+ events.RescheduleEvent(Events::CheckHealth, 15s);
+ }
+ events.Repeat(1s);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+ }
+};
+
+// 1230304 - Light Infusion
+class spell_kystia_manaheart_light_infusion : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo ({ Spells::Destabilized });
+ }
+
+ void HandleStun(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, Spells::Destabilized, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_kystia_manaheart_light_infusion::HandleStun, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 1264095 - Mirror Images
+class spell_kystia_manaheart_mirror_images : public AuraScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ Spells::MirrorImage });
+ }
+
+ void HandlePeriodicEffect(AuraEffect const* aurEff) const
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, Spells::MirrorImage, CastSpellExtraArgsInit{
+ .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
+ .TriggeringAura = aurEff
+ });
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_kystia_manaheart_mirror_images::HandlePeriodicEffect, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+};
+
+// 1264098 - Mirror Image
+class spell_kystia_manaheart_mirror_image : public SpellScript
+{
+ void SetDest(SpellDestination& dest) const
+ {
+ dest.RelocateOffset({ frand(-30.0f, 25.0f), frand(-15.0f, 26.0f), 0.0f, 0.0f });
+ }
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_kystia_manaheart_mirror_image::SetDest, EFFECT_0, TARGET_DEST_DEST);
+ }
+};
+
+// 474240 - Fel Nova
+class spell_kystia_manaheart_fel_nova_selector : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ Spells::Blink });
+ }
+
+ void HandleHitTarget(SpellEffIndex /*effIndex*/) const
+ {
+ GetCaster()->CastSpell(GetHitUnit(), Spells::Blink, CastSpellExtraArgsInit{
+ .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
+ .TriggeringSpell = GetSpell()
+ });
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_kystia_manaheart_fel_nova_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+};
+
+// 474183 - Blink
+class spell_kystia_manaheart_blink : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ Spells::FelNova });
+ }
+
+ void HandleCast() const
+ {
+ Unit* caster = GetCaster();
+ caster->CastSpell(caster, Spells::FelNova, CastSpellExtraArgsInit{
+ .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
+ .TriggeringSpell = GetSpell()
+ });
+ }
+
+ void Register() override
+ {
+ AfterCast += SpellCastFn(spell_kystia_manaheart_blink::HandleCast);
+ }
+};
+
+// 474365 - Fel Crazed
+class spell_kystia_manaheart_fel_crazed : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ Spells::Felshield });
+ }
+
+ void HandleFelshield(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ Unit* caster = GetCaster();
+ caster->CastSpell(caster, Spells::Felshield, CastSpellExtraArgs()
+ .SetTriggerFlags(TRIGGERED_FULL_MASK)
+ .SetTriggeringSpell(GetSpell())
+ .AddSpellMod(SPELLVALUE_AURA_STACK, 4));
+ }
+
+ void Register() override
+ {
+ OnEffectLaunch += SpellEffectFn(spell_kystia_manaheart_fel_crazed::HandleFelshield, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
+ }
+};
+
+// 1264106 - Felstorm
+class spell_kystia_manaheart_felstorm : public AuraScript
+{
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* targetCreature = GetTarget()->ToCreature())
+ targetCreature->DespawnOrUnsummon(1ms);
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_kystia_manaheart_felstorm::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 1253811 - Fel Spray
+// ID - 39560
+struct at_kystia_manaheart_fel_spray : AreaTriggerAI
+{
+ using AreaTriggerAI::AreaTriggerAI;
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ Unit* caster = at->GetCaster();
+ if (!caster)
+ return;
+
+ if (!unit->IsPlayer())
+ return;
+
+ caster->CastSpell(unit, Spells::FelSprayDamage, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
+ }
+
+ void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
+ {
+ unit->RemoveAurasDueToSpell(Spells::FelSprayDamage);
+ }
+};
+}
+
+void AddSC_boss_kystia_manaheart()
+{
+ using namespace Scripts::QuelThalas::MurderRow::KystiaManaheart;
+
+ RegisterMurderRowCreatureAI(boss_kystia_manaheart);
+ RegisterMurderRowCreatureAI(boss_kystia_manaheart_nibbles);
+
+ RegisterSpellScript(spell_kystia_manaheart_light_infusion);
+ RegisterSpellScript(spell_kystia_manaheart_mirror_images);
+ RegisterSpellScript(spell_kystia_manaheart_mirror_image);
+ RegisterSpellScript(spell_kystia_manaheart_fel_nova_selector);
+ RegisterSpellScript(spell_kystia_manaheart_blink);
+ RegisterSpellScript(spell_kystia_manaheart_fel_crazed);
+ RegisterSpellScript(spell_kystia_manaheart_felstorm);
+
+ RegisterAreaTriggerAI(at_kystia_manaheart_fel_spray);
+}
diff --git a/src/server/scripts/QuelThalas/MurderRow/instance_murder_row.cpp b/src/server/scripts/QuelThalas/MurderRow/instance_murder_row.cpp
new file mode 100644
index 0000000000..9189efbd83
--- /dev/null
+++ b/src/server/scripts/QuelThalas/MurderRow/instance_murder_row.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 .
+ */
+
+#include "AreaBoundary.h"
+#include "InstanceScript.h"
+#include "ScriptMgr.h"
+#include "murder_row.h"
+
+BossBoundaryData const boundaries =
+{
+ { DATA_KYSTIA_MANAHEART, new ZRangeBoundary(-8.0f, 4.50f) }
+};
+
+static constexpr ObjectData creatureData[] =
+{
+ { BOSS_KYSTIA_MANAHEART, DATA_KYSTIA_MANAHEART },
+ { BOSS_ZAEN_BLADESORROW, DATA_ZAEN_BLADESORROW },
+ { BOSS_XATHUUX_THE_ANNIHILATOR, DATA_XATHUUX_THE_ANNIHILATOR },
+ { BOSS_LITHIEL_CINDERFURY, DATA_LITHIEL_CINDERFURY },
+ { NPC_NIBBLES, DATA_NIBBLES }
+};
+
+static constexpr DungeonEncounterData const encounters[] =
+{
+ { DATA_KYSTIA_MANAHEART, {{ 3101 }} },
+ { DATA_ZAEN_BLADESORROW, {{ 3102 }} },
+ { DATA_XATHUUX_THE_ANNIHILATOR, {{ 3103 }} },
+ { DATA_LITHIEL_CINDERFURY, {{ 3105 }} }
+};
+
+static constexpr DoorData doorData[] =
+{
+ { GO_FEL_DOOR, DATA_KYSTIA_MANAHEART, EncounterDoorBehavior::OpenWhenNotInProgress }
+};
+
+class instance_murder_row : public InstanceMapScript
+{
+public:
+ instance_murder_row() : InstanceMapScript(MRScriptName, 2813) { }
+
+ struct instance_murder_row_InstanceMapScript: public InstanceScript
+ {
+ instance_murder_row_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadObjectData(creatureData, {});
+ LoadDoorData(doorData);
+ LoadBossBoundaries(boundaries);
+ LoadDungeonEncounterData(encounters);
+ }
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_murder_row_InstanceMapScript(map);
+ }
+};
+
+void AddSC_instance_murder_row()
+{
+ new instance_murder_row();
+}
diff --git a/src/server/scripts/QuelThalas/MurderRow/murder_row.h b/src/server/scripts/QuelThalas/MurderRow/murder_row.h
new file mode 100644
index 0000000000..b8337fe37f
--- /dev/null
+++ b/src/server/scripts/QuelThalas/MurderRow/murder_row.h
@@ -0,0 +1,65 @@
+/*
+ * 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 .
+ */
+
+#ifndef DEF_MURDER_ROW_H_
+#define DEF_MURDER_ROW_H_
+
+#include "CreatureAIImpl.h"
+
+#define MRScriptName "instance_murder_row"
+#define DataHeader "MurderRow"
+
+uint32 const EncounterCount = 4;
+
+enum MurderRowDataTypes
+{
+ // Encounters
+ DATA_KYSTIA_MANAHEART = 0,
+ DATA_ZAEN_BLADESORROW = 1,
+ DATA_XATHUUX_THE_ANNIHILATOR = 2,
+ DATA_LITHIEL_CINDERFURY = 3,
+
+ // Additional Data
+ DATA_NIBBLES
+};
+
+enum MurderRowCreatureIds
+{
+ // Bosses
+ BOSS_KYSTIA_MANAHEART = 234648,
+ BOSS_ZAEN_BLADESORROW = 234649,
+ BOSS_XATHUUX_THE_ANNIHILATOR = 234647,
+ BOSS_LITHIEL_CINDERFURY = 237415,
+
+ // Npcs
+ NPC_NIBBLES = 234660
+};
+
+enum MurderRowGameObjectIds
+{
+ GO_FEL_DOOR = 618401
+};
+
+template
+inline AI* GetMurderRowAI(T* obj)
+{
+ return GetInstanceAI(obj, MRScriptName);
+}
+
+#define RegisterMurderRowCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMurderRowAI)
+
+#endif
diff --git a/src/server/scripts/QuelThalas/quel_thalas_script_loader.cpp b/src/server/scripts/QuelThalas/quel_thalas_script_loader.cpp
new file mode 100644
index 0000000000..df7d68a978
--- /dev/null
+++ b/src/server/scripts/QuelThalas/quel_thalas_script_loader.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 .
+ */
+
+// This is where scripts' loading functions should be declared:
+
+// Murder Row
+void AddSC_boss_kystia_manaheart();
+void AddSC_instance_murder_row();
+
+// The name of this function should match:
+// void Add${NameOfDirectory}Scripts()
+void AddQuelThalasScripts()
+{
+ // Murder Row
+ AddSC_boss_kystia_manaheart();
+ AddSC_instance_murder_row();
+}