From cb07d1fc8a40b44595a785045458f3f41bbba95c Mon Sep 17 00:00:00 2001 From: patou01 <2592673+patou01@users.noreply.github.com> Date: Sun, 7 Nov 2021 10:10:19 +0100 Subject: [PATCH] fix(Scripts/DB): UBRS Solakar / father flame (#8236) --- .../rev_1633268017505597200.sql | 27 ++ .../BlackrockSpire/blackrock_spire.h | 11 +- .../boss_solakar_flamewreath.cpp | 248 ++++++++++++++++++ .../instance_blackrock_spire.cpp | 119 ++++++++- .../eastern_kingdoms_script_loader.cpp | 2 + 5 files changed, 398 insertions(+), 9 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1633268017505597200.sql create mode 100644 src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp diff --git a/data/sql/updates/pending_db_world/rev_1633268017505597200.sql b/data/sql/updates/pending_db_world/rev_1633268017505597200.sql new file mode 100644 index 000000000..d64872cb0 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1633268017505597200.sql @@ -0,0 +1,27 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1633268017505597200'); + +-- rookery guardians +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 10258; +DELETE FROM `smart_scripts` WHERE `entryorguid` = 10258 AND `source_type` = 0 AND (`id` IN (0, 1, 2, 3)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(10258, 0, 0, 0, 63, 0, 100, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 25, 500, 1, 0, 0, 0, 0, 0, 0, 'Rookery Guardian - On Just Created - Start Attacking'), +(10258, 0, 1, 0, 0, 0, 100, 2, 10000, 12000, 10000, 15000, 0, 11, 15572, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Rookery Guardian - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'), +(10258, 0, 2, 0, 0, 0, 100, 2, 5000, 7000, 4000, 6000, 0, 11, 15580, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Rookery Guardian - In Combat - Cast \'Strike\' (Normal Dungeon)'); + +-- rookery hatcher +UPDATE `creature_template` SET `ScriptName` = 'npc_rookery_hatcher' WHERE `entry` = 10683; +DELETE FROM `creature_text` WHERE `CreatureID` = 10683; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `Comment`) VALUES +(10683, 0, 0, 'Intruders are destroying our eggs! Stop!!', 14, 0, 0, 0, 5538, 0, 'UBRS - Solakar event'); + +-- solakar +UPDATE `creature_template` SET `ScriptName` = 'boss_solakar_flamewreath' WHERE `entry` = 10264; + +-- father flame +UPDATE `gameobject_template` SET `ScriptName` = 'go_father_flame' WHERE `entry` = 175245; +DELETE FROM `smart_scripts` WHERE `entryorguid` = 175245 AND `source_type` = 1 AND `id` = 0; + +-- partial cleanup for the eggs +DELETE FROM `gameobject_template` WHERE `entry` = 175622; +DELETE FROM `gameobject_template_addon` WHERE `entry` = 175622; +DELETE FROM `smart_scripts` WHERE `entryorguid` = 175622; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h index 335cda813..5fb2739c3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h @@ -49,7 +49,8 @@ enum DataTypes DATA_HALL_RUNE_4 = 19, DATA_HALL_RUNE_5 = 20, DATA_HALL_RUNE_6 = 21, - DATA_HALL_RUNE_7 = 22 + DATA_HALL_RUNE_7 = 22, + DATA_SOLAKAR_FLAMEWREATH = 23 }; enum CreaturesIds @@ -73,6 +74,12 @@ enum CreaturesIds NPC_BLACKHAND_VETERAN = 9819, NPC_BLACKHAND_INCARCERATOR = 10316, NPC_LORD_VICTOR_NEFARIUS = 10162, + + NPC_SOLAKAR = 10264, + NPC_ROOKERY_GUARDIAN = 10258, + NPC_ROOKERY_HATCHER = 10683, + NPC_ROOKERY_WHELP = 10161, + NPC_UROK_MAGUS = 10602, NPC_UROK_ENFORCER = 10601, NPC_FINKLE_EINHORN = 10776 @@ -91,7 +98,7 @@ enum AdditionalData enum GameObjectsIds { - GO_WHELP_SPAWNER = 175622, // trap spawned by go id 175124 + GO_ROOKERY_EGG = 175124, // Doors GO_EMBERSEER_IN = 175244, // First door to Pyroguard Emberseer GO_DOORS = 175705, // Second door to Pyroguard Emberseer diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp new file mode 100644 index 000000000..9e5b57c81 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp @@ -0,0 +1,248 @@ +/* + * This file is part of the AzerothCore 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 Affero General Public License as published by the + * Free Software Foundation; either version 3 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 Affero 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "blackrock_spire.h" + +enum Spells +{ + SPELL_WAR_STOMP = 16727, + SPELL_HATCH_EGG = 15746 +}; + +enum Timer +{ + TIMER_WAR_STOMP = 20000 +}; + +constexpr float RANGE_SPELL_HATCH_EGG = 3.0f; // needed because the eggs seem to hatch if the mobs goes too close +constexpr float RANGE_WHELP_CALL_HELP = 15.0f; // range for the hatchers to call nearby whelps after having summoned them. + +enum Says +{ + SAY_SUMMON = 0, +}; + +class npc_rookery_hatcher : public CreatureScript +{ +public: + npc_rookery_hatcher() : CreatureScript("npc_rookery_hatcher") {} + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackrockSpireAI(creature); + } + + struct npc_rookery_hatcherAI : public CreatureAI + { + npc_rookery_hatcherAI(Creature* creature) : CreatureAI(creature) {} + + EventMap events; + std::list nearbyEggs; + GameObject* targetEgg; + Position targetPosition; + + void InitializeAI() override + { + CreatureAI::InitializeAI(); + DoZoneInCombat(nullptr, 100.0f); + nearbyEggs.clear(); + targetEgg = nullptr; + } + + void EnterCombat(Unit* /*who*/) override + { + events.ScheduleEvent(SPELL_HATCH_EGG, 1000); + } + + void UpdateAI(uint32 diff) override + { + std::list nearbyEggs; + float tempDist = 20; + float minDist = 25; + std::list nearbyWhelps; + + if (!UpdateVictim()) + { + return; + } + + GetCreatureListWithEntryInGrid(nearbyWhelps, me, NPC_ROOKERY_WHELP, RANGE_WHELP_CALL_HELP); + for (const auto& whelp : nearbyWhelps) + { + if (!whelp->IsInCombat()) + { + whelp->SetInCombatWith(me->GetVictim()); + whelp->AI()->AttackStart(me->GetVictim()); + } + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case SPELL_HATCH_EGG: + if (!targetEgg) // no target, try to find one + { + minDist = 50; + tempDist = 50; + me->GetGameObjectListWithEntryInGrid(nearbyEggs, GO_ROOKERY_EGG, 40); + for (const auto& egg : nearbyEggs) + { + if (egg->isSpawned() && egg->getLootState() == GO_READY) + { + tempDist = me->GetDistance2d(egg); + if (tempDist < minDist) + { + minDist = tempDist; + targetEgg = egg; + } + } + } + } + + if (targetEgg) //have a target, go to it and cast it + { + me->GetMotionMaster()->MovePoint(0, targetEgg->GetPosition()); + } + break; + default: + break; + } + } + + // cast takes 1.5second, during which we don't have a target + if (targetEgg && targetEgg->getLootState() == GO_READY && me->GetDistance2d(targetEgg) < RANGE_SPELL_HATCH_EGG) + { + me->StopMovingOnCurrentPos(); + me->SetFacingToObject(targetEgg); + targetPosition = me->GetPosition(); + DoCast(SPELL_HATCH_EGG); + targetEgg = nullptr; + events.ScheduleEvent(SPELL_HATCH_EGG, urand(6000, 8000)); + } + else if (!me->HasUnitState(UNIT_STATE_CASTING) && !targetEgg) + { + if (Unit* victim = me->GetVictim()) + { + AttackStart(victim); + } + + if (me->GetDistance2d(me->GetVictim()) > me->GetMeleeReach()) + { + me->GetMotionMaster()->MovePoint(0, me->GetVictim()->GetPosition()); // a bit hacky, but needed to start moving once we've summoned an egg + } + } + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_solakar_flamewreath : public CreatureScript +{ +public: + boss_solakar_flamewreath() : CreatureScript("boss_solakar_flamewreath") { } + + struct boss_solakar_flamewreathAI : public BossAI + { + boss_solakar_flamewreathAI(Creature* creature) : BossAI(creature, DATA_SOLAKAR_FLAMEWREATH) {} + + uint32 resetTimer; + + void Reset() override + { + _Reset(); + resetTimer = 10000; + } + + void InitializeAI() override + { + BossAI::InitializeAI(); + Talk(SAY_SUMMON); + DoZoneInCombat(nullptr, 100.0f); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + events.ScheduleEvent(SPELL_WAR_STOMP, urand(17000, 20000)); + resetTimer = 0; + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SetData(DATA_SOLAKAR_FLAMEWREATH, DONE); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case SPELL_WAR_STOMP: + DoCastVictim(SPELL_WAR_STOMP); + events.ScheduleEvent(SPELL_WAR_STOMP, urand(17000, 20000)); + break; + + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + resetTimer -= diff; + if (resetTimer < diff) + { + instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL); + } + return; + } + resetTimer = 10000; + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + { + return; + } + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackrockSpireAI(creature); + } +}; + +void AddSC_boss_solakar_flamewreath() +{ + new boss_solakar_flamewreath(); + new npc_rookery_hatcher(); +} diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp index 844788307..b297a7a85 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp @@ -26,19 +26,34 @@ #include "ScriptedCreature.h" #include "ScriptMgr.h" -//uint32 const DragonspireRunes[7] = { GO_HALL_RUNE_1, GO_HALL_RUNE_2, GO_HALL_RUNE_3, GO_HALL_RUNE_4, GO_HALL_RUNE_5, GO_HALL_RUNE_6, GO_HALL_RUNE_7 }; - uint32 const DragonspireMobs[3] = { NPC_BLACKHAND_DREADWEAVER, NPC_BLACKHAND_SUMMONER, NPC_BLACKHAND_VETERAN }; enum EventIds { EVENT_DARGONSPIRE_ROOM_STORE = 1, - EVENT_DARGONSPIRE_ROOM_CHECK = 2 + EVENT_DARGONSPIRE_ROOM_CHECK = 2, + + EVENT_SOLAKAR_WAVE = 3 }; +enum Timers +{ + TIMER_SOLAKAR_WAVE = 30000 +}; + +enum SolakarWaves +{ + MAX_WAVE_COUNT = 5 +}; + +Position SolakarPosLeft = Position(78.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0); +Position SolakarPosRight = Position(84.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0); +Position SolakarPosBoss = Position(80.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0); + enum Texts { - SAY_NEFARIUS_REND_WIPE = 11 + SAY_NEFARIUS_REND_WIPE = 11, + SAY_SOLAKAR_FIRST_HATCHER = 0 }; class instance_blackrock_spire : public InstanceMapScript @@ -48,9 +63,16 @@ public: struct instance_blackrock_spireMapScript : public InstanceScript { + uint32 CurrentSolakarWave = 0; + uint32 SolakarState = NOT_STARTED; // there should be a global instance encounter state, where is it? + std::vector SolakarSummons; + instance_blackrock_spireMapScript(InstanceMap* map) : InstanceScript(map) { SetBossNumber(EncounterCount); + CurrentSolakarWave = 0; + SolakarState = NOT_STARTED; + SolakarSummons.clear(); } void CreatureLooted(Creature* creature, LootType loot) override @@ -140,9 +162,6 @@ public: { switch (go->GetEntry()) { - case GO_WHELP_SPAWNER: - go->CastSpell(nullptr, SPELL_SUMMON_ROOKERY_WHELP); - break; case GO_EMBERSEER_IN: go_emberseerin = go->GetGUID(); HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE, go); @@ -331,6 +350,29 @@ public: Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_STORE, 1000); } break; + case DATA_SOLAKAR_FLAMEWREATH: + switch(data) + { + case IN_PROGRESS: + if (SolakarState == NOT_STARTED) + { + Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, 500); + } + break; + case FAIL: + for (const auto& creature : SolakarSummons) + { + creature->RemoveFromWorld(); + } + SolakarSummons.clear(); + CurrentSolakarWave = 0; + SetData(DATA_SOLAKAR_FLAMEWREATH, NOT_STARTED); + break; + case DONE: + break; + } + SolakarState = data; + break; case DATA_UROK_DOOMHOWL: if (data == FAIL) { @@ -368,6 +410,38 @@ public: } } + uint32 GetData(uint32 type) const override + { + if (type == DATA_SOLAKAR_FLAMEWREATH) + { + return SolakarState; + } + else + { + return InstanceScript::GetData(type); + } + } + + void SummonSolakarWave(uint8 number) + { + if (number < MAX_WAVE_COUNT) + { + SolakarSummons.push_back(instance->SummonCreature(NPC_ROOKERY_GUARDIAN, SolakarPosLeft)); + SolakarSummons.push_back(instance->SummonCreature(NPC_ROOKERY_HATCHER, SolakarPosRight)); + if (number == 0) + { + if (Creature* FirstHatcher = SolakarSummons.back()) // works because we spawned a hatcher second + { + FirstHatcher->AI()->Talk(SAY_SOLAKAR_FIRST_HATCHER); + } + } + } + else if (number == MAX_WAVE_COUNT) + { + SolakarSummons.push_back(instance->SummonCreature(NPC_SOLAKAR, SolakarPosBoss)); + } + } + ObjectGuid GetGuidData(uint32 type) const override { switch (type) @@ -462,6 +536,14 @@ public: if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)) Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3000); break; + case EVENT_SOLAKAR_WAVE: + SummonSolakarWave(CurrentSolakarWave); + if (CurrentSolakarWave < MAX_WAVE_COUNT) + { + Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, TIMER_SOLAKAR_WAVE); + CurrentSolakarWave++; + } + break; default: break; } @@ -704,9 +786,32 @@ public: } }; +class go_father_flame : public GameObjectScript +{ +public: + go_father_flame() : GameObjectScript("go_father_flame") {} + + void OnLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override + { + if (InstanceScript* instance = go->GetInstanceScript()) + { + if (state == GO_ACTIVATED) + { + if (instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == IN_PROGRESS || instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == DONE) + { + return; + } + + instance->SetData(DATA_SOLAKAR_FLAMEWREATH, IN_PROGRESS); + } + } + } +}; + void AddSC_instance_blackrock_spire() { new instance_blackrock_spire(); new at_dragonspire_hall(); new at_blackrock_stadium(); + new go_father_flame(); } diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 5862cc2c1..f0fef63a5 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -43,6 +43,7 @@ void AddSC_boss_pyroguard_emberseer(); void AddSC_boss_gyth(); void AddSC_boss_rend_blackhand(); void AddSC_boss_urok_doomhowl(); +void AddSC_boss_solakar_flamewreath(); void AddSC_instance_blackrock_spire(); void AddSC_boss_razorgore(); //Blackwing lair void AddSC_boss_vaelastrasz(); @@ -179,6 +180,7 @@ void AddEasternKingdomsScripts() AddSC_boss_warmastervoone(); AddSC_boss_pyroguard_emberseer(); AddSC_boss_gyth(); + AddSC_boss_solakar_flamewreath(); AddSC_boss_rend_blackhand(); AddSC_boss_urok_doomhowl(); AddSC_instance_blackrock_spire();