Scripts/TheStonevault: Implement E.D.N.A. encounter (all difficulties) (#30604)

This commit is contained in:
Aqua Deus
2025-01-30 14:00:13 +01:00
committed by GitHub
parent 1f305e951a
commit 212c257bb9
5 changed files with 899 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
-- Creature
UPDATE `creature_template_difficulty` SET `HealthScalingExpansion`=10, `CreatureDifficultyID`=274040, `TypeFlags2`=128 WHERE (`Entry`=223237 AND `DifficultyID`=23); -- Volatile Spike Stalker
UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2, `LevelScalingDeltaMax`=2, `ContentTuningID`=2722, `StaticFlags1`=0x10000000, `VerifiedBuild`=58238 WHERE (`Entry`=210108 AND `DifficultyID`=23); -- 210108 (E.D.N.A.) - CanSwim
UPDATE `creature_template` SET `faction`=14, `BaseAttackTime`=2000, `unit_flags`=0x2000000, `unit_flags2`=0x800, `unit_flags3`=0x41080001, `AIName`='SmartAI' WHERE `entry`=223237; -- Volatile Spike Stalker
UPDATE `creature_template` SET `ScriptName`='boss_edna' WHERE `entry`=210108; -- 210108 (E.D.N.A.)
UPDATE `creature_template` SET `ScriptName`='npc_skardyn_invader' WHERE `entry`=224516; -- 224516 (Skardyn Invader)
UPDATE `creature_template` SET `StringId`='edna_intro_trash' WHERE `entry`=210109; -- 210109 (Earth Infused Golem)
DELETE FROM `creature_template_addon` WHERE `entry`=210108;
INSERT INTO `creature_template_addon` (`entry`, `PathId`, `mount`, `MountCreatureID`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvPFlags`, `emote`, `aiAnimKit`, `movementAnimKit`, `meleeAnimKit`, `visibilityDistanceType`, `auras`) VALUES
(210108, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, '451704 447230 422356');
-- Instance
DELETE FROM `instance_template` WHERE `map`=2652;
INSERT INTO `instance_template` (`map`, `parent`, `script`) VALUES
(2652, 0, 'instance_the_stonevault');
-- Areatriggers
DELETE FROM `areatrigger_template` WHERE (`IsCustom`=0 AND `Id` IN (33881, 19401));
INSERT INTO `areatrigger_template` (`Id`, `IsCustom`, `Flags`, `VerifiedBuild`) VALUES
(33881, 0, 0, 58238),
(19401, 0, 0, 58238);
DELETE FROM `areatrigger_create_properties` WHERE (`IsCustom`=0 AND `Id` IN (33613, 30324));
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
(33613, 0, 33881, 0, 4, 0, 0, 0, 0, -1, 0, 0, 424909, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 'at_edna_volatile_spike', 58238), -- SpellForVisuals: 424909 (Volatile Spike)
(30324, 0, 19401, 0, 4, 0, 0, 0, 0, -1, 0, 0, 424909, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, '', 58238); -- SpellForVisuals: 424909 (Volatile Spike) Unknown purpose (maybe testing?)
-- Spells
DELETE FROM `spell_script_names` WHERE `spell_id` IN (451705, 447230, 451728, 424889, 424903, 452738, 424805, 424879);
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(451705, 'spell_edna_energize'),
(447230, 'spell_edna_skarden_spawn_rp_periodic'),
(451728, 'spell_edna_skarden_spawn_rp'),
(424889, 'spell_edna_seismic_reverberation'),
(424903, 'spell_edna_volatile_spike_selector'),
(452738, 'spell_edna_refracting_beam_selector'),
(424805, 'spell_edna_refracting_beam_instakill'),
(424879, 'spell_edna_earth_shatterer');
-- Volatile Spike SAI
DELETE FROM `smart_scripts` WHERE `entryorguid`=223237 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
(223237, 0, 0, 0, '', 63, 0, 100, 0, 0, 0, 0, 0, 0, '', 85, 424909, 2, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Volatile Spike Stalker - On Summoned - Cast Self: Volatile Spike'),
(223237, 0, 1, 2, '', 8, 0, 100, 0, 448207, 0, 0, 0, 0, '', 85, 424913, 0, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Volatile Spike Stalker - On Spellhit \'Refracting Beam\' - Cast Self: Volatile Explosion'),
(223237, 0, 2, 0, '', 61, 0, 100, 0, 0, 0, 0, 0, 0, '', 41, 0, 0, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Volatile Spike Stalker - On Spellhit \'Refracting Beam\' - Despawn'),
(223237, 0, 3, 4, '', 8, 0, 100, 0, 448220, 0, 0, 0, 0, '', 85, 424913, 0, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Volatile Spike Stalker - On Spellhit \'Earth Shatterer\' - Cast Self: Volatile Explosion'),
(223237, 0, 4, 0, '', 61, 0, 100, 0, 0, 0, 0, 0, 0, '', 41, 0, 0, 0, 0, 0, 0, 0, NULL, 1, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 'Volatile Spike Stalker - On Spellhit \'Earth Shatterer\' - Despawn');
-- Conditions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` = 424805;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 4, 424805, 0, 0, 51, 0, 5, 224516, 0, '', 0, 0, 0, '', 'Spell \'Refracting Beam\' can only hit \'Skardyn Invader\'');
-- Texts
DELETE FROM `creature_text` WHERE `CreatureID`= 210108;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(210108, 0, 0, 'Intruders approaching. Systems on.', 14, 0, 100, 0, 0, 247879, 262600, 0, 'E.D.N.A.'),
(210108, 1, 0, 'Activating defense protocols.', 14, 0, 100, 0, 0, 247879, 262601, 0, 'E.D.N.A.'),
(210108, 2, 0, 'Seismic protocol activated.', 14, 0, 100, 0, 0, 247883, 262604, 0, 'E.D.N.A.'),
(210108, 3, 0, 'Offensive measures engaged.', 14, 0, 100, 0, 0, 250762, 262608, 0, 'E.D.N.A.'),
(210108, 4, 0, 'Dominant intruder identified.', 14, 0, 100, 0, 0, 247884, 262605, 0, 'E.D.N.A.'),
(210108, 5, 0, '|TInterface\\ICONS\\INV_ElementalEarth2.blp:20|t %s begins to cast |cFFFF0000|Hspell:424888|h[Seismic Smash]|h|r.', 41, 0, 100, 0, 0, 247884, 0, 0, 'E.D.N.A.'), -- Unknown BroadcastTextId
(210108, 6, 0, 'Engaging offensive protocols.', 14, 0, 100, 0, 0, 247885, 262606, 0, 'E.D.N.A.'),
(210108, 7, 0, 'Intruder terminated.', 14, 0, 100, 0, 0, 247881, 262602, 0, 'E.D.N.A.'),
(210108, 8, 0, 'All intruders terminated.', 14, 0, 100, 0, 0, 247889, 262610, 0, 'E.D.N.A.'),
(210108, 9, 0, 'All systems... shutting down...', 14, 0, 100, 0, 0, 247890, 262611, 0, 'E.D.N.A.');
-- Conversations
DELETE FROM `conversation_actors` WHERE (`Idx`=0 AND `ConversationId` IN (25769,25768));
INSERT INTO `conversation_actors` (`ConversationId`, `ConversationActorId`, `Idx`, `CreatureId`, `CreatureDisplayInfoId`, `NoActorObject`, `ActivePlayerObject`, `VerifiedBuild`) VALUES
(25769, 99466, 0, 224736, 119519, 0, 0, 58630),
(25768, 99466, 0, 224736, 119519, 0, 0, 58630);
DELETE FROM `conversation_line_template` WHERE `Id` IN (70041, 70040, 70039);
INSERT INTO `conversation_line_template` (`Id`, `UiCameraID`, `ActorIdx`, `Flags`, `ChatType`, `VerifiedBuild`) VALUES
(70041, 1218, 0, 0, 0, 58630),
(70040, 1218, 0, 0, 0, 58630),
(70039, 1218, 0, 0, 0, 58630);
DELETE FROM `conversation_template` WHERE `Id` IN (25814, 25775, 25773, 25772, 25771, 25770, 25769, 25768, 25767, 26511);
INSERT INTO `conversation_template` (`Id`, `FirstLineID`, `TextureKitId`, `VerifiedBuild`) VALUES
(25769, 70041, 0, 58630),
(25768, 70039, 0, 58630);

View File

@@ -0,0 +1,593 @@
/*
* 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 "Conversation.h"
#include "Creature.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "TemporarySummon.h"
#include "the_stonevault.h"
enum EdnaSpells
{
// Intro
SPELL_REFRACTING_BEAM_INTRO = 464888,
SPELL_SKARDEN_SPAWN_PERIODIC = 447230,
SPELL_SKARDEN_SPAWN_RP = 451728,
SPELL_SHADOW_DISSOLVE_IN = 448168,
// Combat
SPELL_EDNA_ENERGIZE = 451705,
SPELL_EDNA_START_ENERGY = 456814,
SPELL_EARTH_SHATTERER = 424879,
SPELL_EARTH_SHATTERER_MISSILE = 448218,
SPELL_REFRACTING_BEAM = 424795,
SPELL_REFRACTING_BEAM_DAMAGE = 424805,
SPELL_REFRACTING_BEAM_SELECTOR = 452738,
SPELL_VOLATILE_SPIKE_SELECTOR = 424903,
SPELL_VOLATILE_SPIKE_MISSILE = 424908,
SPELL_VOLATILE_EXPLOSION = 424913,
SPELL_SEISMIC_SMASH = 424888,
SPELL_STONE_SHIELD = 424893,
SPELL_EDNA_DEFEATED = 464827,
SPELL_ANCHOR_HERE = 45313
};
enum EdnaEvents
{
EVENT_VOLATILE_SPIKE = 1,
EVENT_REFRACTING_BEAM,
EVENT_SEISMIC_SMASH,
EVENT_CHECK_ENERGY
};
enum EdnaTexts
{
SAY_INTRO = 0,
SAY_AGGRO = 1,
SAY_VOLATILE_SPIKE = 2,
SAY_REFRACTING_BEAM = 3,
SAY_SEISMIC_SMASH = 4,
SAY_SEISMIC_SMASH_ALERT = 5,
SAY_EARTH_SHATTERER = 6,
SAY_SLAY = 7,
SAY_WIPE = 8,
SAY_DEATH = 9
};
enum EdnaMisc
{
POINT_EDNA = 0,
POINT_START_COMBAT = 1,
CONVERSATION_INTRO = 25768,
NPC_VOLATILE_SPIKE = 223237
};
static constexpr Position EdnaCombatPosition = { 1.94097f, 0.512153f, 361.66537f };
static constexpr Position SkardenSpawnPositions[4] =
{
{ -11.276042f, -19.234375f, 361.8286f, 2.490876f },
{ -11.395833f, 19.628473f, 361.8286f, 3.805543f },
{ -25.248264f, 34.609375f, 361.8286f, 4.397980f },
{ -20.77257f, -34.930557f, 361.82837f, 1.994346f }
};
// 210108 - E.D.N.A.
struct boss_edna : public BossAI
{
boss_edna(Creature* creature) : BossAI(creature, DATA_EDNA), _refractingBeamCount(1), _seismicSmashCount(1), _volatileSpikeCount(1) { }
void InitializeAI() override
{
if (instance->GetBossState(DATA_EDNA) != NOT_STARTED)
me->Relocate(EdnaCombatPosition);
}
void Reset() override
{
BossAI::Reset();
_refractingBeamCount = 1;
_seismicSmashCount = 1;
_volatileSpikeCount = 1;
}
void JustAppeared() override
{
if (instance->GetData(DATA_EDNA_INTRO_STATE) == DONE)
{
me->RemoveAurasDueToSpell(SPELL_SKARDEN_SPAWN_PERIODIC);
me->SetImmuneToPC(false);
}
me->SetPowerType(POWER_ENERGY);
me->SetPower(POWER_ENERGY, 4);
if (IsMythic() || IsMythicPlus())
DoCastSelf(SPELL_EDNA_START_ENERGY);
}
void KilledUnit(Unit* victim) override
{
if (!victim->IsPlayer())
return;
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
Talk(SAY_DEATH);
DoCast(SPELL_EDNA_DEFEATED);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
Talk(SAY_WIPE);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void DoAction(int32 actionId) override
{
if (actionId != ACTION_START_EDNA_INTRO)
return;
Conversation::CreateConversation(CONVERSATION_INTRO, me, me->GetPosition(), ObjectGuid::Empty);
scheduler.Schedule(3s, [this](TaskContext /*context*/)
{
me->RemoveAurasDueToSpell(SPELL_SKARDEN_SPAWN_PERIODIC);
me->GetMotionMaster()->MovePoint(POINT_START_COMBAT, EdnaCombatPosition, true, {}, {}, MovementWalkRunSpeedSelectionMode::ForceWalk);
});
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE)
return;
if (id != POINT_START_COMBAT)
return;
scheduler.Schedule(1s, [this](TaskContext /*context*/)
{
instance->SetData(DATA_EDNA_INTRO_STATE, DONE);
Talk(SAY_INTRO);
DoCastSelf(SPELL_ANCHOR_HERE, TRIGGERED_FULL_MASK);
me->SetImmuneToPC(false);
});
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
if (IsMythic() || IsMythicPlus())
{
events.ScheduleEvent(EVENT_CHECK_ENERGY, 500ms);
events.ScheduleEvent(EVENT_VOLATILE_SPIKE, 6s);
events.ScheduleEvent(EVENT_REFRACTING_BEAM, 14s);
events.ScheduleEvent(EVENT_SEISMIC_SMASH, 18s);
DoCastSelf(SPELL_EDNA_ENERGIZE);
}
else
{
events.ScheduleEvent(EVENT_VOLATILE_SPIKE, 8100ms);
events.ScheduleEvent(EVENT_REFRACTING_BEAM, 11800ms);
events.ScheduleEvent(EVENT_SEISMIC_SMASH, 15400ms);
}
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_VOLATILE_SPIKE:
{
Talk(SAY_VOLATILE_SPIKE);
DoCast(SPELL_VOLATILE_SPIKE_SELECTOR);
_volatileSpikeCount++;
if (IsMythic() || IsMythicPlus())
{
if (_volatileSpikeCount % 2 == 0)
events.Repeat(20s);
else
events.Repeat(28s);
}
else
events.Repeat(14600ms);
break;
}
case EVENT_REFRACTING_BEAM:
{
Talk(SAY_REFRACTING_BEAM);
DoCast(SPELL_REFRACTING_BEAM_SELECTOR);
_refractingBeamCount++;
if (IsMythic() || IsMythicPlus())
{
if (_refractingBeamCount % 2 == 0)
events.Repeat(20s);
else
events.Repeat(28s);
}
else
events.Repeat(10900ms);
break;
}
case EVENT_SEISMIC_SMASH:
{
Talk(SAY_SEISMIC_SMASH);
Talk(SAY_SEISMIC_SMASH_ALERT);
DoCastVictim(SPELL_SEISMIC_SMASH);
_seismicSmashCount++;
if (IsMythic() || IsMythicPlus())
{
if (_seismicSmashCount % 2 == 0)
events.Repeat(20s);
else
events.Repeat(28s);
}
else
events.Repeat(23100ms);
break;
}
case EVENT_CHECK_ENERGY:
{
if (me->GetPower(POWER_ENERGY) >= 95)
{
Talk(SAY_EARTH_SHATTERER);
DoCast(SPELL_EARTH_SHATTERER);
events.Repeat(4s);
}
else
events.Repeat(500ms);
break;
}
default:
break;
}
}
private:
uint16 _refractingBeamCount;
uint16 _seismicSmashCount;
uint16 _volatileSpikeCount;
};
// 224516 - Skardyn Invader
struct npc_skardyn_invader : public ScriptedAI
{
npc_skardyn_invader(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoCastSelf(SPELL_SHADOW_DISSOLVE_IN);
_scheduler.Schedule(2400ms, [this](TaskContext /*context*/)
{
TempSummon* summon = me->ToTempSummon();
if (!summon)
return;
if (Unit* summoner = summon->GetSummonerUnit())
{
me->GetMotionMaster()->MovePoint(POINT_EDNA, summoner->GetPosition());
summoner->CastSpell(me, SPELL_REFRACTING_BEAM_INTRO, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
// 451705 - E.D.N.A. Energize
class spell_edna_energize : public AuraScript
{
static constexpr std::array<uint8, 6> EdnaEnergizeCycle = { 2, 2, 2, 2, 3, 2 };
void PeriodicTick(AuraEffect const* aurEff) const
{
uint8 cycleIdx = aurEff->GetTickNumber() % EdnaEnergizeCycle.size();
GetTarget()->ModifyPower(POWER_ENERGY, EdnaEnergizeCycle[cycleIdx]);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_edna_energize::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 447230 - Skarden Spawn RP
class spell_edna_skarden_spawn_rp_periodic : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SKARDEN_SPAWN_RP });
}
void HandlePeriodic(AuraEffect const* aurEff) const
{
Unit* target = GetTarget();
target->CastSpell(target, SPELL_SKARDEN_SPAWN_RP, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringAura = aurEff
});
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_edna_skarden_spawn_rp_periodic::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 451728 - Skarden Spawn RP
class spell_edna_skarden_spawn_rp : public SpellScript
{
static void SetDest(SpellDestination& dest)
{
dest.Relocate(Trinity::Containers::SelectRandomContainerElement(SkardenSpawnPositions));
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_edna_skarden_spawn_rp::SetDest, EFFECT_0, TARGET_DEST_DEST);
}
};
// 424889 - Seismic Reverberation
class spell_edna_seismic_reverberation : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_STONE_SHIELD });
}
void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) const
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL)
return;
Unit* target = GetTarget();
target->CastSpell(target, SPELL_STONE_SHIELD, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringAura = aurEff
});
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_edna_seismic_reverberation::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
}
};
// 424903 - Volatile Spike
class spell_edna_volatile_spike_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_VOLATILE_SPIKE_MISSILE });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit()->GetPosition(), SPELL_VOLATILE_SPIKE_MISSILE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell(),
.OriginalCastId = GetSpell()->m_castId
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_edna_volatile_spike_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 452738 - Refracting Beam
class spell_edna_refracting_beam_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REFRACTING_BEAM })
&& ValidateSpellEffect({ { SPELL_REFRACTING_BEAM_DAMAGE, EFFECT_3 } });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
GetCaster()->m_Events.AddEvent([this, hitUnitGUID = GetHitUnit()->GetGUID()]()
{
Unit* hitUnit = ObjectAccessor::GetUnit(*GetCaster(), hitUnitGUID);
if (!hitUnit)
return;
GetCaster()->CastSpell(GetHitUnit(), SPELL_REFRACTING_BEAM, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell(),
.OriginalCastId = GetSpell()->m_castId
});
}, _timeMultiplier * 500ms);
_timeMultiplier++;
}
void FilterTargets(std::list<WorldObject*>& targets) const
{
SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_REFRACTING_BEAM_DAMAGE, GetCastDifficulty());
uint32 maxTargets = spell->GetEffect(EFFECT_3).CalcValue(GetCaster());
if (targets.size() > maxTargets)
targets.resize(maxTargets);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_edna_refracting_beam_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_edna_refracting_beam_selector::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
}
private:
uint8 _timeMultiplier = 0u;
};
// 424805 - Refracting Beam
class spell_edna_refracting_beam_instakill : public SpellScript
{
void FilterTargets(std::list<WorldObject*>& targets) const
{
static constexpr uint8 MAX_TARGETS = 1;
if (targets.size() <= MAX_TARGETS)
return;
auto closestTargetItr = std::ranges::min_element(targets, [caster = GetCaster()](WorldObject const* left, WorldObject const* right)
{
return caster->GetDistance(left->GetPosition()) < caster->GetDistance(right->GetPosition());
});
if (closestTargetItr == targets.end())
return;
WorldObject* closestTarget = *closestTargetItr;
targets.clear();
targets.push_back(closestTarget);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_edna_refracting_beam_instakill::FilterTargets, EFFECT_2, TARGET_UNIT_LINE_CASTER_TO_DEST);
}
};
// 424879 - Earth Shatterer
class spell_edna_earth_shatterer : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_EARTH_SHATTERER_MISSILE });
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/) const
{
Unit* caster = GetCaster();
std::list<Creature*> volatileSpikes;
GetCreatureListWithEntryInGrid(volatileSpikes, caster, NPC_VOLATILE_SPIKE, 200.0f);
for (Creature* spike : volatileSpikes)
{
caster->CastSpell(spike, SPELL_EARTH_SHATTERER_MISSILE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell(),
.OriginalCastId = GetSpell()->m_castId
});
}
}
void HandleAfterCast() const
{
Unit* caster = GetCaster();
caster->SetPower(caster->GetPowerType(), 0);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_edna_earth_shatterer::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
AfterCast += SpellCastFn(spell_edna_earth_shatterer::HandleAfterCast);
}
};
// 424909 - Volatile Spike
// Id - 33613
struct at_edna_volatile_spike : AreaTriggerAI
{
at_edna_volatile_spike(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) {}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
Unit* caster = at->GetCaster();
if (!caster)
return;
caster->CastSpell(unit, SPELL_VOLATILE_EXPLOSION, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
if (Creature* casterCreature = caster->ToCreature())
casterCreature->DespawnOrUnsummon();
}
};
void AddSC_boss_edna()
{
RegisterTheStonevaultCreatureAI(boss_edna);
RegisterTheStonevaultCreatureAI(npc_skardyn_invader);
RegisterSpellScript(spell_edna_energize);
RegisterSpellScript(spell_edna_skarden_spawn_rp_periodic);
RegisterSpellScript(spell_edna_skarden_spawn_rp);
RegisterSpellScript(spell_edna_seismic_reverberation);
RegisterSpellScript(spell_edna_volatile_spike_selector);
RegisterSpellScript(spell_edna_refracting_beam_selector);
RegisterSpellScript(spell_edna_refracting_beam_instakill);
RegisterSpellScript(spell_edna_earth_shatterer);
RegisterAreaTriggerAI(at_edna_volatile_spike);
}

