Scripts/ReturnToKarazhan: Implement Shade of Medivh encounter (#31281)

This commit is contained in:
Aqua Deus
2025-10-04 18:13:35 +02:00
committed by GitHub
parent 3bbd6340dc
commit d76f436b9f
5 changed files with 955 additions and 4 deletions

View File

@@ -0,0 +1,76 @@
SET @AREATRIGGERID := 172;
-- Creature
UPDATE `creature_template` SET `ScriptName`='boss_shade_of_medivh' WHERE `entry`=114350;
UPDATE `creature_template` SET `faction`=16, `BaseAttackTime`=2000, `unit_flags2`=0x800, `unit_flags3`=0x40080000, `ScriptName`='boss_shade_of_medivh_guardians_image' WHERE `entry`=114675; -- Guardian's Image
UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2, `LevelScalingDeltaMax`=2, `ContentTuningID`=629, `StaticFlags1`=0x30000100, `VerifiedBuild`=63003 WHERE (`Entry`=114675 AND `DifficultyID`=23); -- 114675 (Guardian's Image) - Sessile, CanSwim, Floating
DELETE FROM `creature_template_movement` WHERE `CreatureId`=114675;
INSERT INTO `creature_template_movement` (`CreatureId`, `HoverInitiallyEnabled`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
(114675, 1, 0, 0, NULL);
-- Areatriggers
DELETE FROM `areatrigger_template` WHERE (`IsCustom` IN (0,1) AND `Id` IN (12878, 12916, @AREATRIGGERID+0, @AREATRIGGERID+1));
INSERT INTO `areatrigger_template` (`Id`, `IsCustom`, `Flags`, `ActionSetId`, `ActionSetFlags`, `VerifiedBuild`) VALUES
(12916, 0, 0, 0, 512, 59570),
(12878, 0, 0, 0, 0, 45745),
(@AREATRIGGERID+0, 1, 0, 0, 0, 0),
(@AREATRIGGERID+1, 1, 0, 0, 0, 0);
DELETE FROM `areatrigger_create_properties` WHERE (`IsCustom`=0 AND `Id` IN (8809, 8848, 8851, 8879));
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
(8851, 0, 12916, 0, 0, 2618, 0, 0, 0, -1, 0, 0, NULL, 20000, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 'at_shade_of_medivh_flame_wreath', 45745), -- Spell: 228257 (Flame Wreath)
(8809, 0, @AREATRIGGERID+0, 1, 0, 0, 0, 0, 0, -1, 0, 89, NULL, 20000, 0, 4, 40, 40, 1, 1, 0.300000011920928955, 0.300000011920928955, 0, 0, 'at_shade_of_medivh_ceaseless_winter_jump_check', 45745), -- SpellForVisuals: 227779 (Ceaseless Winter)
(8848, 0, 12878, 0, 0, 0, 0, 0, 0, -1, 0, 0, NULL, 20000, 0, 4, 40, 40, 15, 15, 0.300000011920928955, 0.300000011920928955, 0, 0, 'at_shade_of_medivh_ceaseless_winter', 45745), -- SpellForVisuals: 227779 (Ceaseless Winter)
(8879, 0, @AREATRIGGERID+1, 1, 0, 0, 0, 2319, 0, -1, 0, 89, NULL, 20000, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, '', 45745); -- Spell: 228588 (Ceaseless Winter)
-- Texts
DELETE FROM `creature_text` WHERE `CreatureID` = 114350;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(114350, 0, 0, 'This is who I am. I was tainted from birth, polluted from before my conception, a bad seed grown to bear bitter fruit.', 14, 0, 100, 0, 0, 77556, 123824, 0, 'Shade of Medivh'),
(114350, 1, 0, 'You\'re just like the others, aren\'t you?', 14, 0, 50, 0, 0, 77558, 123832, 0, 'Shade of Medivh to Player'),
(114350, 1, 1, 'Hello, champions. I\'ve been expecting you.', 14, 0, 50, 0, 0, 77552, 123831, 0, 'Shade of Medivh to Player'),
(114350, 2, 0, '|TInterface\\Icons\\spell_mage_infernoblast:20|tYou are targeted by |cFFF00000|Hspell:227615|h[Inferno Bolt]|h|r!', 42, 0, 100, 0, 0, 77558, 123231, 0, 'Shade of Medivh to Player'),
(114350, 3, 0, 'The inherent nature of fire...', 14, 0, 50, 0, 0, 77561, 123812, 0, 'Shade of Medivh'),
(114350, 3, 1, 'Burn... just like that dragon!', 14, 0, 50, 0, 0, 77570, 123813, 0, 'Shade of Medivh'),
(114350, 4, 0, '|TINTERFACE\\ICONS\\SPELL_SHAMAN_IMPROVEDFIRENOVA:20|tShade of Medivh begins to cast |cFFF00000|Hspell:228269|h[Flame Wreath]|h|r!', 41, 0, 100, 0, 0, 77550, 123526, 0, 'Shade of Medivh'),
(114350, 5, 0, 'It burns, burns, burns!', 14, 0, 50, 0, 0, 77550, 123819, 0, 'Shade of Medivh'),
(114350, 5, 1, 'I suggest staying put.', 14, 0, 50, 0, 0, 77566 , 123820, 0, 'Shade of Medivh'),
(114350, 6, 0, 'Winter is here!', 14, 0, 50, 0, 0, 77572, 123821, 0, 'Shade of Medivh'),
(114350, 6, 1, 'Keep still. Let it end.', 14, 0, 50, 0, 0, 77555, 123822, 0, 'Shade of Medivh to Player'),
(114350, 7, 0, 'So many pieces of me...', 14, 0, 50, 0, 0, 77565, 123817, 0, 'Shade of Medivh'),
(114350, 7, 1, 'Carrion for the birds...', 14, 0, 50, 0, 0, 77562, 123818, 0, 'Shade of Medivh'),
(114350, 8, 0, 'A memory, frozen in time!', 14, 0, 100, 0, 0, 77560, 123809, 0, 'Shade of Medivh to Player'),
(114350, 8, 1, 'The tower needed a new decoration.', 14, 0, 100, 0, 0, 77571, 123810, 0, 'Shade of Medivh to Player'),
(114350, 9, 0, 'A basic spell... but effective.', 14, 0, 100, 0, 0, 77549, 123816, 0, 'Shade of Medivh to Player'),
(114350, 10, 0, 'Just. Gets. Easier.', 14, 0, 33, 0, 0, 77551, 123826, 0, 'Shade of Medivh to Player'),
(114350, 10, 1, 'A fitting end for a thief!', 14, 0, 33, 0, 0, 77554, 123829, 0, 'Shade of Medivh to Player'),
(114350, 10, 2, 'All goes as planned.', 14, 0, 33, 0, 0, 77557, 123828, 0, 'Shade of Medivh to Player'),
(114350, 11, 0, 'You grow weaker... I grow stronger!', 14, 0, 100, 0, 0, 77564, 123815, 0, 'Shade of Medivh to Player'),
(114350, 12, 0, 'Once you get used to it, you can kill friends as easily as anyone else.', 14, 0, 50, 0, 0, 77573, 123834, 0, 'Shade of Medivh to Player'),
(114350, 12, 1, 'You have no idea what it\'s like to do the things I\'ve done. Harsh things. Necessary things.', 14, 0, 50, 0, 0, 77559, 123835, 0, 'Shade of Medivh to Player'),
(114350, 13, 0, 'So... it comes... to this...', 14, 0, 33, 0, 0, 77567, 123838, 0, 'Shade of Medivh to Player'),
(114350, 13, 1, 'Atiesh... will be... splintered...', 14, 0, 3, 0, 0, 77569, 123839, 0, 'Shade of Medivh to Player'),
(114350, 13, 2, 'I fought it... for as long as... I could...', 14, 0, 33, 0, 0, 77563, 123836, 0, 'Shade of Medivh to Player'),
(114350, 14, 0, 'My staff... a relic, yes, but MINE!', 14, 0, 100, 0, 0, 77568, 123833, 0, 'Shade of Medivh to Player');
-- Conditions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=228558;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 228558, 0, 0, 51, 0, 5, 114350, 0, '', 0, 0, 0, '', 'Spell \'Reform Visual\' can only hit \'Shade of Medivh\'');
-- Spells
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_shade_of_medivh_arcane_bolt_selector', 'spell_shade_of_medivh_basic_primer', 'spell_shade_of_medivh_ceaseless_winter_periodic', 'spell_shade_of_medivh_flame_wreath_selector', 'spell_shade_of_medivh_guardians_image', 'spell_shade_of_medivh_inferno_bolt_marker', 'spell_shade_of_medivh_mana_regen', 'spell_shade_of_medivh_piercing_missiles', 'spell_shade_of_medivh_signature_primer', 'spell_shade_of_medivh_vo_controller', 'spell_shade_of_medivh_vo_controller_cast');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(228992, 'spell_shade_of_medivh_arcane_bolt_selector'),
(227599, 'spell_shade_of_medivh_basic_primer'),
(228237, 'spell_shade_of_medivh_signature_primer'),
(228222, 'spell_shade_of_medivh_ceaseless_winter_periodic'),
(228269, 'spell_shade_of_medivh_flame_wreath_selector'),
(228334, 'spell_shade_of_medivh_guardians_image'),
(228249, 'spell_shade_of_medivh_inferno_bolt_marker'),
(228582, 'spell_shade_of_medivh_mana_regen'),
(227628, 'spell_shade_of_medivh_piercing_missiles'),
(232314, 'spell_shade_of_medivh_vo_controller'),
(227592, 'spell_shade_of_medivh_vo_controller_cast'),
(227615, 'spell_shade_of_medivh_vo_controller_cast');

View File

@@ -0,0 +1,868 @@
/*
* 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 "Containers.h"
#include "Creature.h"
#include "InstanceScript.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "Position.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "return_to_karazhan.h"
enum ShadeOfMedivhSpells
{
SPELL_ARCANE_CHANNEL = 189573,
SPELL_MANA_REGEN = 228582,
SPELL_VO_CONTROLLER = 232314,
SPELL_BASIC_PRIMER = 227599,
SPELL_INFERNO_BOLT = 227615,
SPELL_INFERNO_BOLT_MARKER = 228249,
SPELL_PIERCING_MISSILES = 227628,
SPELL_PIERCING_MISSILES_DEBUFF = 227644,
SPELL_FROSTBITE = 227592,
SPELL_SIGNATURE_PRIMER = 228237,
SPELL_FLAME_WREATH_SELECTOR = 228269,
SPELL_FLAME_WREATH_AREATRIGGER = 228257,
SPELL_FLAME_WREATH_AREA_DAMAGE = 228262,
SPELL_FLAME_WREATH_PERIODIC_DAMAGE = 228261,
SPELL_CEASELESS_WINTER = 227779,
SPELL_CEASELESS_WINTER_DAMAGE = 227806,
SPELL_CEASELESS_WINTER_PERIODIC = 228222,
SPELL_GUARDIANS_IMAGE = 228334,
SPELL_GUARDIANS_IMAGE_MISSILE = 228338,
SPELL_DISSOLVE = 228572,
SPELL_REFORM_VISUAL = 228558,
SPELL_REFORM_VISUAL_STATE_1 = 228568,
SPELL_REFORM_VISUAL_STATE_2 = 228569,
SPELL_ARCANE_DISSOLVE_IN = 228343,
SPELL_ARCANE_BOLT_SELECTOR = 228992,
SPELL_SHIMMER = 228521
};
enum ShadeOfMedivhEvents
{
EVENT_BASIC_PRIMER = 1,
EVENT_CHECK_MANA,
EVENT_TELEPORT,
EVENT_BACK_TO_COMBAT,
// Guardian's Image
EVENT_ARCANE_BOLT
};
enum ShadeOfMedivhTexts
{
SAY_INTRO = 0, // Implement later
SAY_AGGRO = 1,
SAY_INFERNO_BOLT_WARNING = 2,
SAY_INFERNO_BOLT = 3,
SAY_FLAME_WREATH_WARNING = 4,
SAY_FLAME_WREATH = 5,
SAY_CEASELESS_WINTER = 6,
SAY_GUARDIANS_IMAGE = 7,
SAY_FROSTBITE = 8,
SAY_PIERCING_MISSILES = 9,
SAY_SLAY = 10,
SAY_STRONGER = 11,
SAY_WIPE = 12,
SAY_DEAD = 13,
SAY_SPECIAL = 14 // Used if players have the item Atiesh, Greatstaff of the Guardian
};
enum ShadeOfMedivhActions
{
ACTION_DISSOLVE = 1,
ACTION_FINISH_SPLIT,
ACTION_START_VISUALS
};
enum ShadeOfMedivhDatas
{
DATA_INFERNO_BOLT_NEXT = 0,
};
enum ShadeOfMedivhVisuals
{
SPELLVISUAL_ARCANE_MISSILE = 51100
};
static constexpr Position GuardiansImageMedivhPosition = { -4599.3f, -2517.86f, 2876.59f };
static constexpr Position GuardiansImagePosition[3] =
{
{ -4599.8057f, -2494.7551f, 2876.6255f, 4.694935f },
{ -4618.8994f, -2526.8315f, 2876.6252f, 0.663225f },
{ -4581.1006f, -2526.6892f, 2876.6257f, 2.460914f }
};
static constexpr Position MedivhVisualSpellsPositions[14] =
{
{ -4573.2363f, -2517.875f, 2903.3594f },
{ -4617.39f, -2499.2f, 2886.25f },
{ -4620.2275f, -2535.092f, 2903.4875f },
{ -4573.2363f, -2517.875f, 2885.7869f },
{ -4617.3906f, -2499.1997f, 2902.f },
{ -4598.722f, -2555.3784f, 2906.814f },
{ -4580.137f, -2499.736f, 2887.0764f },
{ -4624.4116f, -2517.2588f, 2886.9016f },
{ -4624.4116f, -2517.2588f, 2904.4302f },
{ -4580.137f, -2499.736f, 2902.3f },
{ -4620.2275f, -2535.092f, 2887.8333f },
{ -4577.932f, -2535.927f, 2902.615f },
{ -4573.2363f, -2517.875f, 2903.3594f },
{ -4577.932f, -2535.927f, 2885.7869f }
};
// 114350 - Shade of Medivh
struct boss_shade_of_medivh : public BossAI
{
boss_shade_of_medivh(Creature* creature) : BossAI(creature, DATA_SHADE_OF_MEDIVH), _triggeredSplit(false), _castInfernoBoltNext(0), _guardiansImageDefeatedCount(0) { }
void JustAppeared() override
{
scheduler.ClearValidator();
DoCastSelf(SPELL_ARCANE_CHANNEL);
me->SetPowerType(POWER_MANA);
me->SetPower(POWER_MANA, 0);
scheduler.Schedule(2s, [this](TaskContext task)
{
static constexpr uint8 VisualCount = 5;
static constexpr float TravelSpeed = 8.0f;
std::vector<Position> positions(std::begin(MedivhVisualSpellsPositions), std::end(MedivhVisualSpellsPositions));
Trinity::Containers::RandomShuffle(positions);
for (uint8 i = 0; i < VisualCount; i++)
{
me->SendPlaySpellVisual(positions[i], SPELLVISUAL_ARCANE_MISSILE, 0, 0, TravelSpeed);
}
task.Repeat(1200ms);
});
}
void JustDied(Unit* /*killer*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_JustDied();
me->RemoveAllAreaTriggers();
Talk(SAY_DEAD);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
Talk(SAY_WIPE);
summons.DespawnAll();
me->RemoveAllAreaTriggers();
_EnterEvadeMode();
_DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
{
if (!victim->IsPlayer())
return;
Talk(SAY_SLAY);
}
void Reset() override
{
events.Reset();
_triggeredSplit = false;
_castInfernoBoltNext = 0;
_guardiansImageDefeatedCount = 0;
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DISSOLVE:
{
DoCastSelf(SPELL_DISSOLVE);
me->RemoveAurasDueToSpell(SPELL_MANA_REGEN);
me->AttackStop();
me->SetUninteractible(true);
me->SetReactState(REACT_PASSIVE);
events.ScheduleEvent(EVENT_TELEPORT, 2s);
events.CancelEvent(EVENT_BASIC_PRIMER);
break;
}
case ACTION_FINISH_SPLIT:
{
_triggeredSplit = false;
_guardiansImageDefeatedCount = 0;
me->RemoveAurasDueToSpell(SPELL_REFORM_VISUAL_STATE_1);
me->RemoveAurasDueToSpell(SPELL_REFORM_VISUAL_STATE_2);
instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me, 1);
events.ScheduleEvent(EVENT_BACK_TO_COMBAT, 2s);
break;
}
default:
break;
}
}
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
{
switch (spellInfo->Id)
{
case SPELL_REFORM_VISUAL:
{
_guardiansImageDefeatedCount++;
if (_guardiansImageDefeatedCount == 1)
DoCastSelf(SPELL_REFORM_VISUAL_STATE_1);
else if (_guardiansImageDefeatedCount == 2)
DoCastSelf(SPELL_REFORM_VISUAL_STATE_2);
else if (_guardiansImageDefeatedCount == 3)
DoAction(ACTION_FINISH_SPLIT);
break;
}
case SPELL_GUARDIANS_IMAGE:
{
if (!_triggeredSplit)
{
_triggeredSplit = true;
DoAction(ACTION_DISSOLVE);
}
break;
}
default:
break;
}
}
void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
{
if (!target->IsPlayer())
return;
switch (spellInfo->Id)
{
case SPELL_PIERCING_MISSILES_DEBUFF:
{
Talk(SAY_PIERCING_MISSILES);
break;
}
case SPELL_INFERNO_BOLT_MARKER:
{
Talk(SAY_INFERNO_BOLT_WARNING, target);
break;
}
default:
break;
}
}
void OnSpellStart(SpellInfo const* spellInfo) override
{
switch (spellInfo->Id)
{
case SPELL_GUARDIANS_IMAGE:
{
Talk(SAY_GUARDIANS_IMAGE);
break;
}
case SPELL_FLAME_WREATH_SELECTOR:
{
Talk(SAY_FLAME_WREATH_WARNING);
Talk(SAY_FLAME_WREATH);
break;
}
case SPELL_CEASELESS_WINTER:
{
Talk(SAY_CEASELESS_WINTER);
break;
}
default:
break;
}
}
void OnSpellFailed(SpellInfo const* spellInfo) override
{
switch (spellInfo->Id)
{
case SPELL_INFERNO_BOLT:
case SPELL_PIERCING_MISSILES:
case SPELL_FROSTBITE:
{
Talk(SAY_STRONGER);
break;
}
default:
break;
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
DoCastSelf(SPELL_VO_CONTROLLER);
DoCastSelf(SPELL_MANA_REGEN, TRIGGERED_FULL_MASK);
scheduler.CancelAll();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
events.ScheduleEvent(EVENT_BASIC_PRIMER, 3s);
events.ScheduleEvent(EVENT_CHECK_MANA, 1s);
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BASIC_PRIMER:
{
DoCastSelf(SPELL_BASIC_PRIMER);
events.Repeat(6s);
break;
}
case EVENT_CHECK_MANA:
{
if (me->GetPowerPct(POWER_MANA) >= 100)
DoCastSelf(SPELL_SIGNATURE_PRIMER);
events.Repeat(500ms);
break;
}
case EVENT_TELEPORT:
{
me->NearTeleportTo(GuardiansImageMedivhPosition);
break;
}
case EVENT_BACK_TO_COMBAT:
{
me->RemoveAurasDueToSpell(SPELL_DISSOLVE);
me->SetUninteractible(false);
me->SetReactState(REACT_AGGRESSIVE);
DoCastSelf(SPELL_MANA_REGEN);
events.ScheduleEvent(EVENT_BASIC_PRIMER, 1s);
break;
}
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
uint32 GetData(uint32 id) const override
{
if (id == DATA_INFERNO_BOLT_NEXT)
return _castInfernoBoltNext;
return 0;
}
void SetData(uint32 id, uint32 value) override
{
if (id == DATA_INFERNO_BOLT_NEXT)
_castInfernoBoltNext = value;
}
private:
bool _triggeredSplit;
uint8 _castInfernoBoltNext;
uint8 _guardiansImageDefeatedCount;
};
// 114675 - Guardian's Image
struct boss_shade_of_medivh_guardians_image : public ScriptedAI
{
boss_shade_of_medivh_guardians_image(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoCastSelf(SPELL_ARCANE_DISSOLVE_IN);
DoZoneInCombat();
}
void JustDied(Unit* /*killer*/) override
{
me->GetInstanceScript()->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
DoCast(SPELL_REFORM_VISUAL);
me->DespawnOrUnsummon(3s);
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* shadeOfMedivh = me->GetInstanceScript()->GetCreature(DATA_SHADE_OF_MEDIVH))
shadeOfMedivh->AI()->EnterEvadeMode(why);
}
void JustEngagedWith(Unit* /*who*/) override
{
me->GetInstanceScript()->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
DoCastSelf(SPELL_SHIMMER);
events.ScheduleEvent(EVENT_ARCANE_BOLT, 1s);
}
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_ARCANE_BOLT:
{
DoCastSelf(SPELL_ARCANE_BOLT_SELECTOR);
events.Repeat(3s);
break;
}
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
EventMap events;
};
// 228582 - Mana Regen
class spell_shade_of_medivh_mana_regen : public AuraScript
{
static constexpr std::array<uint8, 3> ShadeOfMedivhEnergizeCycle = { 3, 4, 3 };
void PeriodicTick(AuraEffect const* aurEff) const
{
uint8 cycleIdx = (aurEff->GetTickNumber() - 1) % ShadeOfMedivhEnergizeCycle.size();
int32 amount = ShadeOfMedivhEnergizeCycle[cycleIdx] * GetTarget()->GetMaxPower(POWER_MANA) / 100;
GetTarget()->ModifyPower(POWER_MANA, amount);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shade_of_medivh_mana_regen::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 227599 - Basic Primer
class spell_shade_of_medivh_basic_primer : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_INFERNO_BOLT_MARKER, SPELL_PIERCING_MISSILES, SPELL_FROSTBITE });
}
void HandleHit()
{
Creature* creatureCaster = GetCaster()->ToCreature();
if (!creatureCaster)
return;
Unit* target = creatureCaster->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true);
uint32 spellId = RAND(SPELL_INFERNO_BOLT_MARKER, SPELL_PIERCING_MISSILES, SPELL_FROSTBITE);
if (creatureCaster->AI()->GetData(DATA_INFERNO_BOLT_NEXT) == 1)
{
spellId = SPELL_INFERNO_BOLT_MARKER;
creatureCaster->AI()->SetData(DATA_INFERNO_BOLT_NEXT, 0);
}
else if (spellId == SPELL_FROSTBITE)
creatureCaster->AI()->SetData(DATA_INFERNO_BOLT_NEXT, 1);
creatureCaster->CastSpell(target, spellId, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnHit += SpellHitFn(spell_shade_of_medivh_basic_primer::HandleHit);
}
};
// 228237 - Signature Primer
class spell_shade_of_medivh_signature_primer : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FLAME_WREATH_SELECTOR, SPELL_GUARDIANS_IMAGE, SPELL_CEASELESS_WINTER });
}
void HandleHit() const
{
Creature* creatureCaster = GetCaster()->ToCreature();
if (!creatureCaster)
return;
uint32 spellId = RAND(SPELL_FLAME_WREATH_SELECTOR, SPELL_GUARDIANS_IMAGE, SPELL_CEASELESS_WINTER);
creatureCaster->CastSpell(creatureCaster, spellId, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void HandleAfterCast() const
{
GetCaster()->SetPower(POWER_MANA, 0);
}
void Register() override
{
OnHit += SpellHitFn(spell_shade_of_medivh_signature_primer::HandleHit);
AfterCast += SpellCastFn(spell_shade_of_medivh_signature_primer::HandleAfterCast);
}
};
// 228249 - Inferno Bolt
class spell_shade_of_medivh_inferno_bolt_marker : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_INFERNO_BOLT });
}
void HandleInfernoBolt(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_INFERNO_BOLT, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_shade_of_medivh_inferno_bolt_marker::HandleInfernoBolt, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
};
// 227628 - Piercing Missiles
class spell_shade_of_medivh_piercing_missiles : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PIERCING_MISSILES_DEBUFF });
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
GetCaster()->CastSpell(GetTarget(), SPELL_PIERCING_MISSILES_DEBUFF, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_shade_of_medivh_piercing_missiles::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
// 228269 - Flame Wreath
class spell_shade_of_medivh_flame_wreath_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FLAME_WREATH_AREATRIGGER });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit()->GetPosition(), SPELL_FLAME_WREATH_AREATRIGGER, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_shade_of_medivh_flame_wreath_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 228222 - Ceaseless Winter
class spell_shade_of_medivh_ceaseless_winter_periodic : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_CEASELESS_WINTER_DAMAGE });
}
void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) const
{
Unit* target = GetTarget();
if (target->isMoving())
GetTarget()->RemoveAuraFromStack(SPELL_CEASELESS_WINTER_DAMAGE);
else
target->CastSpell(target, SPELL_CEASELESS_WINTER_DAMAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shade_of_medivh_ceaseless_winter_periodic::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 228334 - Guardian's Image
class spell_shade_of_medivh_guardians_image : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_GUARDIANS_IMAGE_MISSILE });
}
void HandleHit() const
{
for (uint8 i = 0; i < 3; i++)
{
GetCaster()->CastSpell(GuardiansImagePosition[i], SPELL_GUARDIANS_IMAGE_MISSILE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
}
void Register() override
{
OnHit += SpellHitFn(spell_shade_of_medivh_guardians_image::HandleHit);
}
};
// 228992 - Arcane Bolt
class spell_shade_of_medivh_arcane_bolt_selector : public SpellScript
{
void HandleScript(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), GetEffectValue(), CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell(),
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_shade_of_medivh_arcane_bolt_selector::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 232314 - V.O Controller
class spell_shade_of_medivh_vo_controller : public SpellScript
{
void HandleScript(SpellEffIndex /*effIndex*/) const
{
uint8 text = 0;
ObjectGuid originalCast = GetSpell()->m_originalCastId;
if (!originalCast.IsEmpty())
{
switch (originalCast.GetEntry())
{
case SPELL_FROSTBITE:
{
text = SAY_FROSTBITE;
break;
}
case SPELL_INFERNO_BOLT:
{
text = SAY_INFERNO_BOLT;
break;
}
default:
break;
}
}
else
text = SAY_AGGRO;
if (Creature* shadeOfMedivh = GetHitUnit()->ToCreature())
shadeOfMedivh->AI()->Talk(text);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_shade_of_medivh_vo_controller::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
};
// 232314 - V.O Controller (attached to 227592 - Frostbite and 227615 - Inferno Bolt)
class spell_shade_of_medivh_vo_controller_cast : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_VO_CONTROLLER });
}
void HandleAfterCast() const
{
Unit* caster = GetCaster();
if (caster->HasAura(SPELL_VO_CONTROLLER))
return;
caster->CastSpell(caster, SPELL_VO_CONTROLLER, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell(),
});
}
void Register() override
{
AfterCast += SpellCastFn(spell_shade_of_medivh_vo_controller_cast::HandleAfterCast);
}
};
// 227779 - Ceaseless Winter
// Id - 8848
struct at_shade_of_medivh_ceaseless_winter : AreaTriggerAI
{
using AreaTriggerAI::AreaTriggerAI;
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
unit->CastSpell(unit, SPELL_CEASELESS_WINTER_PERIODIC, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
unit->RemoveAurasDueToSpell(SPELL_CEASELESS_WINTER_DAMAGE);
unit->RemoveAurasDueToSpell(SPELL_CEASELESS_WINTER_PERIODIC);
}
private:
TaskScheduler _scheduler;
};
// 227779 - Ceaseless Winter
// Id - 8809
struct at_shade_of_medivh_ceaseless_winter_jump_check : AreaTriggerAI
{
using AreaTriggerAI::AreaTriggerAI;
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
unit->RemoveAuraFromStack(SPELL_CEASELESS_WINTER_DAMAGE);
}
};
// 228257 - Flame Wreath
struct at_shade_of_medivh_flame_wreath : AreaTriggerAI
{
using AreaTriggerAI::AreaTriggerAI;
uint32 GetInsidePlayersCount()
{
return std::ranges::count_if(at->GetInsideUnits(), [this](ObjectGuid const& guid)
{
Player* player = ObjectAccessor::GetPlayer(*at, guid);
if (!player || !player->IsAlive() || player->IsGameMaster())
return false;
return true;
});
}
void OnUnitEnter(Unit* unit) override
{
Unit* caster = at->GetCaster();
if (!caster)
return;
if (!unit->IsPlayer())
return;
if (GetInsidePlayersCount() >= 2)
{
caster->CastSpell(unit, SPELL_FLAME_WREATH_AREA_DAMAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
at->Remove();
}
else
caster->CastSpell(unit, SPELL_FLAME_WREATH_PERIODIC_DAMAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
Unit* caster = at->GetCaster();
if (!caster)
return;
if (!unit->IsPlayer())
return;
if (unit->HasAura(SPELL_FLAME_WREATH_PERIODIC_DAMAGE))
{
unit->RemoveAurasDueToSpell(SPELL_FLAME_WREATH_PERIODIC_DAMAGE);
caster->CastSpell(unit, SPELL_FLAME_WREATH_AREA_DAMAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
at->Remove();
}
}
};
void AddSC_boss_shade_of_medivh()
{
RegisterReturnToKarazhanCreatureAI(boss_shade_of_medivh);
RegisterReturnToKarazhanCreatureAI(boss_shade_of_medivh_guardians_image);
RegisterSpellScript(spell_shade_of_medivh_mana_regen);
RegisterSpellScript(spell_shade_of_medivh_piercing_missiles);
RegisterSpellScript(spell_shade_of_medivh_basic_primer);
RegisterSpellScript(spell_shade_of_medivh_signature_primer);
RegisterSpellScript(spell_shade_of_medivh_inferno_bolt_marker);
RegisterSpellScript(spell_shade_of_medivh_flame_wreath_selector);
RegisterSpellScript(spell_shade_of_medivh_ceaseless_winter_periodic);
RegisterSpellScript(spell_shade_of_medivh_guardians_image);
RegisterSpellScript(spell_shade_of_medivh_arcane_bolt_selector);
RegisterSpellScript(spell_shade_of_medivh_vo_controller);
RegisterSpellScript(spell_shade_of_medivh_vo_controller_cast);
RegisterAreaTriggerAI(at_shade_of_medivh_ceaseless_winter_jump_check);
RegisterAreaTriggerAI(at_shade_of_medivh_ceaseless_winter);
RegisterAreaTriggerAI(at_shade_of_medivh_flame_wreath);
}

View File

@@ -22,7 +22,8 @@
BossBoundaryData const boundaries =
{
{ DATA_MAIDEN_OF_VIRTUE_RTK, new CircleBoundary(Position(-10945.900391f, -2103.530029f, 92.794197f), 55.0f) }
{ DATA_MAIDEN_OF_VIRTUE_RTK, new CircleBoundary(Position(-10945.900391f, -2103.530029f, 92.794197f), 55.0f) },
{ DATA_SHADE_OF_MEDIVH, new CircleBoundary(Position(-4599.149902f, -2517.947266f, 2876.506836f), 35.0f) },
};
ObjectData const creatureData[] =
@@ -35,8 +36,10 @@ ObjectData const creatureData[] =
DoorData const doorData[] =
{
{ GO_STRANGE_WALL, DATA_THE_CURATOR_RTK, EncounterDoorBehavior::OpenWhenDone },
{ 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress }
{ GO_STRANGE_WALL, DATA_THE_CURATOR_RTK, EncounterDoorBehavior::OpenWhenDone },
{ GO_SUSPICIOUS_BOOKCASE, DATA_SHADE_OF_MEDIVH, EncounterDoorBehavior::OpenWhenDone },
{ GO_MEDIVH_DOOR, DATA_SHADE_OF_MEDIVH, EncounterDoorBehavior::OpenWhenNotInProgress },
{ 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress }
};
DungeonEncounterData const encounters[] =

View File

@@ -49,7 +49,9 @@ enum RTKCreatureIds
enum RTKGameObjectsIds
{
GO_STRANGE_WALL = 266508
GO_STRANGE_WALL = 266508,
GO_SUSPICIOUS_BOOKCASE = 266510,
GO_MEDIVH_DOOR = 266846
};
template <class AI, class T>

View File

@@ -211,6 +211,7 @@ void AddSC_instance_return_to_karazhan();
void AddSC_boss_maiden_of_virtue_rtk();
void AddSC_boss_the_curator_rtk();
void AddSC_boss_mana_devourer();
void AddSC_boss_shade_of_medivh();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
@@ -412,4 +413,5 @@ void AddEasternKingdomsScripts()
AddSC_boss_maiden_of_virtue_rtk();
AddSC_boss_the_curator_rtk();
AddSC_boss_mana_devourer();
AddSC_boss_shade_of_medivh();
}