diff options
author | Aqua Deus <95978183+aquadeus@users.noreply.github.com> | 2025-02-04 19:14:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-04 19:14:20 +0100 |
commit | 17df38e02506c11a330346b5a2c4b6d88d3a57ab (patch) | |
tree | 70dce189679727123a969bd63fcd2c8dbfd4d53e /src | |
parent | 2b1ad96be1c102b1d681b7205ec38d2c5de28d9d (diff) |
Scripts/AtalDazar: Implement Volkaal encounter (#30663)
Diffstat (limited to 'src')
4 files changed, 481 insertions, 3 deletions
diff --git a/src/server/scripts/Zandalar/AtalDazar/atal_dazar.h b/src/server/scripts/Zandalar/AtalDazar/atal_dazar.h index 2da36868e0b..afd5015ad09 100644 --- a/src/server/scripts/Zandalar/AtalDazar/atal_dazar.h +++ b/src/server/scripts/Zandalar/AtalDazar/atal_dazar.h @@ -38,11 +38,19 @@ enum AtalDazarCreatureIds { // Bosses BOSS_PRIESTESS_ALUNZA = 129614, - BOSS_VOLKAAL = 129399, + BOSS_VOLKAAL = 122965, BOSS_REZAN = 122963, BOSS_YAZMA = 129412 }; +enum AtalDazarGameObjectIds +{ + GO_VOLKAAL_DOOR_1 = 292399, + GO_VOLKAAL_DOOR_2 = 292400, + GO_VOLKAAL_DOOR_3 = 292401, + GO_VOLKAAL_DOOR_4 = 292402 +}; + template <class AI, class T> inline AI* GetAtalDazarAI(T* obj) { diff --git a/src/server/scripts/Zandalar/AtalDazar/boss_volkaal.cpp b/src/server/scripts/Zandalar/AtalDazar/boss_volkaal.cpp new file mode 100644 index 00000000000..358e3ff5171 --- /dev/null +++ b/src/server/scripts/Zandalar/AtalDazar/boss_volkaal.cpp @@ -0,0 +1,457 @@ +/* + * 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 "AreaTriggerAI.h" +#include "CellImpl.h" +#include "Creature.h" +#include "GridNotifiersImpl.h" +#include "InstanceScript.h" +#include "MotionMaster.h" +#include "MoveSpline.h" +#include "ObjectAccessor.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "atal_dazar.h" + +enum VolkaalSpells +{ + SPELL_SOUL_ANCHOR = 259537, + SPELL_BAD_VOODOO = 250192, + SPELL_RAPID_DECAY = 250241, + SPELL_RAPID_DECAY_TARGET = 250694, + SPELL_RAPID_DECAY_RANDOM = 250697, + SPELL_TOXIC_POOL = 250585, + SPELL_REANIMATE = 259531, + SPELL_TOXIC_LEAP_SELECTOR = 250708, + SPELL_TOXIC_LEAP = 250258, + SPELL_TOXIC_LEAP_DAMAGE = 250259, + SPELL_NOXIOUS_STENCH = 259572, + SPELL_LINGERING_NAUSEA = 250372 +}; + +enum VolkaalEvents +{ + EVENT_TOXIC_LEAP = 1, + EVENT_NOXIOUS_STENCH, +}; + +enum VolkaalActions +{ + ACTION_TOTEMS_DIED = 1 +}; + +enum VolkaalSummonGroups +{ + SUMMON_GROUP_VOLKAAL_TOTEMS = 0 +}; + +enum VolkaalTexts +{ + SAY_AGGRO = 0, + SAY_DECAY = 1, + SAY_DIED = 2, + SAY_SLAY = 3, + SAY_WIPE = 4 +}; + +// 122965 - Vol'kaal +struct boss_volkaal : public BossAI +{ + boss_volkaal(Creature* creature) : BossAI(creature, DATA_VOLKAAL), _toxicLeapCount(1), _leaping(false) { } + + void JustAppeared() override + { + me->SummonCreatureGroup(SUMMON_GROUP_VOLKAAL_TOTEMS); + } + + void Reset() override + { + _Reset(); + + _toxicLeapCount = 1; + _leaping = false; + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + Talk(SAY_WIPE); + + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + summons.DespawnAll(); + + _EnterEvadeMode(); + _DespawnAtEvade(); + } + + void KilledUnit(Unit* victim) override + { + if (!victim->IsPlayer()) + return; + + Talk(SAY_SLAY); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1); + + for (ObjectGuid summonGuid : summons) + { + if (Creature * totem = ObjectAccessor::GetCreature(*me, summonGuid)) + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, totem, 2); + } + + Talk(SAY_AGGRO); + + events.ScheduleEvent(EVENT_TOXIC_LEAP, 2200ms); + events.ScheduleEvent(EVENT_NOXIOUS_STENCH, 5800ms); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + summons.DespawnAll(); + + Talk(SAY_DIED); + } + + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_RAPID_DECAY) + { + Talk(SAY_DECAY); + events.CancelEvent(EVENT_TOXIC_LEAP); + } + } + + void MovementInform(uint32 /*type*/, uint32 id) override + { + if (id == EVENT_JUMP) + { + DoCastSelf(SPELL_TOXIC_LEAP_DAMAGE); + _leaping = false; + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_TOTEMS_DIED) + { + for (ObjectGuid summonGuid : summons) + { + if (Creature* totem = ObjectAccessor::GetCreature(*me, summonGuid)) + { + totem->SetUnkillable(false); + totem->KillSelf(); + } + } + } + } + + 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_TOXIC_LEAP: + { + _leaping = true; + DoCast(SPELL_TOXIC_LEAP_SELECTOR); + _toxicLeapCount++; + if (_toxicLeapCount % 3 == 2) + events.Repeat(8500ms); + else + events.Repeat(6s); + break; + } + case EVENT_NOXIOUS_STENCH: + { + if (!_leaping) + { + DoCast(SPELL_NOXIOUS_STENCH); + events.Repeat(19400ms); + } + else + events.Repeat(100ms); + break; + } + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + +private: + uint32 _toxicLeapCount; + bool _leaping; +}; + +// 125977 - Reanimation Totem +struct npc_volkaal_reanimation_totem : public ScriptedAI +{ + npc_volkaal_reanimation_totem(Creature* creature) : ScriptedAI(creature) { } + + void JustAppeared() override + { + if (IsHeroicOrHigher()) + me->SetUnkillable(true); + } + + void JustEngagedWith(Unit* /*who*/) override + { + InstanceScript* instance = me->GetInstanceScript(); + if (!instance) + return; + + if (Creature* volkaal = instance->GetCreature(DATA_VOLKAAL)) + volkaal->AI()->DoZoneInCombat(); + } + + void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (me->GetHealth() <= damage) + { + if (IsHeroicOrHigher()) + { + DoCastSelf(SPELL_SOUL_ANCHOR); + DoCastSelf(SPELL_REANIMATE); + } + } + } + + void JustDied(Unit* /*killer*/) override + { + InstanceScript* instance = me->GetInstanceScript(); + if (!instance) + return; + + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } +}; + +// 250372 - Lingering Nausea +class spell_volkaal_lingering_nausea : public AuraScript +{ + void HandlePeriodic(AuraEffect const* aurEff) const + { + Unit* target = GetTarget(); + + if (Unit* caster = GetCaster()) + caster->CastSpell(target, aurEff->GetAmount(), CastSpellExtraArgsInit{ + .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR, + .TriggeringAura = aurEff + }); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_volkaal_lingering_nausea::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +// 250368 - Noxious Stench +class spell_volkaal_noxious_stench : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo ({ SPELL_LINGERING_NAUSEA }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) const + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_LINGERING_NAUSEA, CastSpellExtraArgsInit{ + .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR, + .TriggeringSpell = GetSpell() + }); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_volkaal_noxious_stench::HandleDummy, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } +}; + +// 250708 - Toxic Leap +class spell_volkaal_toxic_leap_selector : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_TOXIC_LEAP }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) const + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_TOXIC_LEAP); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_volkaal_toxic_leap_selector::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +// 250258 - Toxic Leap +class spell_volkaal_toxic_leap : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_TOXIC_LEAP }); + } + + void HandleHit(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + float dist = GetCaster()->GetExactDist(GetHitDest()); + float jumpGravity = 159500.0f / (dist * dist); // constant based on calculating avg of inverse from multiple leaps + GetCaster()->GetMotionMaster()->MoveJumpWithGravity(*GetHitDest(), 50, jumpGravity, EVENT_JUMP); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_volkaal_toxic_leap::HandleHit, EFFECT_1, SPELL_EFFECT_JUMP_CHARGE); + } +}; + +// 250229 - Soul Anchor +class spell_volkaal_soul_anchor : public SpellScript +{ + void SelectTotem(std::list<WorldObject*>& targets) const + { + if (targets.empty()) + { + InstanceScript* instance = GetCaster()->GetInstanceScript(); + if (!instance) + return; + + if (Creature* volkaal = instance->GetCreature(DATA_VOLKAAL)) + volkaal->AI()->DoAction(ACTION_TOTEMS_DIED); + + Unit* caster = GetCaster(); + caster->RemoveAurasDueToSpell(SPELL_BAD_VOODOO); + caster->CastSpell(caster, SPELL_RAPID_DECAY, CastSpellExtraArgsInit{ + .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR, + .TriggeringSpell = GetSpell() + }); + } + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_volkaal_soul_anchor::SelectTotem, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } +}; + +// 259531 - Reanimate +class spell_volkaal_reanimate : public SpellScript +{ + void HandleScript(SpellEffIndex /*effIndex*/) const + { + GetCaster()->RemoveAurasDueToSpell(SPELL_SOUL_ANCHOR); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_volkaal_reanimate::HandleScript, EFFECT_0, SPELL_EFFECT_HEAL_PCT); + } +}; + +// 250241 - Rapid Decay +class spell_volkaal_rapid_decay : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo ({ SPELL_RAPID_DECAY_TARGET, SPELL_RAPID_DECAY_RANDOM }); + } + + void HandleToxicPool(AuraEffect const* aurEff) const + { + Unit* caster = GetCaster(); + if (!caster) + return; + + float range = 100.0f; + Player* player = nullptr; + Trinity::AnyPlayerInObjectRangeCheck check(caster, range); + Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(caster, player, check); + Cell::VisitWorldObjects(caster, searcher, range); + + CastSpellExtraArgs args; + args.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR; + args.TriggeringAura = aurEff; + caster->CastSpell(player->GetPosition(), SPELL_RAPID_DECAY_TARGET, args); + // not present in 11.0.7 + //caster->CastSpell(caster, SPELL_RAPID_DECAY_RANDOM, args); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_volkaal_rapid_decay::HandleToxicPool, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); + } +}; + +// 250696 - Rapid Decay +// ID - 11243 +struct at_volkaal_rapid_decay : AreaTriggerAI +{ + at_volkaal_rapid_decay(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } + + void OnUnitEnter(Unit* unit) override + { + if (!unit->IsPlayer()) + return; + + unit->CastSpell(unit, SPELL_TOXIC_POOL, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR); + } + + void OnUnitExit(Unit* unit) override + { + unit->RemoveAurasDueToSpell(SPELL_TOXIC_POOL); + } +}; + +void AddSC_boss_volkaal() +{ + RegisterAtalDazarCreatureAI(boss_volkaal); + RegisterAtalDazarCreatureAI(npc_volkaal_reanimation_totem); + + RegisterSpellScript(spell_volkaal_lingering_nausea); + RegisterSpellScript(spell_volkaal_noxious_stench); + RegisterSpellScript(spell_volkaal_toxic_leap_selector); + RegisterSpellScript(spell_volkaal_toxic_leap); + RegisterSpellScript(spell_volkaal_soul_anchor); + RegisterSpellScript(spell_volkaal_reanimate); + RegisterSpellScript(spell_volkaal_rapid_decay); + + RegisterAreaTriggerAI(at_volkaal_rapid_decay); +} diff --git a/src/server/scripts/Zandalar/AtalDazar/instance_atal_dazar.cpp b/src/server/scripts/Zandalar/AtalDazar/instance_atal_dazar.cpp index 6bf3af91f54..fd84c32d220 100644 --- a/src/server/scripts/Zandalar/AtalDazar/instance_atal_dazar.cpp +++ b/src/server/scripts/Zandalar/AtalDazar/instance_atal_dazar.cpp @@ -23,9 +23,10 @@ BossBoundaryData const boundaries = { { DATA_REZAN, new ZRangeBoundary(639.0f, 650.0f) }, // 647.65f + { DATA_VOLKAAL, new ZRangeBoundary(709.0f, 730.0f) }, }; -ObjectData const creatureData[] = +constexpr ObjectData creatureData[] = { { BOSS_PRIESTESS_ALUNZA, DATA_PRIESTESS_ALUNZA }, { BOSS_VOLKAAL, DATA_VOLKAAL }, @@ -34,7 +35,16 @@ ObjectData const creatureData[] = { 0, 0 } // END }; -DungeonEncounterData const encounters[] = +constexpr DoorData doorData[] = +{ + { GO_VOLKAAL_DOOR_1, DATA_VOLKAAL, EncounterDoorBehavior::OpenWhenNotInProgress }, + { GO_VOLKAAL_DOOR_2, DATA_VOLKAAL, EncounterDoorBehavior::OpenWhenNotInProgress }, + { GO_VOLKAAL_DOOR_3, DATA_VOLKAAL, EncounterDoorBehavior::OpenWhenNotInProgress }, + { GO_VOLKAAL_DOOR_4, DATA_VOLKAAL, EncounterDoorBehavior::OpenWhenNotInProgress }, + { 0, 0, EncounterDoorBehavior::OpenWhenNotInProgress } // END +}; + +constexpr DungeonEncounterData encounters[] = { { DATA_PRIESTESS_ALUNZA, {{ 2084 }} }, { DATA_VOLKAAL, {{ 2085 }} }, @@ -54,6 +64,7 @@ public: SetHeaders(DataHeader); SetBossNumber(EncounterCount); LoadObjectData(creatureData, nullptr); + LoadDoorData(doorData); LoadBossBoundaries(boundaries); LoadDungeonEncounterData(encounters); } diff --git a/src/server/scripts/Zandalar/zandalar_script_loader.cpp b/src/server/scripts/Zandalar/zandalar_script_loader.cpp index d907c8036c3..44d821e6c3d 100644 --- a/src/server/scripts/Zandalar/zandalar_script_loader.cpp +++ b/src/server/scripts/Zandalar/zandalar_script_loader.cpp @@ -20,6 +20,7 @@ // Atal'Dazar void AddSC_instance_atal_dazar(); void AddSC_boss_rezan(); +void AddSC_boss_volkaal(); // Underrot void AddSC_instance_underrot(); @@ -38,6 +39,7 @@ void AddZandalarScripts() // Atal'Dazar AddSC_instance_atal_dazar(); AddSC_boss_rezan(); + AddSC_boss_volkaal(); // Underrot AddSC_instance_underrot(); |