View File

@@ -0,0 +1,141 @@
/*
* 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 "Creature.h"
#include "CreatureAI.h"
#include "InstanceScript.h"
#include "ScriptMgr.h"
#include "the_stonevault.h"
BossBoundaryData const boundaries =
{
{ DATA_EDNA, new CircleBoundary({ 0.0f, 0.0f }, 58.0f)}
};
ObjectData const creatureData[] =
{
{ BOSS_EDNA, DATA_EDNA },
{ BOSS_SKARMORAX, DATA_SKARMORAK },
{ BOSS_SPEAKER_DORLITA, DATA_SPEAKER_DORLITA },
{ BOSS_SPEAKER_BROKK, DATA_SPEAKER_BROKK },
{ BOSS_VOID_SPEAKER_EIRICH, DATA_VOID_SPEAKER_EIRICH },
{ 0, 0 } // END
};
static DoorData const doorData[] =
{
{ GO_FOUNDRY_DOOR_ENTRANCE, DATA_EDNA, EncounterDoorBehavior::OpenWhenNotInProgress },
{ GO_FOUNDRY_DOOR_TOWARDS_SKARMORAK, DATA_EDNA, EncounterDoorBehavior::OpenWhenDone },
{ GO_FOUNDRY_DOOR_TOWARDS_MACHINISTS, DATA_EDNA, EncounterDoorBehavior::OpenWhenDone },
{ 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress }
};
DungeonEncounterData const encounters[] =
{
{ DATA_EDNA, {{ 2854 }} },
{ DATA_SKARMORAK, {{ 2880 }} },
{ DATA_MASTER_MACHINISTS, {{ 2883 }} },
{ DATA_VOID_SPEAKER_EIRICH, {{ 2888 }} }
};
constexpr uint8 EDNA_INTRO_REQUIRED_KILLS = 5;
class instance_the_stonevault : public InstanceMapScript
{
public:
instance_the_stonevault() : InstanceMapScript(TSVScriptName, 2652) { }
struct instance_the_stonevault_InstanceMapScript: public InstanceScript
{
instance_the_stonevault_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
LoadBossBoundaries(boundaries);
LoadDungeonEncounterData(encounters);
_ednaIntroState = NOT_STARTED;
_ednaIntroNPCsKillCount = 0;
}
uint32 GetData(uint32 dataId) const override
{
switch (dataId)
{
case DATA_EDNA_INTRO_STATE:
return _ednaIntroState;
default:
break;
}
return 0;
}
void SetData(uint32 dataId, uint32 value) override
{
switch (dataId)
{
case DATA_EDNA_INTRO_STATE:
_ednaIntroState = value;
break;
default:
break;
}
}
void OnUnitDeath(Unit* unit) override
{
Creature* creature = unit->ToCreature();
if (!creature)
return;
if (creature->HasStringId("edna_intro_trash"))
{
if (_ednaIntroState != NOT_STARTED)
return;
_ednaIntroNPCsKillCount++;
if (_ednaIntroNPCsKillCount < EDNA_INTRO_REQUIRED_KILLS)
return;
_ednaIntroState = IN_PROGRESS;
Creature* edna = GetCreature(DATA_EDNA);
if (!edna)
return;
edna->AI()->DoAction(ACTION_START_EDNA_INTRO);
}
}
private:
uint8 _ednaIntroState;
uint8 _ednaIntroNPCsKillCount;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_the_stonevault_InstanceMapScript(map);
}
};
void AddSC_instance_the_stonevault()
{
new instance_the_stonevault();
}

View File

@@ -0,0 +1,72 @@
/*
* 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_THE_STONEVAULT_H_
#define DEF_THE_STONEVAULT_H_
#include "CreatureAIImpl.h"
#define TSVScriptName "instance_the_stonevault"
#define DataHeader "TheStonevault"
constexpr uint32 EncounterCount = 4;
enum TheStonevaultDataTypes
{
// Encounters
DATA_EDNA = 0,
DATA_SKARMORAK = 1,
DATA_MASTER_MACHINISTS = 2,
DATA_VOID_SPEAKER_EIRICH = 3,
// Additional Data
DATA_SPEAKER_DORLITA,
DATA_SPEAKER_BROKK,
DATA_EDNA_INTRO_STATE
};
enum TheStonevaultCreatureIds
{
// Bosses
BOSS_EDNA = 210108,
BOSS_SKARMORAX = 210156,
BOSS_SPEAKER_DORLITA = 213216,
BOSS_SPEAKER_BROKK = 213217,
BOSS_VOID_SPEAKER_EIRICH = 213119
};
enum TheStonevaultGameObjectIds
{
GO_FOUNDRY_DOOR_ENTRANCE = 440236,
GO_FOUNDRY_DOOR_TOWARDS_SKARMORAK = 440235,
GO_FOUNDRY_DOOR_TOWARDS_MACHINISTS = 440239
};
enum TheStonevaultSharedActions
{
ACTION_START_EDNA_INTRO = 0
};
template <class AI, class T>
inline AI* GetTheStonevaultAI(T* obj)
{
return GetInstanceAI<AI>(obj, TSVScriptName);
}
#define RegisterTheStonevaultCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTheStonevaultAI)
#endif

View File

@@ -23,6 +23,10 @@ void AddSC_zone_dornogal();
// Zone Isle Of Dorn
void AddSC_zone_isle_of_dorn();
// The Stonevault
void AddSC_instance_the_stonevault();
void AddSC_boss_edna();
// Nerub'ar Palace
void AddSC_instance_nerubar_palace();
void AddSC_boss_ulgrax_the_devourer();
@@ -37,6 +41,10 @@ void AddKhazAlgarScripts()
// Zone Isle of Dorn
AddSC_zone_isle_of_dorn();
// The Stonevault
AddSC_instance_the_stonevault();
AddSC_boss_edna();
// Nerub'ar Palace
AddSC_instance_nerubar_palace();
AddSC_boss_ulgrax_the_devourer();