From aff2bad53443466dba94b20ce7cfa0f1eaf83ce4 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Tue, 24 Nov 2020 11:29:14 +0100 Subject: [PATCH] Scripts/FL: implement Majordomo Staghelm encounter --- .../world/4.3.4/2020_11_24_00_world.sql | 70 +++ .../Firelands/boss_majordomo_staghelm.cpp | 578 ++++++++++++++++++ .../scripts/Kalimdor/Firelands/firelands.h | 7 + .../Kalimdor/Firelands/instance_firelands.cpp | 89 +++ .../Kalimdor/kalimdor_script_loader.cpp | 2 + 5 files changed, 746 insertions(+) create mode 100644 sql/updates/world/4.3.4/2020_11_24_00_world.sql create mode 100644 src/server/scripts/Kalimdor/Firelands/boss_majordomo_staghelm.cpp diff --git a/sql/updates/world/4.3.4/2020_11_24_00_world.sql b/sql/updates/world/4.3.4/2020_11_24_00_world.sql new file mode 100644 index 00000000000..818b57a52fb --- /dev/null +++ b/sql/updates/world/4.3.4/2020_11_24_00_world.sql @@ -0,0 +1,70 @@ +UPDATE `creature_template` SET `ScriptName`= 'boss_majordomo_staghelm' WHERE `entry`= 52571; +UPDATE `creature_template` SET `mingold`= 2500000, `maxgold`= 2500000 WHERE `entry` IN (52571, 53857); +UPDATE `creature_template` SET `mingold`= 6250000, `maxgold`= 6250000 WHERE `entry` IN (53856, 53858); +UPDATE `creature_template` SET `mechanic_immune_mask`= 650854271, `lootid`= `entry` WHERE `entry` IN (52571, 53857, 53856, 53858); +UPDATE `creature_template` SET `DamageModifier`= 240, `BaseVariance`= 0.665 WHERE `entry` IN (53857, 53858); +UPDATE `creature_template` SET `DamageModifier`= 200, `BaseVariance`= 0.665 WHERE `entry` IN (52571, 53856); +UPDATE `creature_template` SET `mechanic_immune_mask`= 650854271 WHERE `entry` IN (52593, 53859, 53860, 53861); +UPDATE `creature_template` SET `DamageModifier`= 240, `BaseVariance`= 0.665 WHERE `entry` IN (53859, 53861); +UPDATE `creature_template` SET `DamageModifier`= 200, `BaseVariance`= 0.665 WHERE `entry` IN (52593, 53860); +UPDATE `creature_template` SET `AIName`= 'NullCreatureAI', `RegenHealth`= 0, `mechanic_immune_mask`= 650854271, `flags_extra`= 0x100 | 0x40000000 WHERE `entry`= 53216; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_majordomo_staghelm_form_controller', +'spell_majordomo_staghelm_clump_check', +'spell_majordomo_staghelm_leaping_flames_targeting', +'spell_majordomo_staghelm_leaping_flames', +'spell_majordomo_staghelm_searing_seeds', +'spell_majordomo_staghelm_concentration', +'spell_majordomo_staghelm_burning_orbs'); + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(98386, 'spell_majordomo_staghelm_form_controller'), +(98399, 'spell_majordomo_staghelm_clump_check'), +(100943, 'spell_majordomo_staghelm_clump_check'), +(101165, 'spell_majordomo_staghelm_leaping_flames_targeting'), +(98476, 'spell_majordomo_staghelm_leaping_flames'), +(98450, 'spell_majordomo_staghelm_searing_seeds'), +(98229, 'spell_majordomo_staghelm_concentration'), +(98451, 'spell_majordomo_staghelm_burning_orbs'); + +DELETE FROM `spell_proc` WHERE `SpellId`= 98229; +INSERT INTO `spell_proc` (`SpellId`, `SpellTypeMask`, `AttributesMask`) VALUES +(98229, 1 | 4, 0x2); + +DELETE FROM `creature_text` WHERE `CreatureID`= 52571; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES +(52571, 0, 0, 'Very well. Witness the raw power of my new Lord!', 14, 0, 100, 0, 0, 24464, 52195, 'Majordomo Staghelm - Intro'), +(52571, 1, 0, 'The master\'s power takes on many forms...', 14, 0, 100, 0, 0, 24483, 52430, 'Majordomo Staghelm - Scorpion Form'), +(52571, 2, 0, '|TInterface\\Icons\\inv_mount_hordescorpiong.blp:20|t%s transforms into a |c0087CEFA|Hspell:98379|h[Scorpion]|h|r!', 41, 0, 100, 0, 0, 0, 52646, 'Majordomo Staghelm - Announce Scorpion Form'), +(52571, 3, 0, 'Behold the rage of the Firelands!', 14, 0, 100, 0, 0, 24485, 52431, 'Majordomo Staghelm - Cat Form'), +(52571, 4, 0, '|TInterface\\Icons\\ability_druid_tigersroar.blp:20|t%s transforms into a |c0087CEFA|Hspell:98374|h[Cat]|h|r!', 41, 0, 100, 0, 0, 0, 52645, 'Majordomo Staghelm - Announce Cat Form'), +(52571, 5, 0, 'Blaze of Glory!', 14, 0, 100, 0, 0, 24472, 52427, 'Majordomo Staghelm - Searing Seeds'), +(52571, 6, 0, '|c00FF0000Searing Seeds begin to grow!|r', 41, 0, 100, 0, 0, 0, 52491, 'Majordomo Staghelm - Announce Searing Seeds'), +(52571, 7, 0, 'Nothing but ash!', 14, 0, 100, 0, 0, 24478, 52422, 'Majordomo Staghelm - Burning Orbs'), +(52571, 8, 0, '|c00FF0000%s summons Burning Orbs!|r', 41, 0, 100, 0, 0, 0, 52484, 'Majordomo Staghelm - Announce Burning Orbs'), +(52571, 9, 0, 'Burn.', 14, 0, 100, 0, 0, 24477, 52418, 'Majordomo Staghelm - Slay'), +(52571, 9, 1, 'Soon ALL of Azeroth will burn!', 14, 0, 100, 0, 0, 24479, 52419, 'Majordomo Staghelm - Slay'), +(52571, 9, 2, 'So much power!', 14, 0, 100, 0, 0, 24480, 52420, 'Majordomo Staghelm - Slay'), +(52571, 9, 3, 'You stood in the fire!', 14, 0, 100, 0, 0, 24481, 52421, 'Majordomo Staghelm - Slay'), +(52571, 10, 0, 'My studies... had only just begun...', 14, 0, 100, 0, 0, 24471, 52432, 'Majordomo Staghelm to Player'), +(52571, 11, 0, 'Well, well. I admire your tenacity. Baleroc stood guard over this keep for a thousand mortal lifetimes.', 14, 0, 100, 0, 0, 24473, 52415, 'Majordomo Staghelm - Baleroc Outro 1'), +(52571, 12, 0, 'But none may enter the Firelord\'s abode!', 14, 0, 100, 0, 0, 24474, 52416, 'Majordomo Staghelm - Baleroc Outro'), +(52571, 13, 0, 'Beg for mercy now, and I may yet allow you to live. Well, \"heroes?\" What is your answer?', 14, 0, 100, 0, 0, 24475, 52417, 'Majordomo Staghelm - Baleroc Outro'); + +UPDATE `creature_text` SET `TextRange`= 3 WHERE `CreatureID`= 52571 AND `GroupID` IN (0, 11, 12, 13); + +UPDATE `creature_model_info` SET `BoundingRadius`= 1.75, `CombatReach`= 7 WHERE `DisplayID`= 38208; +UPDATE `creature_model_info` SET `BoundingRadius`= 2, `CombatReach`= 4 WHERE `DisplayID`= 38174; +UPDATE `creature_model_info` SET `BoundingRadius`= 1.75, `CombatReach`= 7 WHERE `DisplayID`= 38747; + +UPDATE `creature_template_addon` SET `auras`= '98583' WHERE `entry`= 53216; +DELETE FROM `creature` WHERE `guid`= 338806; +DELETE FROM `creature_addon` WHERE `guid`= 338806; + +DELETE FROM `spell_custom_attr` WHERE `entry` IN (98474, 100212, 100213, 100214); +INSERT INTO `spell_custom_attr` (`entry`, `attributes`) VALUES +(98474, 0x8), +(100212, 0x8), +(100213, 0x8), +(100214, 0x8); diff --git a/src/server/scripts/Kalimdor/Firelands/boss_majordomo_staghelm.cpp b/src/server/scripts/Kalimdor/Firelands/boss_majordomo_staghelm.cpp new file mode 100644 index 00000000000..ab005a7cbce --- /dev/null +++ b/src/server/scripts/Kalimdor/Firelands/boss_majordomo_staghelm.cpp @@ -0,0 +1,578 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "firelands.h" +#include "InstanceScript.h" +#include "Map.h" +#include "MotionMaster.h" +#include "ScriptedCreature.h" +#include "ScriptMgr.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" + +enum Spells +{ + // Majordomo Staghelm + SPELL_ZERO_ENERGY_ZERO_REGEN = 72242, + SPELL_FORM_CONTROLLER = 98386, + SPELL_CONCENTRATION = 98256, + SPELL_CLUMP_CHECK = 98399, + SPELL_SCORPION_FORM = 98379, + SPELL_CAT_FORM = 98374, + SPELL_FURY = 97235, + SPELL_ADRENALINE = 97238, + SPELL_FLAME_SCYTHE = 98474, + SPELL_LEAPING_FLAMES_TARGETING = 101165, + SPELL_LEAPING_FLAMES_SUMMON = 101222, + SPELL_FIERY_CYCLONE = 98443, + SPELL_SEARING_SEEDS = 98450, + SPELL_BURNING_ORBS = 98451, + SPELL_BURNING_ORBS_SUMMON = 98565, + + // Spirit of the Flame + SPELL_STUN_AND_HATE = 101224, + + // Player + SPELL_SEARING_SEED = 98620, + SPELL_UNCOMMON_CONCENTRTATION = 98254, + SPELL_RARE_CONCENTRTATION = 98253, + SPELL_EPIC_CONCENTRTATION = 98252, + SPELL_LEGENDARY_CONCENTRATION = 98245 +}; + +enum Events +{ + // Majordomo Staghelm + EVENT_ALLOW_COMBAT = 1, + EVENT_FORM_ABILITY, + EVENT_BALEROC_DIED_1, + EVENT_BALEROC_DIED_2, + EVENT_BALEROC_DIED_3 +}; + +enum Actions +{ + ACTION_PLAYERS_CLUSTERED = 0, + ACTION_PLAYERS_SPLIT = 1, + ACTION_BALEROC_DIED = 2, + ACTION_DRUID_OF_THE_FLAME_DIED = 3 +}; + +enum Phases +{ + PHASE_INTRO = 1, + PHASE_COMBAT = 2 +}; + +enum Texts +{ + // Majordomo Staghelm + SAY_INTRO = 0, + SAY_SCORPION_FORM = 1, + SAY_ANNOUNCE_SCORPION_FORM = 2, + SAY_CAT_FORM = 3, + SAY_ANNOUNCE_CAT_FORM = 4, + SAY_SEARING_SEEDS = 5, + SAY_ANNOUNCE_SEARING_SEEDS = 6, + SAY_BURNING_ORBS = 7, + SAY_ANNOUNCE_BURNING_ORBS = 8, + SAY_SLAY = 9, + SAY_DEATH = 10, + SAY_BALEROC_DIED_1 = 11, + SAY_BALEROC_DIED_2 = 12, + SAY_BALEROC_DIED_3 = 13 +}; + +enum Points +{ + // Majordomo Staghelm + POINT_INTRO = 0 +}; + +enum class Forms +{ + Druid = 0, + Cat = 1, + Scorpion = 2 +}; + +Position const MajordomoStaghelmMovePosition = { 523.4965f, -61.987846f, 83.94701f }; + +struct boss_majordomo_staghelm : public BossAI +{ + boss_majordomo_staghelm(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_STAGHELM), + _firstTransformation(true), _splitPlayersTicks(0), _clusteredPlayersTicks(0), _currentForm(Forms::Druid), _appliedSeeds(0), _formSwitchCount(0), _killedDruidsOfTheFlameCount(0) { } + + void InitializeAI() override + { + if (instance->GetBossState(DATA_MAJORDOMO_STAGHELM) == FAIL) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + me->SetPowerType(POWER_ENERGY); + DoCastSelf(SPELL_ZERO_ENERGY_ZERO_REGEN); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + + DoCastSelf(SPELL_ZERO_ENERGY_ZERO_REGEN); + DoCastSelf(SPELL_FORM_CONTROLLER); + if (IsHeroic()) + DoCastSelf(SPELL_CONCENTRATION); + + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.SetPhase(PHASE_COMBAT); + } + + void EnterEvadeMode(EvadeReason why) override + { + BossAI::EnterEvadeMode(why); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + instance->SetBossState(DATA_MAJORDOMO_STAGHELM, FAIL); + me->DespawnOrUnsummon(); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + me->RemoveAllDynObjects(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SEARING_SEEDS); + Talk(SAY_DEATH); + } + + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + Talk(SAY_SLAY, victim); + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (pointId == POINT_INTRO) + events.ScheduleEvent(EVENT_ALLOW_COMBAT, 1s); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + + switch (summon->GetEntry()) + { + case NPC_SPIRIT_OF_THE_FLAME: + summon->CastSpell(summon, SPELL_STUN_AND_HATE); + summon->SetCorpseDelay(0); + summon->m_Events.AddEventAtOffset([summon]() + { + if (summon->IsAIEnabled) + summon->AI()->DoZoneInCombat(); + }, 1s); + break; + case NPC_BURNING_ORB: + summon->SetCorpseDelay(0); + break; + default: + break; + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_PLAYERS_CLUSTERED: + ++_clusteredPlayersTicks; + _splitPlayersTicks = 0; + break; + case ACTION_PLAYERS_SPLIT: + ++_splitPlayersTicks; + _clusteredPlayersTicks = 0; + break; + case ACTION_BALEROC_DIED: + me->setActive(true); + events.SetPhase(PHASE_INTRO); + events.ScheduleEvent(EVENT_BALEROC_DIED_1, 10s); + break; + case ACTION_DRUID_OF_THE_FLAME_DIED: + ++_killedDruidsOfTheFlameCount; + if (_killedDruidsOfTheFlameCount >= (Is25ManRaid() ? 6 : 3)) + { + events.SetPhase(PHASE_INTRO); + Talk(SAY_INTRO); + me->GetMotionMaster()->MovePoint(POINT_INTRO, MajordomoStaghelmMovePosition, true, 5.f); + } + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (action != ACTION_PLAYERS_CLUSTERED && action != ACTION_PLAYERS_SPLIT) + return; + + if ((_clusteredPlayersTicks >= 3 && _currentForm != Forms::Scorpion) + || (_splitPlayersTicks >= 3 && _currentForm != Forms::Cat)) + { + if (_formSwitchCount >= 2) + { + me->RemoveAurasDueToSpell(SPELL_SCORPION_FORM); + me->RemoveAurasDueToSpell(SPELL_CAT_FORM); + me->RemoveAurasDueToSpell(SPELL_ADRENALINE); + DoCastAOE(SPELL_FIERY_CYCLONE); + + if (_currentForm == Forms::Cat) + { + _appliedSeeds = 0; + DoCastAOE(SPELL_SEARING_SEEDS); + Talk(SAY_SEARING_SEEDS); + Talk(SAY_ANNOUNCE_SEARING_SEEDS); + } + else + { + DoCastAOE(SPELL_BURNING_ORBS); + Talk(SAY_BURNING_ORBS); + Talk(SAY_ANNOUNCE_BURNING_ORBS); + } + + _currentForm = Forms::Druid; + _formSwitchCount = 0; + return; + } + + bool useScorpionForm = _clusteredPlayersTicks > _splitPlayersTicks; + Talk(useScorpionForm ? SAY_SCORPION_FORM : SAY_CAT_FORM); + Talk(useScorpionForm ? SAY_ANNOUNCE_SCORPION_FORM : SAY_ANNOUNCE_CAT_FORM); + DoCastSelf(useScorpionForm ? SPELL_SCORPION_FORM : SPELL_CAT_FORM); + + if (!_firstTransformation) + DoCastSelf(SPELL_FURY); + else + _firstTransformation = false; + + me->RemoveAurasDueToSpell(SPELL_ADRENALINE); + events.RescheduleEvent(EVENT_FORM_ABILITY, 400ms, 0, PHASE_COMBAT); + _currentForm = useScorpionForm ? Forms::Scorpion : Forms::Cat; + ++_formSwitchCount; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ALLOW_COMBAT: + DoCastSelf(SPELL_ZERO_ENERGY_ZERO_REGEN); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + break; + case EVENT_FORM_ABILITY: + if (me->GetPower(POWER_ENERGY) == me->GetMaxPower(POWER_ENERGY)) + { + if (_currentForm == Forms::Scorpion) + DoCastVictim(SPELL_FLAME_SCYTHE); + else if (_currentForm == Forms::Cat) + DoCastAOE(SPELL_LEAPING_FLAMES_TARGETING, CastSpellExtraArgs(false).AddSpellMod(SPELLVALUE_MAX_TARGETS, 1)); + } + events.Repeat(400ms); + break; + case EVENT_BALEROC_DIED_1: + Talk(SAY_BALEROC_DIED_1); + events.ScheduleEvent(EVENT_BALEROC_DIED_2, 11s); + break; + case EVENT_BALEROC_DIED_2: + Talk(SAY_BALEROC_DIED_2); + events.ScheduleEvent(EVENT_BALEROC_DIED_3, 11s); + break; + case EVENT_BALEROC_DIED_3: + Talk(SAY_BALEROC_DIED_3); + if (!me->IsEngaged()) + me->setActive(false); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } + +private: + bool _firstTransformation; + uint32 _splitPlayersTicks; + uint32 _clusteredPlayersTicks; + Forms _currentForm; + uint8 _appliedSeeds; + uint8 _formSwitchCount; + uint8 _killedDruidsOfTheFlameCount; +}; + +class spell_majordomo_staghelm_form_controller : public AuraScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_CLUMP_CHECK }); + } + + void HandlePeriodicDummy(AuraEffect const* /*aurEff*/) + { + GetTarget()->CastSpell(nullptr, SPELL_CLUMP_CHECK, true); + } + + void Register() override + { + OnEffectPeriodic.Register(&spell_majordomo_staghelm_form_controller::HandlePeriodicDummy, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +class spell_majordomo_staghelm_clump_check : public SpellScript +{ + bool Load() override + { + _targetThreshold = GetCaster()->GetMap()->Is25ManRaid() ? 18 : 7; + return GetCaster()->IsCreature(); + } + + void FilterTargets(std::list& targets) + { + Creature* caster = GetCaster()->ToCreature(); + if (caster->IsAIEnabled) + caster->AI()->DoAction(targets.size() >= _targetThreshold ? ACTION_PLAYERS_CLUSTERED : ACTION_PLAYERS_SPLIT); + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_majordomo_staghelm_clump_check::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY_2); + } +private: + uint8 _targetThreshold = 0; +}; + +class spell_majordomo_staghelm_leaping_flames_targeting : public SpellScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_LEAPING_FLAMES_SUMMON }); + } + + void HandleDummyEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + caster->CastSpell(nullptr, SPELL_LEAPING_FLAMES_SUMMON); + caster->CastSpell(GetHitUnit(), GetEffectValue()); + } + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_majordomo_staghelm_leaping_flames_targeting::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_majordomo_staghelm_leaping_flames : public SpellScript +{ + void HandleJumpEffect(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + if (caster->IsAlive()) + caster->CastSpell(caster->GetPosition(), GetSpellInfo()->Effects[effIndex].TriggerSpell, true); + } + + void Register() override + { + OnEffectHit.Register(&spell_majordomo_staghelm_leaping_flames::HandleJumpEffect, EFFECT_0, SPELL_EFFECT_JUMP_DEST); + } +}; + +class spell_majordomo_staghelm_searing_seeds : public SpellScript +{ + void CalculateDuration(std::list& targets) + { + uint32 baseValue = 10 * IN_MILLISECONDS; + uint32 offsetValue = (GetCaster()->GetMap()->Is25ManRaid() ? 2 : 5) * IN_MILLISECONDS; + uint8 targetCount = 0; + + for (WorldObject* target : targets) + { + ++targetCount; + _durationForTarget[target->GetGUID()] = baseValue + offsetValue * targetCount; + } + } + + void HandleAuraDuration(SpellEffIndex /*effIndex*/) + { + if (Aura* aura = GetHitAura()) + { + aura->SetMaxDuration(_durationForTarget[GetHitUnit()->GetGUID()]); + aura->SetDuration(_durationForTarget[GetHitUnit()->GetGUID()]); + } + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_majordomo_staghelm_searing_seeds::CalculateDuration, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget.Register(&spell_majordomo_staghelm_searing_seeds::HandleAuraDuration, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + +private: + std::unordered_map _durationForTarget; +}; + +class spell_majordomo_staghelm_searing_seeds_AuraScript : public AuraScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_SEARING_SEED }); + } + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode().HasFlag(AuraRemoveFlags::Expired)) + GetTarget()->CastSpell(nullptr, SPELL_SEARING_SEED, true); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_majordomo_staghelm_searing_seeds_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + +class spell_majordomo_staghelm_concentration : public AuraScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( + { + SPELL_UNCOMMON_CONCENTRTATION, + SPELL_RARE_CONCENTRTATION, + SPELL_EPIC_CONCENTRTATION, + SPELL_LEGENDARY_CONCENTRATION + }); + } + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + RemoveConcentration(GetTarget()); + } + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + uint8 power = GetTarget()->GetPower(POWER_ALTERNATE_POWER); + + if (_oldPower != power) + { + uint32 oldConcentration = _currentConcentrationSpellId; + if (power == 100) + _currentConcentrationSpellId = SPELL_LEGENDARY_CONCENTRATION; + else if (power >= 75) + _currentConcentrationSpellId = SPELL_EPIC_CONCENTRTATION; + else if (power >= 50) + _currentConcentrationSpellId = SPELL_RARE_CONCENTRTATION; + else if (power >= 25) + _currentConcentrationSpellId = SPELL_UNCOMMON_CONCENTRTATION; + + if (oldConcentration != _currentConcentrationSpellId) + { + target->RemoveAurasDueToSpell(oldConcentration); + target->CastSpell(target, _currentConcentrationSpellId, true); + } + + _oldPower = power; + } + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + RemoveConcentration(GetTarget()); + GetTarget()->SetPower(POWER_ALTERNATE_POWER, 0); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_majordomo_staghelm_concentration::HandleRemove, EFFECT_0, SPELL_AURA_ENABLE_ALT_POWER, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic.Register(&spell_majordomo_staghelm_concentration::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + OnEffectProc.Register(&spell_majordomo_staghelm_concentration::HandleProc, EFFECT_0, SPELL_AURA_ENABLE_ALT_POWER); + } +private: + void RemoveConcentration(Unit* target) + { + target->RemoveAurasDueToSpell(SPELL_UNCOMMON_CONCENTRTATION); + target->RemoveAurasDueToSpell(SPELL_RARE_CONCENTRTATION); + target->RemoveAurasDueToSpell(SPELL_EPIC_CONCENTRTATION); + target->RemoveAurasDueToSpell(SPELL_LEGENDARY_CONCENTRATION); + _currentConcentrationSpellId = 0; + _oldPower = 0; + } + + uint8 _oldPower = 0; + uint32 _currentConcentrationSpellId = 0; +}; + +class spell_majordomo_staghelm_burning_orbs : public SpellScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_BURNING_ORBS_SUMMON }); + } + + void HandleDummyEffect(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + for (uint8 i = 0; i < 5; ++i) + caster->CastSpell(nullptr, SPELL_BURNING_ORBS_SUMMON); + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_majordomo_staghelm_burning_orbs::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +void AddSC_boss_majordomo_staghelm() +{ + RegisterFirelandsCreatureAI(boss_majordomo_staghelm); + RegisterSpellScript(spell_majordomo_staghelm_form_controller); + RegisterSpellScript(spell_majordomo_staghelm_clump_check); + RegisterSpellScript(spell_majordomo_staghelm_leaping_flames_targeting); + RegisterSpellScript(spell_majordomo_staghelm_leaping_flames); + RegisterSpellAndAuraScriptPair(spell_majordomo_staghelm_searing_seeds, spell_majordomo_staghelm_searing_seeds_AuraScript); + RegisterSpellScript(spell_majordomo_staghelm_concentration); + RegisterSpellScript(spell_majordomo_staghelm_burning_orbs); +} diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.h b/src/server/scripts/Kalimdor/Firelands/firelands.h index f989e443286..9bd326edb79 100644 --- a/src/server/scripts/Kalimdor/Firelands/firelands.h +++ b/src/server/scripts/Kalimdor/Firelands/firelands.h @@ -55,6 +55,11 @@ enum FLCreatureIds NPC_HARBINGER_OF_FLAME = 53793, NPC_MOLTEN_EGG_TRASH = 53914, NPC_SMOULDERING_HATCHLING = 53794, + + // Majordomo Staghelm + NPC_SPIRIT_OF_THE_FLAME = 52593, + NPC_BURNING_ORB = 53216, + NPC_DRUID_OF_THE_FLAME = 53619 }; enum GameobjectIds @@ -72,4 +77,6 @@ inline AI* GetFirelandsAI(T* obj) return GetInstanceAI(obj, FirelandsScriptName); } +#define RegisterFirelandsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetFirelandsAI) + #endif // FIRELANDS_H_ diff --git a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp index d0d856044e8..f5fb01b260d 100644 --- a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp +++ b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp @@ -60,6 +60,19 @@ private: Creature* _owner; }; +enum MajordomoStaghelmActions +{ + ACTION_BALEROC_DIED = 2, // Action 0 and 1 used by encounter + ACTION_DRUID_OF_THE_FLAME_DIED = 3 +}; + +enum Events +{ + EVENT_RESPAWN_MAJORDOMO_STAGHELM = 1 +}; + +Position const MajordomoStaghelmSpawnPosition = { 570.2274f, -61.82986f, 90.42272f, 3.1415927f }; +Position const MajordomoStaghelmRespawnPosition = { 523.4965f, -61.987846f, 83.94701f, 3.1415927f }; class instance_firelands : public InstanceMapScript { @@ -76,8 +89,23 @@ class instance_firelands : public InstanceMapScript LoadObjectData(creatureData, nullptr); } + void Create() override + { + InstanceScript::Create(); + instance->SummonCreature(BOSS_MAJORDOMO_STAGHELM, MajordomoStaghelmSpawnPosition); + } + + void Load(char const* data) override + { + InstanceScript::Load(data); + if (GetBossState(DATA_MAJORDOMO_STAGHELM) != DONE) + instance->SummonCreature(BOSS_MAJORDOMO_STAGHELM, MajordomoStaghelmSpawnPosition); + } + void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { case NPC_SMOULDERING_HATCHLING: @@ -88,6 +116,67 @@ class instance_firelands : public InstanceMapScript break; } } + + void OnUnitDeath(Unit* unit) override + { + if (!unit->IsCreature()) + return; + + switch (unit->GetEntry()) + { + case NPC_DRUID_OF_THE_FLAME: + if (Creature* majordomo = GetCreature(DATA_MAJORDOMO_STAGHELM)) + if (majordomo->IsAIEnabled) + majordomo->AI()->DoAction(ACTION_DRUID_OF_THE_FLAME_DIED); + break; + default: + break; + } + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_BALEROC: + if (state == DONE) + if (Creature* majordomo = GetCreature(DATA_MAJORDOMO_STAGHELM)) + if (majordomo->IsAIEnabled) + majordomo->AI()->DoAction(ACTION_BALEROC_DIED); + break; + case DATA_MAJORDOMO_STAGHELM: + if (state == FAIL) + _events.ScheduleEvent(EVENT_RESPAWN_MAJORDOMO_STAGHELM, 30s); + break; + default: + break; + } + + return true; + } + + void Update(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RESPAWN_MAJORDOMO_STAGHELM: + instance->SummonCreature(BOSS_MAJORDOMO_STAGHELM, MajordomoStaghelmRespawnPosition); + break; + default: + break; + } + } + } + + private: + EventMap _events; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp index 8dc472552cb..e47016ba981 100644 --- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -128,6 +128,7 @@ void AddSC_boss_alakir(); void AddSC_instance_firelands(); //Firelands void AddSC_boss_alysrazor(); void AddSC_boss_baleroc(); +void AddSC_boss_majordomo_staghelm(); void AddSC_ashenvale(); void AddSC_azuremyst_isle(); @@ -262,6 +263,7 @@ void AddKalimdorScripts() AddSC_instance_firelands(); //Firelands AddSC_boss_alysrazor(); AddSC_boss_baleroc(); + AddSC_boss_majordomo_staghelm(); AddSC_ashenvale(); AddSC_azuremyst_isle();