Scripts/MawOfSouls: Implemented Ymiron, the Fallen King encounter (#29987)

This commit is contained in:
ModoX
2024-05-22 16:00:48 +02:00
committed by GitHub
parent 7f077e72bd
commit 5f5871708f
6 changed files with 974 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
--
SET @ATID := 65;
SET @ATSPAWNID := 67;
SET @ATCP := 53;
DELETE FROM `areatrigger` WHERE `SpawnId`=@ATSPAWNID+0;
INSERT INTO `areatrigger` (`SpawnId`, `AreaTriggerCreatePropertiesId`, `IsCustom`, `MapId`, `SpawnDifficulties`, `PosX`, `PosY`, `PosZ`, `Orientation`, `PhaseUseFlags`, `PhaseId`, `PhaseGroup`, `ScriptName`, `Comment`, `VerifiedBuild`) VALUES
(@ATSPAWNID+0, @ATCP+0, 1, 1492, '1,2,8,23', 7380.5766, 7289.9389, 43.8447, 2.8720, 1, 0, 0, 'at_ymiron_the_fallen_king_activation', 'Maw of Souls - Ymiron Activation Trigger', 0);
DELETE FROM `areatrigger_create_properties` WHERE `Id`=@ATCP+0 AND `IsCustom`=1;
INSERT INTO `areatrigger_create_properties` (`Id`, `IsCustom`, `AreaTriggerId`, `IsAreatriggerCustom`, `Flags`, `MoveCurveId`, `ScaleCurveId`, `MorphCurveId`, `FacingCurveId`, `AnimId`, `AnimKitId`, `DecalPropertiesId`, `TimeToTarget`, `TimeToTargetScale`, `Shape`, `ShapeData0`, `ShapeData1`, `ShapeData2`, `ShapeData3`, `ShapeData4`, `ShapeData5`, `ShapeData6`, `ShapeData7`, `ScriptName`, `VerifiedBuild`) VALUES
(@ATCP+0, 1, @ATID+0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 4, 35, 35, 5, 5, 0, 0, 0, 0, '', 0);
DELETE FROM `areatrigger_template` WHERE `Id`=@ATID+0 AND `IsCustom`=1;
INSERT INTO `areatrigger_template` (`Id`, `IsCustom`, `Flags`, `VerifiedBuild`) VALUES
(@ATID+0, 1, 1, 0);
UPDATE `creature_model_info` SET `VerifiedBuild`=52129 WHERE `DisplayID` IN (30076, 66346, 66348, 66681, 66345, 66238, 66121, 70528, 66688, 64208, 66852, 26725, 66184, 106378, 67556, 30710, 70529, 66102, 66181, 67179, 66183, 66103, 65823, 64467, 64200, 28120, 28118, 65214, 67001, 65079, 21342, 66119, 25801, 27824, 66091, 11686, 16925, 66090, 25630);
UPDATE `creature_model_info` SET `BoundingRadius`=10.46424579620361328, `VerifiedBuild`=52129 WHERE `DisplayID`=65778;
UPDATE `creature_model_info` SET `BoundingRadius`=52.32122802734375, `VerifiedBuild`=52129 WHERE `DisplayID`=66680;
UPDATE `creature_model_info` SET `BoundingRadius`=13.0803070068359375, `VerifiedBuild`=52129 WHERE `DisplayID`=66618;
UPDATE `creature_model_info` SET `BoundingRadius`=31.39273834228515625, `VerifiedBuild`=52129 WHERE `DisplayID`=67211;
DELETE FROM `areatrigger_create_properties_orbit` WHERE (`AreaTriggerCreatePropertiesId`=5838 AND `IsCustom`=0);
INSERT INTO `areatrigger_create_properties_orbit` (`AreaTriggerCreatePropertiesId`, `IsCustom`, `StartDelay`, `CircleRadius`, `BlendFromRadius`, `InitialAngle`, `ZOffset`, `CounterClockwise`, `CanLoop`, `VerifiedBuild`) VALUES
(5838, 0, 0, 0, 0, 0, 0, 0, 1, 52129); -- Spell: 193465 (Bane)
DELETE FROM `areatrigger_create_properties` WHERE (`IsCustom`=0 AND `Id` IN (5838));
INSERT INTO `areatrigger_create_properties` (`Id`, `IsCustom`, `AreaTriggerId`, `IsAreatriggerCustom`, `Flags`, `MoveCurveId`, `ScaleCurveId`, `MorphCurveId`, `FacingCurveId`, `AnimId`, `AnimKitId`, `DecalPropertiesId`, `TimeToTarget`, `TimeToTargetScale`, `Shape`, `ShapeData0`, `ShapeData1`, `ShapeData2`, `ShapeData3`, `ShapeData4`, `ShapeData5`, `ShapeData6`, `ShapeData7`, `VerifiedBuild`) VALUES
(5838, 0, 10407, 0, 0, 0, 0, 0, 0, -1, 0, 26, 11863, 21000, 0, 2, 2, 0, 0, 0, 0, 0, 0, 52129); -- Spell: 193465 (Bane)
UPDATE `areatrigger_create_properties` SET `ScriptName`='at_ymiron_the_fallen_king_bane' WHERE `Id`=5838 AND `IsCustom`=0;
UPDATE `areatrigger_template` SET `Flags`=0, `VerifiedBuild`=52129 WHERE (`Id`=10407 AND `IsCustom`=0);
-- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DELETE FROM `instance_template` WHERE `map`=1492;
INSERT INTO `instance_template` (`map`, `parent`, `script`) VALUES
(1492, 0, 'instance_maw_of_souls');
UPDATE `creature_template` SET `AIName`='', `ScriptName`='boss_ymiron_the_fallen_king' WHERE `entry`=96756;
UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_ymiron_the_fallen_king_risen_warrior' WHERE `entry`=98246;
UPDATE `creature_template_addon` SET `auras`='342788' WHERE `entry`=96756; -- remove kneeling from template
UPDATE `creature` SET `equipment_id`=-1 WHERE `guid`=650507; -- add weapon to ymiron
UPDATE `creature_template` SET `faction`=16, `speed_run`=0.857142865657806396, `BaseAttackTime`=1500, `unit_flags`=32768, `unit_flags2`=2099200, `unit_flags3`=524288 WHERE `entry`=98246; -- Risen Warrior
DELETE FROM `creature_template_addon` WHERE `entry`=98246;
INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES
(98246, '123978');
SET @PATHID := 9675600;
DELETE FROM `waypoint_path` WHERE `PathId` BETWEEN @PATHID+0 AND @PATHID+1;
INSERT INTO `waypoint_path` (`PathId`, `MoveType`, `Flags`, `Velocity`, `Comment`) VALUES
(@PATHID+0, 0, 0, NULL, 'Ymiron - Intro Path towards Runecarver Slaves'),
(@PATHID+1, 0, 0, NULL, 'Ymiron - Intro Path away from Runecarver Slaves');
DELETE FROM `waypoint_path_node` WHERE `PathId` BETWEEN @PATHID+0 AND @PATHID+1;
INSERT INTO `waypoint_path_node` (`PathId`, `NodeId`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `Delay`) VALUES
(@PATHID+0, 0, 7400.461, 7288.4614, 44.063484, NULL, 0),
(@PATHID+0, 1, 7398.961, 7291.4614, 44.063484, NULL, 0),
(@PATHID+0, 2, 7394.7075, 7295.432, 43.7841, NULL, 0),
(@PATHID+1, 0, 7397.9185, 7286.777, 43.79471, NULL, 0),
(@PATHID+1, 1, 7398.374, 7277.1206, 43.792637, 5.724679946899414062, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` IN (243029));
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `Comment`) VALUES
(13, 0x1|0x2|0x4, 243029, 0, 0, 51, 0, 5, 114712, 0, '', 0, 'Potential target of the spell is creature, entry is Runecarver Slave (114712)');
DELETE FROM `serverside_spell` WHERE `Id`=193510;
INSERT INTO `serverside_spell` (`Id`, `DifficultyID`, `CategoryId`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `AttributesEx8`, `AttributesEx9`, `AttributesEx10`, `AttributesEx11`, `AttributesEx12`, `AttributesEx13`, `AttributesEx14`, `Stances`, `StancesNot`, `Targets`, `TargetCreatureType`, `RequiresSpellFocus`, `FacingCasterFlags`, `CasterAuraState`, `TargetAuraState`, `ExcludeCasterAuraState`, `ExcludeTargetAuraState`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CasterAuraType`, `TargetAuraType`, `ExcludeCasterAuraType`, `ExcludeTargetAuraType`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `StartRecoveryCategory`, `StartRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags1`, `AuraInterruptFlags2`, `ChannelInterruptFlags1`, `ChannelInterruptFlags2`, `ProcFlags`, `ProcFlags2`, `ProcChance`, `ProcCharges`, `ProcCooldown`, `ProcBasePPM`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `RangeIndex`, `Speed`, `LaunchDelay`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `ContentTuningId`, `SpellName`, `ConeAngle`, `ConeWidth`, `MaxTargetLevel`, `MaxAffectedTargets`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `SpellFamilyFlags4`, `DmgClass`, `PreventionType`, `AreaGroupId`, `SchoolMask`, `ChargeCategoryId`) VALUES
(193510, 0, 0, 0, 0, 0x100, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 1, 0, 0, 0, -1, 0, 0, 0, 'Arise, Fallen', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
DELETE FROM `serverside_spell_effect` WHERE `SpellID`=193510;
INSERT INTO `serverside_spell_effect` (`SpellID`, `EffectIndex`, `DifficultyID`, `Effect`, `EffectAura`, `EffectAmplitude`, `EffectAttributes`, `EffectAuraPeriod`, `EffectBonusCoefficient`, `EffectChainAmplitude`, `EffectChainTargets`, `EffectItemType`, `EffectMechanic`, `EffectPointsPerResource`, `EffectPosFacing`, `EffectRealPointsPerLevel`, `EffectTriggerSpell`, `BonusCoefficientFromAP`, `PvpMultiplier`, `Coefficient`, `Variance`, `ResourceCoefficient`, `GroupSizeBasePointsCoefficient`, `EffectBasePoints`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectSpellClassMask1`, `EffectSpellClassMask2`, `EffectSpellClassMask3`, `EffectSpellClassMask4`, `ImplicitTarget1`, `ImplicitTarget2`) VALUES
(193510, 0, 0, 6, 4, 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, 1, 0);
DELETE FROM `spell_script_names` WHERE `spell_id` IN(167922, 193460, 243029, 193566);
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(167922, 'spell_ymiron_the_fallen_king_power_periodic'),
(193460, 'spell_ymiron_the_fallen_king_bane_periodic'),
(243029, 'spell_ymiron_the_fallen_king_soul_siphon'),
(193566, 'spell_ymiron_the_fallen_king_arise_fallen_selector');
DELETE FROM `creature_text` WHERE `CreatureID`=96756;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(96756, 0, 0, 'Your souls will drift for eternity in the tides of the underworld!', 14, 0, 100, 0, 0, 54404, 102193, 0, 'Ymiron, the Fallen King to Player'),
(96756, 1, 0, 'Another drop in the sea of souls!', 14, 0, 100, 66, 0, 54367, 102185, 0, 'Ymiron, the Fallen King to Player'),
(96756, 2, 0, 'Mortals... I fell to your wretched kind once before. It WILL NOT happen again!', 14, 0, 100, 0, 0, 54403, 102191, 0, 'Ymiron, the Fallen King to Player'),
(96756, 3, 0, 'FLEE, COWARDS!', 14, 0, 100, 0, 0, 54360, 102175, 0, 'Ymiron, the Fallen King'),
(96756, 3, 1, 'COWER BEFORE ME!', 14, 0, 100, 0, 0, 54359, 102174, 0, 'Ymiron, the Fallen King'),
(96756, 3, 2, 'CRAVEN MAGGOTS!', 14, 0, 100, 0, 0, 54361, 102176, 0, 'Ymiron, the Fallen King'),
(96756, 4, 0, 'Know the bitter chill of death as I have!', 14, 0, 100, 0, 0, 54362, 102177, 0, 'Ymiron, the Fallen King'),
(96756, 4, 1, 'The winds of the frozen north still howl in these veins!', 14, 0, 100, 0, 0, 54364, 102178, 0, 'Ymiron, the Fallen King'),
(96756, 5, 0, 'The shadows of the underworld bend to me!', 14, 0, 100, 0, 0, 54357, 102171, 0, 'Ymiron, the Fallen King'),
(96756, 6, 0, 'The shadows of Helheim cut deeper than steel!', 14, 0, 100, 0, 0, 54358, 102173, 0, 'Ymiron, the Fallen King'),
(96756, 7, 0, 'Not... again... HARBARON! CAST THEIR SOULS INTO THE TIDES!', 14, 0, 100, 0, 0, 54366, 102182, 0, 'Ymiron, the Fallen King to Player');
UPDATE `creature_template_difficulty` SET `StaticFlags2`=`StaticFlags2`|0x02|0x04 WHERE `Entry`=96756;

View File

@@ -4696,6 +4696,22 @@ void SpellMgr::LoadSpellInfoCorrections()
// ENDOF MARDUM SPELLS
//
// MAW OF SOULS SPELLS
//
// 193465 - Bane
ApplySpellFix({ 193465 }, [](SpellInfo* spellInfo)
{
ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
{
// Normal difficulty should also be using the regular heroic+ AreaTriggerCreateProperties
spellEffectInfo->MiscValue = 5838;
});
});
// ENDOF MAW OF SOULS SPELLS
//
// ANTORUS THE BURNING THRONE SPELLS
//

View File

@@ -0,0 +1,723 @@
/*
* 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 "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "InstanceScript.h"
#include "Map.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "SharedDefines.h"
#include "TemporarySummon.h"
#include "maw_of_souls.h"
enum YmironFallenKingSpells
{
// Intro
SPELL_SOUL_SIPHON = 243029,
SPELL_SOUL_SIPHON_CHANNEL = 194665,
SPELL_KNEELING = 197227,
SPELL_SUICIDE = 117624,
SPELL_POWER = 167922,
SPELL_DARK_SLASH = 193211,
SPELL_SCREAMS_OF_THE_DEAD = 193364,
SPELL_WINDS_OF_NORTHREND = 193977,
SPELL_BANE_AURA = 193460,
SPELL_BANE_MISSILE = 193463,
SPELL_BANE_AT_NHC_HEROIC = 193465,
SPELL_BANE_DAMAGE = 193513, // only on triggering unit of Bane
SPELL_BANE_NOVA = 200194, // AoE on party when Bane orb is triggered
SPELL_ARISE_FALLEN_ENABLER = 193510,
SPELL_ARISE_FALLEN_SELECTOR = 193566,
SPELL_ARISE_FALLEN_SUMMON = 193594,
SPELL_DESPAWN_AREA_TRIGGERS = 115905,
SPELL_VIGOR = 203816, // stacking every 6s
};
enum YmironFallenKingSpellVisuals
{
SPELL_VISUAL_SOUL_SIPHON = 52528,
SPELL_VISUAL_BANE_PRECAST = 50121,
SPELL_VISUAL_ARISE_FALLEN = 50259,
SPELL_VISUAL_KIT_ARISE_FALLEN = 59548,
};
enum YmironFallenKingEvents
{
EVENT_DARK_SLASH_CHECKER = 1,
EVENT_SCREAMS_OF_THE_DEAD,
EVENT_WINDS_OF_NORTHREND,
EVENT_BANE,
EVENT_ARISE_FALLEN
};
enum YmironFallenKingTexts
{
SAY_INTRO1 = 0, // Your souls will drift for eternity in the tides of the underworld!
SAY_INTRO2 = 1, // Another drop in the sea of souls!
SAY_AGGRO = 2, // Mortals... I fell to your wretched kind once before. It WILL NOT happen again!
SAY_SCREAMS_OF_THE_DEAD = 3, // COWER BEFORE ME!
SAY_WINDS_OF_NORTHREND = 4, // Know the bitter chill of death as I have!
SAY_BANE = 5, // The shadows of the underworld bend to me!
SAY_ARISE_FALLEN = 6, // The shadows of Helheim cut deeper than steel!
SAY_DEATH = 7, // Not... again... HARBARON! CAST THEIR SOULS INTO THE TIDES!
};
enum YmironFallenKingActions
{
ACTION_ACTIVATE = 1,
};
enum YmironFallenKingPaths
{
PATH_INTRO_TOWARDS_SLAVES = 9675600,
PATH_INTRO_AWAY_FROM_SLAVES = 9675601
};
constexpr Position YmironIntroJumpPos = { 7401.39f, 7281.7f, 44.0207f };
constexpr Position YmironRespawnPos = { 7398.374f, 7277.1206f, 43.792637f, 5.724679946899414062f };
// 96756 - Ymiron, the Fallen King
struct boss_ymiron_the_fallen_king : public BossAI
{
boss_ymiron_the_fallen_king(Creature* creature) : BossAI(creature, DATA_YMIRON), _firstScreamDone(false) { }
void JustAppeared() override
{
scheduler.ClearValidator();
DoCastSelf(SPELL_KNEELING);
me->SetPower(me->GetPowerType(), 80);
}
void InitializeAI() override
{
if (instance->GetBossState(DATA_YMIRON) != NOT_STARTED)
me->Relocate(YmironRespawnPos);
}
void Reset() override
{
BossAI::Reset();
_firstScreamDone = false;
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
me->InterruptNonMeleeSpells(true);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
Talk(SAY_AGGRO);
DoCastAOE(SPELL_POWER);
scheduler.CancelAll();
// should turn to highest threat target after standing up
if (me->HasAura(SPELL_KNEELING))
{
me->RemoveAurasDueToSpell(SPELL_KNEELING);
me->SetReactState(REACT_PASSIVE);
scheduler.Schedule(1600ms, [this](TaskContext /*task*/)
{
me->SetReactState(REACT_AGGRESSIVE);
});
}
events.ScheduleEvent(EVENT_DARK_SLASH_CHECKER, 500ms);
events.ScheduleEvent(EVENT_SCREAMS_OF_THE_DEAD, 5900ms);
events.ScheduleEvent(EVENT_WINDS_OF_NORTHREND, 15100ms);
events.ScheduleEvent(EVENT_BANE, 22100ms);
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DARK_SLASH_CHECKER:
{
if (me->GetPower(me->GetPowerType()) >= 100)
{
DoCastVictim(SPELL_DARK_SLASH);
me->SetPower(me->GetPowerType(), 0);
}
events.Repeat(500ms);
break;
}
case EVENT_SCREAMS_OF_THE_DEAD:
{
if (_firstScreamDone)
Talk(SAY_SCREAMS_OF_THE_DEAD);
else
_firstScreamDone = true;
DoCastAOE(SPELL_SCREAMS_OF_THE_DEAD);
events.Repeat(31s);
break;
}
case EVENT_WINDS_OF_NORTHREND:
Talk(SAY_WINDS_OF_NORTHREND);
DoCastAOE(SPELL_WINDS_OF_NORTHREND);
events.Repeat(29s);
break;
case EVENT_BANE:
{
Talk(SAY_BANE);
DoCastAOE(SPELL_BANE_AURA);
if (IsHeroicOrHigher())
events.ScheduleEvent(EVENT_ARISE_FALLEN, 19100ms);
events.Repeat(59s);
break;
}
case EVENT_ARISE_FALLEN:
Talk(SAY_ARISE_FALLEN);
DoCastAOE(SPELL_ARISE_FALLEN_ENABLER);
DoCastAOE(SPELL_ARISE_FALLEN_SELECTOR);
break;
default:
break;
}
}
}
void DoAction(int32 param) override
{
if (param != ACTION_ACTIVATE)
return;
me->RemoveAurasDueToSpell(SPELL_KNEELING);
scheduler.Schedule(2s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MoveJumpWithGravity(YmironIntroJumpPos, 24.0f, 25.31545448303222656, EVENT_JUMP);
});
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId != EVENT_JUMP)
return;
scheduler.Schedule(1500ms, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_INTRO_TOWARDS_SLAVES, false);
});
}
void OnChannelFinished(SpellInfo const* spell) override
{
if (spell->Id != SPELL_SOUL_SIPHON_CHANNEL)
return;
scheduler.Schedule(2s, [this](TaskContext task)
{
Talk(SAY_INTRO2);
task.Schedule(5s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_INTRO_AWAY_FROM_SLAVES, false);
});
});
}
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (me->IsInCombat())
return;
if (pathId == PATH_INTRO_TOWARDS_SLAVES)
{
scheduler.Schedule(2s, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_SOUL_SIPHON_CHANNEL);
Talk(SAY_INTRO1);
});
}
else if (pathId == PATH_INTRO_AWAY_FROM_SLAVES)
{
DoCastSelf(SPELL_KNEELING);
}
}
private:
bool _firstScreamDone;
};
// Maw of Souls - Ymiron Activation Trigger
struct at_ymiron_the_fallen_king_activation : AreaTriggerAI
{
at_ymiron_the_fallen_king_activation(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
Player* player = unit->ToPlayer();
if (!player)
return;
if (player->IsGameMaster())
return;
InstanceScript* instance = at->GetInstanceScript();
if (!instance)
return;
Creature* ymiron = instance->GetCreature(DATA_YMIRON);
if (!ymiron)
return;
ymiron->AI()->DoAction(ACTION_ACTIVATE);
at->Remove();
}
};
class YmironSoulSiphonVisual : public BasicEvent
{
public:
explicit YmironSoulSiphonVisual(ObjectGuid ymironGUID, Unit* runecarver, float travelSpeed) : _ymironGUID(ymironGUID), _runecarver(runecarver), _travelSpeed(travelSpeed) { }
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
if (_runecarver->isDead())
return true;
Unit* ymiron = ObjectAccessor::GetCreature(*_runecarver, _ymironGUID);
if (!ymiron)
return true;
_runecarver->SendPlaySpellVisual(ymiron->GetPosition(), SPELL_VISUAL_SOUL_SIPHON, 0, 0, _travelSpeed, false, 0.0f);
_runecarver->m_Events.AddEventAtOffset(this, 400ms);
return false;
}
private:
ObjectGuid _ymironGUID;
Unit* _runecarver;
float _travelSpeed;
};
// 243029 - Soul Siphon
class spell_ymiron_the_fallen_king_soul_siphon : public AuraScript
{
void OnAfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
float travelSpeed = 15 + 0.180f * caster->GetDistance(GetTarget());
GetTarget()->m_Events.AddEventAtOffset(new YmironSoulSiphonVisual(caster->GetGUID(), GetTarget(), travelSpeed), 1s);
}
void TriggerSuicide()
{
Creature* targetCreature = GetTarget()->ToCreature();
if (!targetCreature)
return;
targetCreature->CastSpell(nullptr, SPELL_SUICIDE, true);
targetCreature->DespawnOrUnsummon(20s);
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
if (!roll_chance_f(10))
return;
TriggerSuicide();
}
void OnAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
TriggerSuicide();
}
void Register() override
{
AfterEffectApply += AuraEffectRemoveFn(spell_ymiron_the_fallen_king_soul_siphon::OnAfterApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_ymiron_the_fallen_king_soul_siphon::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_ymiron_the_fallen_king_soul_siphon::OnAfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 167922 - Power
class spell_ymiron_the_fallen_king_power_periodic : public AuraScript
{
void OnPeriodic(AuraEffect const* aurEff)
{
int32 newPower = GetTarget()->GetPower(POWER_ENERGY) + (((aurEff->GetTickNumber() + 1) % 3 == 0) ? 6 : 7);
GetTarget()->SetPower(POWER_ENERGY, newPower);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_ymiron_the_fallen_king_power_periodic::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
class YmironBanePrecastVisual : public BasicEvent
{
public:
explicit YmironBanePrecastVisual(Unit* caster, int8 remainingVisualsToSpawn) : _caster(caster), _remainingVisualsToSpawn(remainingVisualsToSpawn) { }
static constexpr int8 BANE_VISUAL_NUM = 11;
static constexpr float BANE_VISUAL_TIME_OFFSET = 0.204545438289642f;
static constexpr float BANE_VISUAL_TIME_BASE = 0.75f;
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
float dist = frand(10.0f, 35.0f);
float angle = frand(0.0f, 2.0f * float(M_PI));
Position dest(_caster->GetPositionX() + dist * std::cos(angle), _caster->GetPositionY() + dist * std::sin(angle), _caster->GetPositionZ());
float travelSpeed = BANE_VISUAL_TIME_BASE + (BANE_VISUAL_TIME_OFFSET * _remainingVisualsToSpawn);
_caster->SendPlaySpellVisual(dest, SPELL_VISUAL_BANE_PRECAST, 0, 0, travelSpeed, true);
_remainingVisualsToSpawn--;
if (_remainingVisualsToSpawn > 0)
{
_caster->m_Events.AddEventAtOffset(this, 200ms);
return false;
}
return true;
}
private:
Unit* _caster;
int8 _remainingVisualsToSpawn;
};
// 193460 - Bane
class spell_ymiron_the_fallen_king_bane_periodic : public SpellScript
{
void OnPrecast() override
{
GetCaster()->m_Events.AddEventAtOffset(new YmironBanePrecastVisual(GetCaster(), YmironBanePrecastVisual::BANE_VISUAL_NUM), 0s);
}
void Register() override { }
};
// 193460 - Bane
class spell_ymiron_the_fallen_king_bane_periodic_AuraScript : public AuraScript
{
static constexpr float BANE_MISSILE_DIST_OFFSET = 2.272f;
static constexpr float BANE_MISSILE_DIST_BASE = 10.0f;
static constexpr float BANE_MISSILE_ANGLE_OFFSET = 0.75f;
static constexpr int8 BANE_MAX_TOTAL_TICKS = 4 + 4 + 14;
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& /*isPeriodic*/, int32& amplitude)
{
Unit* caster = GetCaster();
if (!caster)
return;
if (caster->GetMap()->IsMythic() || caster->GetMap()->IsMythicPlus())
amplitude = 1 * IN_MILLISECONDS;
// defaults to 2000 for Normal and Heroic via. db2 data
}
void SpawnBaneOrb(int8 tickNumber)
{
float dist = _distances[tickNumber - 1];
float angle = _angles[tickNumber - 1];
Position dest = { GetTarget()->GetPositionX() + dist * std::cos(angle), GetTarget()->GetPositionY() + dist * std::sin(angle), GetTarget()->GetPositionZ(), angle};
GetTarget()->CastSpell(dest, SPELL_BANE_MISSILE, true);
}
void OnAfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
for (int8 i = 0; i < BANE_MAX_TOTAL_TICKS; i++)
{
float angle = Position::NormalizeOrientation(GetCaster()->GetOrientation() + (i * BANE_MISSILE_ANGLE_OFFSET));
_angles[2 * i + 0] = angle;
_angles[2 * i + 1] = angle;
float dist = BANE_MISSILE_DIST_BASE + (i * BANE_MISSILE_DIST_OFFSET);
_distances[2 * i + 0] = dist;
_distances[2 * i + 1] = dist;
}
Trinity::Containers::RandomShuffle(_angles);
Trinity::Containers::RandomShuffle(_distances);
}
void OnPeriodic(AuraEffect const* aurEff)
{
if (aurEff->GetTickNumber() == 1 || (aurEff->GetTickNumber() == 2 && (GetTarget()->GetMap()->IsMythic() || GetTarget()->GetMap()->IsMythicPlus())))
{
for (int8 i = 0; i < 4; i++)
SpawnBaneOrb(aurEff->GetTickNumber() + i);
}
else
SpawnBaneOrb(aurEff->GetTickNumber() + 8);
}
void OnAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->CastSpell(GetTarget(), SPELL_ARISE_FALLEN_ENABLER, true);
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_ymiron_the_fallen_king_bane_periodic_AuraScript::CalcPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
AfterEffectApply += AuraEffectApplyFn(spell_ymiron_the_fallen_king_bane_periodic_AuraScript::OnAfterApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_ymiron_the_fallen_king_bane_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_ymiron_the_fallen_king_bane_periodic_AuraScript::OnAfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
private:
std::array<float, BANE_MAX_TOTAL_TICKS * 2> _angles;
std::array<float, BANE_MAX_TOTAL_TICKS * 2> _distances;
};
struct at_ymiron_the_fallen_king_bane : AreaTriggerAI
{
at_ymiron_the_fallen_king_bane(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
static constexpr float TIME_TO_TARGET_DIST_MULTIPLIER = 966.6466466434464f;
void OnInitialize() override
{
Unit* caster = at->GetCaster();
if (!caster)
return;
float radius = at->GetExactDist(caster);
float timeToTarget = radius * TIME_TO_TARGET_DIST_MULTIPLIER;
float angle = at->GetOrientation();
AreaTriggerOrbitInfo orbitInfo;
orbitInfo.CounterClockwise = false;
orbitInfo.CanLoop = true;
orbitInfo.ElapsedTimeForMovement = 0;
orbitInfo.StartDelay = 0;
orbitInfo.Radius = radius;
orbitInfo.BlendFromRadius = radius;
orbitInfo.InitialAngle = angle;
orbitInfo.PathTarget = caster->GetGUID();
at->InitOrbit(orbitInfo, timeToTarget);
}
void OnUnitEnter(Unit* unit) override
{
Player* player = unit->ToPlayer();
if (!player)
return;
Unit* caster = at->GetCaster();
if (!caster)
return;
caster->CastSpell(player, SPELL_BANE_DAMAGE, true);
caster->CastSpell(nullptr, SPELL_BANE_NOVA, true);
at->Remove();
}
};
class YmironAriseFallenVisual : public BasicEvent
{
public:
explicit YmironAriseFallenVisual(Unit* caster, Position dest) : _caster(caster), _dest(dest) { }
static constexpr int8 BANE_VISUAL_NUM = 11;
static constexpr float BANE_VISUAL_TIME_OFFSET = 0.204545438289642f;
static constexpr float BANE_VISUAL_TIME_BASE = 0.75f;
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
_caster->CastSpell(_dest, SPELL_ARISE_FALLEN_SUMMON, true);
return true;
}
private:
Unit* _caster;
Position _dest;
};
// 193566 - Arise, Fallen
class spell_ymiron_the_fallen_king_arise_fallen_selector : public SpellScript
{
static constexpr float SPAWN_DIST_TO_TARGET = 3.5f;
void HandleHit(SpellEffIndex /*effIndex*/)
{
GetCaster()->RemoveAurasDueToSpell(SPELL_ARISE_FALLEN_ENABLER);
std::vector<AreaTrigger*> atList = GetCaster()->GetAreaTriggers(SPELL_BANE_AT_NHC_HEROIC);
Trinity::Containers::RandomShuffle(atList);
for (AreaTrigger* at : atList)
{
_baneATGUIDs.push(at->GetGUID());
}
_atsPerTarget = atList.size() / GetUnitTargetCountForEffect(EFFECT_0);
_remainingBaneATs = atList.size() % GetUnitTargetCountForEffect(EFFECT_0);
}
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([](WorldObject* target) -> bool
{
return !target->IsPlayer();
});
}
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
uint8 atNum = _atsPerTarget;
if (_remainingBaneATs > 0)
{
atNum++;
_remainingBaneATs--;
}
for (uint8 i = 0; i < atNum; i++)
{
AreaTrigger* at = ObjectAccessor::GetAreaTrigger(*GetCaster(), _baneATGUIDs.front());
_baneATGUIDs.pop();
if (!at)
return;
Position dest = GetHitUnit()->GetFirstCollisionPosition(SPAWN_DIST_TO_TARGET, frand(0, 2.0f * float(M_PI)));
float travelSpeed = frand(1.50f, 2.50f);
at->SendPlayOrphanSpellVisual(dest, SPELL_VISUAL_ARISE_FALLEN, travelSpeed, true);
uint32 travelSpeedInMs = (uint32)(travelSpeed * 1000);
GetCaster()->m_Events.AddEventAtOffset(new YmironAriseFallenVisual(GetCaster(), dest), Milliseconds(travelSpeedInMs));
at->Remove();
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ymiron_the_fallen_king_arise_fallen_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHit += SpellEffectFn(spell_ymiron_the_fallen_king_arise_fallen_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_ymiron_the_fallen_king_arise_fallen_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
private:
std::queue<ObjectGuid> _baneATGUIDs;
uint8 _atsPerTarget = 0;
uint8 _remainingBaneATs = 0;
};
// 98246 - Risen Warrior
struct npc_ymiron_the_fallen_king_risen_warrior : public ScriptedAI
{
npc_ymiron_the_fallen_king_risen_warrior(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_ARISE_FALLEN, 4, 2000);
me->SetReactState(REACT_PASSIVE);
_scheduler.Schedule(2s, [this](TaskContext /*task*/)
{
me->SetReactState(REACT_AGGRESSIVE);
});
DoZoneInCombat();
_scheduler.Schedule(6s, [this](TaskContext task)
{
DoCastSelf(SPELL_VIGOR, true);
task.Repeat(6s);
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
UpdateVictim();
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_ymiron_the_fallen_king()
{
RegisterMawOfSoulsCreatureAI(boss_ymiron_the_fallen_king);
RegisterAreaTriggerAI(at_ymiron_the_fallen_king_activation);
RegisterSpellScript(spell_ymiron_the_fallen_king_soul_siphon);
RegisterSpellScript(spell_ymiron_the_fallen_king_power_periodic);
RegisterSpellAndAuraScriptPair(spell_ymiron_the_fallen_king_bane_periodic, spell_ymiron_the_fallen_king_bane_periodic_AuraScript);
RegisterAreaTriggerAI(at_ymiron_the_fallen_king_bane);
RegisterSpellScript(spell_ymiron_the_fallen_king_arise_fallen_selector);
RegisterMawOfSoulsCreatureAI(npc_ymiron_the_fallen_king_risen_warrior);
}

View File

@@ -0,0 +1,75 @@
/*
* 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 "maw_of_souls.h"
BossBoundaryData const boundaries =
{
{ DATA_YMIRON, new CircleBoundary({ 7382.8168f, 7300.5527f }, 55.0f)}
};
ObjectData const creatureData[] =
{
{ BOSS_YMIRON, DATA_YMIRON },
{ BOSS_HARBARON, DATA_HARBARON },
{ BOSS_HELYA, DATA_HELYA },
{ 0, 0 } // END
};
DoorData const doorData[] =
{
{ 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress } // END
};
DungeonEncounterData const encounters[] =
{
{ DATA_YMIRON, {{ 1822 }} },
{ DATA_HARBARON, {{ 1823 }} },
{ DATA_HELYA, {{ 1824 }} },
};
class instance_maw_of_souls : public InstanceMapScript
{
public:
instance_maw_of_souls() : InstanceMapScript(MOSScriptName, 1492) { }
struct AddSC_instance_maw_of_souls_InstanceMapScript : public InstanceScript
{
AddSC_instance_maw_of_souls_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 AddSC_instance_maw_of_souls_InstanceMapScript(map);
}
};
void AddSC_instance_maw_of_souls()
{
new instance_maw_of_souls();
}

View File

@@ -0,0 +1,52 @@
/*
* 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 DEF_MAW_OF_SOULS_H_
#define DEF_MAW_OF_SOULS_H_
#include "CreatureAIImpl.h"
#define DataHeader "MawOfSouls"
#define MOSScriptName "instance_maw_of_souls"
uint32 const EncounterCount = 3;
enum MOSDataTypes
{
// Encounters
DATA_YMIRON = 0,
DATA_HARBARON,
DATA_HELYA,
};
enum MOSCreatureIds
{
// Bosses
BOSS_YMIRON = 96756,
BOSS_HARBARON = 96754,
BOSS_HELYA = 96759,
};
template <class AI, class T>
inline AI* GetMawOfSoulsAI(T* obj)
{
return GetInstanceAI<AI>(obj, MOSScriptName);
}
#define RegisterMawOfSoulsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMawOfSoulsAI)
#endif

View File

@@ -17,6 +17,10 @@
// This is where scripts' loading functions should be declared:
// Maw of Souls
void AddSC_boss_ymiron_the_fallen_king();
void AddSC_instance_maw_of_souls();
// Trial of Valor
void AddSC_boss_guarm();
void AddSC_instance_trial_of_valor();
@@ -29,6 +33,10 @@ void AddSC_zone_mardum();
// void Add${NameOfDirectory}Scripts()
void AddBrokenIslesScripts()
{
// Maw of Souls
AddSC_boss_ymiron_the_fallen_king();
AddSC_instance_maw_of_souls();
// Trial of Valor
AddSC_boss_guarm();
AddSC_instance_trial_of_valor();