From 5b36dfa2c0fdb5eb9b34f728b80662aefb34ea34 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Sun, 18 Jun 2023 16:36:11 +0200 Subject: [PATCH 01/13] chore(Scripts/GruulsLair): modernise boss scripts + make timers more accurate (#16576) --- .../scripts/Outland/GruulsLair/boss_gruul.cpp | 119 +++---- .../GruulsLair/boss_high_king_maulgar.cpp | 329 +++++++++--------- 2 files changed, 209 insertions(+), 239 deletions(-) diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp index d6ef410ce..16eb9e89a 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp @@ -58,17 +58,6 @@ enum Spells SPELL_STONED = 33652, }; -enum Events -{ - EVENT_GROWTH = 1, - EVENT_CAVE_IN = 2, - EVENT_GROUND_SLAM = 3, - EVENT_HURTFUL_STRIKE = 4, - EVENT_REVERBERATION = 5, - EVENT_SHATTER = 6, - EVENT_RECENTLY_SPOKEN = 7 -}; - struct boss_gruul : public BossAI { boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { } @@ -76,7 +65,8 @@ struct boss_gruul : public BossAI void Reset() override { _Reset(); - _caveInTimer = 29000; + _recentlySpoken = false; + _caveInTimer = 29000ms; } void JustEngagedWith(Unit* /*who*/) override @@ -84,20 +74,61 @@ struct boss_gruul : public BossAI _JustEngagedWith(); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_GROWTH, 30000); - events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); - events.ScheduleEvent(EVENT_REVERBERATION, 20000); - events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 10000); - events.ScheduleEvent(EVENT_GROUND_SLAM, 35000); + scheduler.Schedule(30300ms, [this](TaskContext context) + { + Talk(EMOTE_GROW); + DoCastSelf(SPELL_GROWTH); + context.Repeat(30300ms); + }).Schedule(_caveInTimer, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_CAVE_IN); + if (_caveInTimer > 4000ms) + { + _caveInTimer = _caveInTimer - 1500ms; + } + context.Repeat(_caveInTimer); + }).Schedule(20s, [this](TaskContext context) + { + DoCastSelf(SPELL_REVERBERATION); + context.Repeat(22s); + }).Schedule(10s, [this](TaskContext context) + { + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f)) + { + DoCast(target, SPELL_HURTFUL_STRIKE); + } + else + { + DoCastVictim(SPELL_HURTFUL_STRIKE); + } + context.Repeat(15s); + }).Schedule(35s, [this](TaskContext context) + { + Talk(SAY_SLAM); + DoCastSelf(SPELL_GROUND_SLAM); + scheduler.DelayAll(9701ms); + scheduler.Schedule(9700ms, [this](TaskContext) + { + Talk(SAY_SHATTER); + me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND); + DoCastSelf(SPELL_SHATTER); + }); + context.Repeat(60s); + }); } void KilledUnit(Unit* /*who*/) override { - if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0) + if (!_recentlySpoken) { - events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5000); Talk(SAY_SLAY); + _recentlySpoken = true; } + + scheduler.Schedule(5s, [this](TaskContext) + { + _recentlySpoken = false; + }); } void JustDied(Unit* /*killer*/) override @@ -111,52 +142,7 @@ struct boss_gruul : public BossAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_GROWTH: - Talk(EMOTE_GROW); - DoCast(me, SPELL_GROWTH); - events.ScheduleEvent(EVENT_GROWTH, 30000); - break; - case EVENT_CAVE_IN: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CAVE_IN, false); - if (_caveInTimer >= 4000) - _caveInTimer -= 1500; - events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); - break; - case EVENT_REVERBERATION: - me->CastSpell(me, SPELL_REVERBERATION, false); - events.ScheduleEvent(EVENT_REVERBERATION, 22000); - break; - case EVENT_HURTFUL_STRIKE: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f)) - { - me->CastSpell(target, SPELL_HURTFUL_STRIKE, false); - } - else - { - me->CastSpell(me->GetVictim(), SPELL_HURTFUL_STRIKE, false); - } - events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 15000); - break; - case EVENT_GROUND_SLAM: - Talk(SAY_SLAM); - me->CastSpell(me, SPELL_GROUND_SLAM, false); - events.DelayEvents(8001); - events.ScheduleEvent(EVENT_GROUND_SLAM, 60000); - events.ScheduleEvent(EVENT_SHATTER, 8000); - break; - case EVENT_SHATTER: - Talk(SAY_SHATTER); - me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND); - me->CastSpell(me, SPELL_SHATTER, false); - break; - } + scheduler.Update(diff); if (!me->HasUnitState(UNIT_STATE_ROOT)) { @@ -165,7 +151,8 @@ struct boss_gruul : public BossAI } private: - uint32 _caveInTimer; + std::chrono::milliseconds _caveInTimer; + bool _recentlySpoken; }; struct npc_invisible_tractor_beam_source : public NullCreatureAI diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp index c00a40894..b59eeec83 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "gruuls_lair.h" enum HighKingMaulgar @@ -59,39 +60,49 @@ enum HighKingMaulgar ACTION_ADD_DEATH = 1 }; -enum HKMEvents -{ - EVENT_RECENTLY_SPOKEN = 1, - EVENT_ARCING_SMASH = 2, - EVENT_MIGHTY_BLOW = 3, - EVENT_WHIRLWIND = 4, - EVENT_CHARGING = 5, - EVENT_ROAR = 6, - EVENT_CHECK_HEALTH = 7, - - EVENT_ADD_ABILITY1 = 10, - EVENT_ADD_ABILITY2 = 11, - EVENT_ADD_ABILITY3 = 12, - EVENT_ADD_ABILITY4 = 13 -}; - struct boss_high_king_maulgar : public BossAI { - boss_high_king_maulgar(Creature* creature) : BossAI(creature, DATA_MAULGAR) { } + boss_high_king_maulgar(Creature* creature) : BossAI(creature, DATA_MAULGAR) + { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } void Reset() override { _Reset(); + _recentlySpoken = false; me->SetLootMode(0); + ScheduleHealthCheckEvent(50, [&]{ + Talk(SAY_ENRAGE); + DoCastSelf(SPELL_FLURRY); + + scheduler.Schedule(0ms, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_BERSERKER_C); + context.Repeat(35s); + }).Schedule(0ms, [this](TaskContext context) + { + DoCastSelf(SPELL_ROAR); + context.Repeat(20600ms, 29100ms); + }); + }); } void KilledUnit(Unit* /*victim*/) override { - if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0) + if(!_recentlySpoken) { - events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5s); Talk(SAY_SLAY); + _recentlySpoken = true; } + + scheduler.Schedule(5s, [this](TaskContext) + { + _recentlySpoken = false; + }); } void JustDied(Unit* /*killer*/) override @@ -126,10 +137,20 @@ struct boss_high_king_maulgar : public BossAI _JustEngagedWith(); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_ARCING_SMASH, 10s); - events.ScheduleEvent(EVENT_MIGHTY_BLOW, 15s); - events.ScheduleEvent(EVENT_WHIRLWIND, 54s); - events.ScheduleEvent(EVENT_CHECK_HEALTH, 500ms); + scheduler.Schedule(9500ms, [this](TaskContext context) + { + DoCastVictim(SPELL_ARCING_SMASH); + context.Repeat(9500ms, 12s); + }).Schedule(15700ms, [this](TaskContext context) + { + DoCastVictim(SPELL_MIGHTY_BLOW); + context.Repeat(16200ms, 19s); + }).Schedule(67000ms, [this](TaskContext context) + { + scheduler.DelayAll(15s); + DoCastSelf(SPELL_WHIRLWIND); + context.Repeat(45s, 60s); + }); } void UpdateAI(uint32 diff) override @@ -137,49 +158,12 @@ struct boss_high_king_maulgar : public BossAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ARCING_SMASH: - me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false); - events.ScheduleEvent(EVENT_ARCING_SMASH, 10s); - break; - case EVENT_MIGHTY_BLOW: - me->CastSpell(me->GetVictim(), SPELL_MIGHTY_BLOW, false); - events.ScheduleEvent(EVENT_MIGHTY_BLOW, 15s); - break; - case EVENT_WHIRLWIND: - events.DelayEvents(15s); - me->CastSpell(me, SPELL_WHIRLWIND, false); - events.ScheduleEvent(EVENT_WHIRLWIND, 54s); - break; - case EVENT_CHECK_HEALTH: - if (me->HealthBelowPct(50)) - { - Talk(SAY_ENRAGE); - me->CastSpell(me, SPELL_FLURRY, true); - events.ScheduleEvent(EVENT_CHARGING, 0s); - events.ScheduleEvent(EVENT_ROAR, 30s); - break; - } - events.ScheduleEvent(EVENT_CHECK_HEALTH, 500ms); - break; - case EVENT_ROAR: - me->CastSpell(me, SPELL_ROAR, false); - events.ScheduleEvent(EVENT_ROAR, 40s); - break; - case EVENT_CHARGING: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) - me->CastSpell(target, SPELL_BERSERKER_C, false); - events.ScheduleEvent(EVENT_CHARGING, 35s); - break; - } + scheduler.Update(diff); DoMeleeAttackIfReady(); } +private: + bool _recentlySpoken; }; struct boss_olm_the_summoner : public ScriptedAI @@ -187,15 +171,18 @@ struct boss_olm_the_summoner : public ScriptedAI boss_olm_the_summoner(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - EventMap events; SummonList summons; InstanceScript* instance; void Reset() override { - events.Reset(); + _scheduler.CancelAll(); summons.DespawnAll(); instance->SetBossState(DATA_MAULGAR, NOT_STARTED); } @@ -214,9 +201,22 @@ struct boss_olm_the_summoner : public ScriptedAI me->SetInCombatWithZone(); instance->SetBossState(DATA_MAULGAR, IN_PROGRESS); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 500ms); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 6500ms); + _scheduler.Schedule(1200ms, [this](TaskContext context) + { + DoCastSelf(SPELL_SUMMON_WFH); + context.Repeat(48500ms); + }).Schedule(6050ms, [this](TaskContext context) + { + DoCastVictim(SPELL_DARK_DECAY); + context.Repeat(6050ms); + }).Schedule(6500ms, [this](TaskContext context) + { + if (me->HealthBelowPct(90)) + { + DoCastRandomTarget(SPELL_DEATH_COIL); + } + context.Repeat(6s, 13500ms); + }); } void JustDied(Unit* /*killer*/) override @@ -234,27 +234,12 @@ struct boss_olm_the_summoner : public ScriptedAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + _scheduler.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_ADD_ABILITY1: - me->CastSpell(me, SPELL_SUMMON_WFH, false); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 50s); - break; - case EVENT_ADD_ABILITY2: - DoCastVictim(SPELL_DARK_DECAY); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 6500ms); - break; - case EVENT_ADD_ABILITY3: - DoCastRandomTarget(SPELL_DEATH_COIL); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 7s); - break; - } DoMeleeAttackIfReady(); } +private: + TaskScheduler _scheduler; }; struct boss_kiggler_the_crazed : public ScriptedAI @@ -262,14 +247,17 @@ struct boss_kiggler_the_crazed : public ScriptedAI boss_kiggler_the_crazed(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - EventMap events; InstanceScript* instance; void Reset() override { - events.Reset(); + _scheduler.CancelAll(); instance->SetBossState(DATA_MAULGAR, NOT_STARTED); } @@ -278,10 +266,35 @@ struct boss_kiggler_the_crazed : public ScriptedAI me->SetInCombatWithZone(); instance->SetBossState(DATA_MAULGAR, IN_PROGRESS); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 25s); - events.ScheduleEvent(EVENT_ADD_ABILITY4, 30s); + _scheduler.Schedule(1200ms, [this](TaskContext context) + { + DoCastVictim(SPELL_LIGHTNING_BOLT); + context.Repeat(2400ms); + }).Schedule(29s, [this](TaskContext context) + { + DoCastVictim(SPELL_ARCANE_SHOCK); + context.Repeat(7200ms, 20600ms); + }).Schedule(23s, [this](TaskContext context) + { + //changed to work similarly to Ikiss poly + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_GREATER_POLYMORPH); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, [&] + (Unit* target) -> bool + { + return target && !target->IsImmunedToSpell(spellInfo); + })) + { + DoCast(target, SPELL_GREATER_POLYMORPH); + } + context.Repeat(10900ms); + }).Schedule(30s, [this](TaskContext context) + { + if (me->SelectNearestPlayer(30.0f)) + { + DoCastAOE(SPELL_ARCANE_EXPLOSION); + } + context.Repeat(30s); + }); } void JustDied(Unit* /*killer*/) override @@ -294,36 +307,12 @@ struct boss_kiggler_the_crazed : public ScriptedAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ADD_ABILITY1: - DoCastVictim(SPELL_LIGHTNING_BOLT); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms); - break; - case EVENT_ADD_ABILITY2: - DoCastVictim(SPELL_ARCANE_SHOCK); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s); - break; - case EVENT_ADD_ABILITY3: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1)) //target method should perhaps change - me->CastSpell(target, SPELL_GREATER_POLYMORPH, false); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 11s); - break; - case EVENT_ADD_ABILITY4: - if (me->SelectNearestPlayer(30.0f)) - { - DoCastAOE(SPELL_ARCANE_EXPLOSION); - } - events.ScheduleEvent(EVENT_ADD_ABILITY4, 30s); - break; - } + _scheduler.Update(diff); DoMeleeAttackIfReady(); } +private: + TaskScheduler _scheduler; }; struct boss_blindeye_the_seer : public ScriptedAI @@ -331,14 +320,17 @@ struct boss_blindeye_the_seer : public ScriptedAI boss_blindeye_the_seer(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - EventMap events; InstanceScript* instance; void Reset() override { - events.Reset(); + _scheduler.CancelAll(); instance->SetBossState(DATA_MAULGAR, NOT_STARTED); } @@ -347,9 +339,22 @@ struct boss_blindeye_the_seer : public ScriptedAI me->SetInCombatWithZone(); instance->SetBossState(DATA_MAULGAR, IN_PROGRESS); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 11s); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 30s); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 31s); + _scheduler.Schedule(7200ms, [this](TaskContext context) + { + if (Unit* target = DoSelectLowestHpFriendly(60.0f, 50000)) + { + DoCast(target, SPELL_HEAL); + } + context.Repeat(7200ms); + }).Schedule(37500s, [this](TaskContext context) + { + DoCastSelf(SPELL_GREATER_PW_SHIELD); + _scheduler.Schedule(1200ms, [this](TaskContext) + { + DoCastSelf(SPELL_PRAYER_OH); + }); + context.Repeat(54500ms, 63s); + }); } void JustDied(Unit* /*killer*/) override @@ -362,31 +367,12 @@ struct boss_blindeye_the_seer : public ScriptedAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ADD_ABILITY1: - if (Unit* target = DoSelectLowestHpFriendly(60.0f, 50000)) - { - DoCast(target, SPELL_HEAL); - } - events.ScheduleEvent(EVENT_ADD_ABILITY1, 6s); - break; - case EVENT_ADD_ABILITY2: - DoCastSelf(SPELL_GREATER_PW_SHIELD); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 30s); - break; - case EVENT_ADD_ABILITY3: - me->CastSpell(me, SPELL_PRAYER_OH, false); - events.ScheduleEvent(EVENT_ADD_ABILITY3, 30s); - break; - } + _scheduler.Update(diff); DoMeleeAttackIfReady(); } +private: + TaskScheduler _scheduler; }; struct boss_krosh_firehand : public ScriptedAI @@ -394,14 +380,17 @@ struct boss_krosh_firehand : public ScriptedAI boss_krosh_firehand(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - EventMap events; InstanceScript* instance; void Reset() override { - events.Reset(); + _scheduler.CancelAll(); instance->SetBossState(DATA_MAULGAR, NOT_STARTED); } @@ -419,9 +408,22 @@ struct boss_krosh_firehand : public ScriptedAI me->SetInCombatWithZone(); instance->SetBossState(DATA_MAULGAR, IN_PROGRESS); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms); //spellshield - events.ScheduleEvent(EVENT_ADD_ABILITY2, 3500ms); //greater fireball - events.ScheduleEvent(EVENT_ADD_ABILITY3, 8s); //blast wave (needs to check for players in range) + _scheduler.Schedule(1200ms, [this](TaskContext context) + { + DoCastSelf(SPELL_SPELLSHIELD); + context.Repeat(30300ms); + }).Schedule(3600ms, [this](TaskContext context) + { + DoCastVictim(SPELL_GREATER_FIREBALL); + context.Repeat(3600ms); + }).Schedule(7200ms, [this](TaskContext context) + { + if (me->SelectNearestPlayer(15.0f)) + { + DoCastAOE(SPELL_BLAST_WAVE); + } + context.Repeat(7200ms); + }); } void JustDied(Unit* /*killer*/) override @@ -434,31 +436,12 @@ struct boss_krosh_firehand : public ScriptedAI if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ADD_ABILITY1: - DoCastSelf(SPELL_SPELLSHIELD); - events.ScheduleEvent(EVENT_ADD_ABILITY1, 30s); - break; - case EVENT_ADD_ABILITY2: - DoCastVictim(SPELL_GREATER_FIREBALL); - events.ScheduleEvent(EVENT_ADD_ABILITY2, 1s); - break; - case EVENT_ADD_ABILITY3: - if (me->SelectNearestPlayer(15.0f)) - { - DoCastAOE(SPELL_BLAST_WAVE); - } - events.ScheduleEvent(EVENT_ADD_ABILITY3, 8s); - break; - } + _scheduler.Update(diff); DoMeleeAttackIfReady(); } +private: + TaskScheduler _scheduler; }; void AddSC_boss_high_king_maulgar() From 6c366c760884a09ce88932f6ab275584ddfb25d5 Mon Sep 17 00:00:00 2001 From: Gultask <100873791+Gultask@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:38:19 -0300 Subject: [PATCH 02/13] fix(DB/Creature): Lower TBC Heroic bosses to level 72 (#16522) Create rev_1686617579364661600.sql --- .../pending_db_world/rev_1686617579364661600.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1686617579364661600.sql diff --git a/data/sql/updates/pending_db_world/rev_1686617579364661600.sql b/data/sql/updates/pending_db_world/rev_1686617579364661600.sql new file mode 100644 index 000000000..cea04d1cb --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1686617579364661600.sql @@ -0,0 +1,11 @@ +-- +UPDATE `creature_template` SET `minlevel` = 72, `maxlevel` = 72 WHERE `entry` IN ( +20738, -- Chrono Lord Deja (1) +20745, -- Temporus (1) +21558, -- High Botanist Freywinn (1) +21559, -- Laj (1) +21581, -- Thorngrin the Tender (1) +21582, -- Warp Splinter (1) +21712, -- Infinite Chrono-Lord (1) +22167 -- Infinite Timereaver (1) +); From d2555e8d5b27c2b82b7966f6a85e3ebfa54216eb Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sun, 18 Jun 2023 14:40:36 +0000 Subject: [PATCH 03/13] chore(DB): import pending files Referenced commit(s): 6c366c760884a09ce88932f6ab275584ddfb25d5 --- .../rev_1686617579364661600.sql => db_world/2023_06_18_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1686617579364661600.sql => db_world/2023_06_18_01.sql} (88%) diff --git a/data/sql/updates/pending_db_world/rev_1686617579364661600.sql b/data/sql/updates/db_world/2023_06_18_01.sql similarity index 88% rename from data/sql/updates/pending_db_world/rev_1686617579364661600.sql rename to data/sql/updates/db_world/2023_06_18_01.sql index cea04d1cb..ac6b9872b 100644 --- a/data/sql/updates/pending_db_world/rev_1686617579364661600.sql +++ b/data/sql/updates/db_world/2023_06_18_01.sql @@ -1,3 +1,4 @@ +-- DB update 2023_06_18_00 -> 2023_06_18_01 -- UPDATE `creature_template` SET `minlevel` = 72, `maxlevel` = 72 WHERE `entry` IN ( 20738, -- Chrono Lord Deja (1) From 50604075988a1ba1b0980b02418e9b57c86f268c Mon Sep 17 00:00:00 2001 From: Johaine <32821455+Johaine@users.noreply.github.com> Date: Sun, 18 Jun 2023 16:47:27 +0200 Subject: [PATCH 04/13] fix(Scripts/TheBlackMorass): rework time rift event logic (#16535) * Fix visual crystals This fixes the crystals not despawning on Medivh's death and being resummoned after every reset * Fix summoning circle visual after cleanup Fix respawn of summoning circle visual NPC Move respawn to same moment as Medivh respawn * Fix race condition during script cleanup after event failure This fixes the bug that rifts still spawn after shield is at 0%, enabling players to exploit the instance and defeat bosses at their own pace. In general, removing rifts schedules spawning of new rifts After failing the event (shield at 0%) this introduces a race between rift despawn and (scheduler) cleanup Fix it by introducing a check if the event has been started and should still progress. * Fix softlock of event during break after boss Make sure that the delay condition is removed if event fails Meeting certain conditions it was possible to softlock the event by extending the after-boss-break indefinitely * Cleanup failed instance without player interaction This respawns Medivh and re-enables the event 5 minutes after a failure Retrying the event shouldn't require all players to leave the instance and to reenter * Misc cleanups Remove unused DataTypes Rename variable to something more self-explanatory Remove unnecessary checks and make scheduling of rifts more straightforward Fix typos --- .../instance_the_black_morass.cpp | 105 ++++++++++-------- .../TheBlackMorass/the_black_morass.cpp | 10 +- .../TheBlackMorass/the_black_morass.h | 17 +-- 3 files changed, 75 insertions(+), 57 deletions(-) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp index 3301df8a4..e4f572fcf 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp @@ -56,7 +56,8 @@ public: _currentRift = 0; _shieldPercent = 100; _encounterNPCs.clear(); - _canSpawnPortal = true; // Delay after bosses + _noBossSpawnDelay = true; // Delay after bosses + _eventStatus = EVENT_PREPARE; } void CleanupInstance() @@ -72,10 +73,24 @@ public: _availableRiftPositions.push_back(pos); } + // prevent getting stuck if event fails during boss break + _noBossSpawnDelay = true; + instance->LoadGrid(-2023.0f, 7121.0f); if (Creature* medivh = GetCreature(DATA_MEDIVH)) { - medivh->DespawnOrUnsummon(0ms, 3s); + medivh->Respawn(); + } + for (ObjectGuid const& guid : _encounterNPCs) + { + if (guid.GetEntry() == NPC_DP_BEAM_STALKER) + { + if (Creature* creature = instance->GetCreature(guid)) + { + creature->Respawn(); + } + break; + } } } @@ -121,8 +136,8 @@ public: case NPC_RIFT_LORD: case NPC_RIFT_LORD_2: case NPC_TIME_RIFT: - case NPC_INFINITE_ASSASIN: - case NPC_INFINITE_ASSASIN_2: + case NPC_INFINITE_ASSASSIN: + case NPC_INFINITE_ASSASSIN_2: case NPC_INFINITE_WHELP: case NPC_INFINITE_CHRONOMANCER: case NPC_INFINITE_CHRONOMANCER_2: @@ -143,14 +158,14 @@ public: case DATA_CHRONO_LORD_DEJA: case DATA_TEMPORUS: { - _canSpawnPortal = false; + _noBossSpawnDelay = false; _scheduler.Schedule(2min + 30s, [this](TaskContext) { - _canSpawnPortal = true; + _noBossSpawnDelay = true; + ScheduleNextPortal(0s, Position(0.0f, 0.0f, 0.0f, 0.0f)); }); - ScheduleNextPortal(2min + 30s, Position(0.0f, 0.0f, 0.0f, 0.0f)); break; } default: @@ -163,26 +178,27 @@ public: void OnPlayerEnter(Player* player) override { - if (instance->GetPlayersCountExceptGMs() <= 1 && GetBossState(DATA_AEONUS) != DONE) + if (instance->GetPlayersCountExceptGMs() <= 1 && GetBossState(DATA_AEONUS) != DONE && _eventStatus != EVENT_IN_PROGRESS) { CleanupInstance(); } - player->SendUpdateWorldState(WORLD_STATE_BM, _currentRift > 0 ? 1 : 0); + player->SendUpdateWorldState(WORLD_STATE_BM, _eventStatus); player->SendUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent); player->SendUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); } void ScheduleNextPortal(Milliseconds time, Position lastPosition) { + // only one rift can be scheduled at any time _scheduler.CancelGroup(CONTEXT_GROUP_RIFTS); _scheduler.Schedule(time, [this, lastPosition](TaskContext context) { if (GetCreature(DATA_MEDIVH)) { - // Spawning prevented - there's a 150s delay after a boss dies. - if (!_canSpawnPortal) + // Spawning prevented: after-boss-delay or event failed/not started or last portal spawned + if (!_noBossSpawnDelay || _eventStatus == EVENT_PREPARE || _currentRift >= 18) { return; } @@ -208,19 +224,10 @@ public: instance->SummonCreature(NPC_TIME_RIFT, spawnPos); - // Here we check if we have available rift spots. - if (_currentRift < 18) - { - if (!_availableRiftPositions.empty()) - { - context.Repeat((_currentRift >= 13 ? 2min : 90s)); - } - else - { - context.Repeat(4s); - } - } + // queue next portal if group doesn't kill keepers fast enough + context.Repeat((_currentRift >= 13 ? 2min : 90s)); } + // if no rift positions are available, the next rift will be scheduled in OnCreatureRemove } context.SetGroup(CONTEXT_GROUP_RIFTS); @@ -241,8 +248,8 @@ public: case NPC_RIFT_KEEPER_MAGE: case NPC_RIFT_LORD: case NPC_RIFT_LORD_2: - case NPC_INFINITE_ASSASIN: - case NPC_INFINITE_ASSASIN_2: + case NPC_INFINITE_ASSASSIN: + case NPC_INFINITE_ASSASSIN_2: case NPC_INFINITE_WHELP: case NPC_INFINITE_CHRONOMANCER: case NPC_INFINITE_CHRONOMANCER_2: @@ -251,6 +258,7 @@ public: case NPC_INFINITE_VANQUISHER: case NPC_INFINITE_VANQUISHER_2: case NPC_DP_BEAM_STALKER: + case NPC_DP_EMITTER_STALKER: _encounterNPCs.insert(creature->GetGUID()); break; } @@ -263,7 +271,7 @@ public: switch (creature->GetEntry()) { case NPC_TIME_RIFT: - if (_currentRift < 18) + if (_currentRift < 18 && _noBossSpawnDelay && _eventStatus == EVENT_IN_PROGRESS) { if (_availableRiftPositions.size() < 3) { @@ -286,8 +294,8 @@ public: case NPC_RIFT_KEEPER_MAGE: case NPC_RIFT_LORD: case NPC_RIFT_LORD_2: - case NPC_INFINITE_ASSASIN: - case NPC_INFINITE_ASSASIN_2: + case NPC_INFINITE_ASSASSIN: + case NPC_INFINITE_ASSASSIN_2: case NPC_INFINITE_WHELP: case NPC_INFINITE_CHRONOMANCER: case NPC_INFINITE_CHRONOMANCER_2: @@ -295,6 +303,7 @@ public: case NPC_INFINITE_EXECUTIONER_2: case NPC_INFINITE_VANQUISHER: case NPC_INFINITE_VANQUISHER_2: + case NPC_DP_EMITTER_STALKER: _encounterNPCs.erase(creature->GetGUID()); break; } @@ -308,27 +317,14 @@ public: { case DATA_MEDIVH: { - DoUpdateWorldState(WORLD_STATE_BM, 1); + _eventStatus = EVENT_IN_PROGRESS; + + DoUpdateWorldState(WORLD_STATE_BM, _eventStatus); DoUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent); DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); ScheduleNextPortal(3s, Position(0.0f, 0.0f, 0.0f, 0.0f)); - for (ObjectGuid const& guid : _encounterNPCs) - { - if (guid.GetEntry() == NPC_DP_BEAM_STALKER) - { - if (Creature* creature = instance->GetCreature(guid)) - { - if (!creature->IsAlive()) - { - creature->Respawn(true); - } - } - break; - } - } - break; } case DATA_DAMAGE_SHIELD: @@ -348,6 +344,8 @@ public: if (!_shieldPercent) { + _eventStatus = EVENT_PREPARE; + if (Creature* medivh = GetCreature(DATA_MEDIVH)) { if (medivh->IsAlive() && medivh->IsAIEnabled) @@ -404,6 +402,12 @@ public: GuidSet encounterNPCSCopy = _encounterNPCs; for (ObjectGuid const& guid : encounterNPCSCopy) { + // Don't despawn permanent visual effect NPC twice or it won't respawn correctly + if (guid.GetEntry() == NPC_DP_BEAM_STALKER) + { + continue; + } + if (Creature* creature = instance->GetCreature(guid)) { creature->CastSpell(creature, SPELL_TELEPORT_VISUAL, true); @@ -412,6 +416,16 @@ public: } _scheduler.CancelAll(); + + // Step 4 - Schedule instance cleanup without player interaction + _scheduler.Schedule(300s, [this](TaskContext) + { + CleanupInstance(); + + DoUpdateWorldState(WORLD_STATE_BM, _eventStatus); + DoUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent); + DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); + }); }); }); }); @@ -447,7 +461,8 @@ public: GuidSet _encounterNPCs; uint8 _currentRift; int8 _shieldPercent; - bool _canSpawnPortal; + bool _noBossSpawnDelay; + EventStatus _eventStatus; TaskScheduler _scheduler; }; }; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp index 9df152bd1..18cd30bae 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp @@ -43,9 +43,9 @@ enum medivhMisc EVENT_OUTRO_8 = 17 }; -static std::vector firstWave = { NPC_INFINITE_ASSASIN, NPC_INFINITE_WHELP, NPC_INFINITE_CHRONOMANCER }; -static std::vector secondWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_WHELP, NPC_INFINITE_ASSASIN }; -static std::vector thirdWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_VANQUISHER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_ASSASIN }; +static std::vector firstWave = { NPC_INFINITE_ASSASSIN, NPC_INFINITE_WHELP, NPC_INFINITE_CHRONOMANCER }; +static std::vector secondWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_WHELP, NPC_INFINITE_ASSASSIN }; +static std::vector thirdWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_VANQUISHER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_ASSASSIN }; class NpcRunToHome : public BasicEvent { @@ -323,8 +323,8 @@ struct npc_time_rift : public NullCreatureAI { switch (entry) { - case NPC_INFINITE_ASSASIN: - entry = NPC_INFINITE_ASSASIN_2; + case NPC_INFINITE_ASSASSIN: + entry = NPC_INFINITE_ASSASSIN_2; break; case NPC_INFINITE_CHRONOMANCER: entry = NPC_INFINITE_CHRONOMANCER_2; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h index 6b560a505..3a8715a34 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h @@ -36,13 +36,10 @@ enum DataTypes MAX_ENCOUNTER = 3, DATA_MEDIVH = 10, - DATA_RIFT_KILLED = 11, + DATA_DAMAGE_SHIELD = 12, DATA_SHIELD_PERCENT = 13, - DATA_RIFT_NUMBER = 14, - - DATA_SUMMONED_NPC = 20, - DATA_DELETED_NPC = 21 + DATA_RIFT_NUMBER = 14 }; enum WorldStateIds @@ -52,6 +49,12 @@ enum WorldStateIds WORLD_STATE_BM_RIFT = 2784 }; +enum EventStatus +{ + EVENT_PREPARE = 0, + EVENT_IN_PROGRESS = 1 +}; + enum QuestIds { QUEST_OPENING_PORTAL = 10297, @@ -75,13 +78,13 @@ enum CreatureIds NPC_INFINITE_TIMEREAVER = 21698, NPC_AEONUS = 17881, - NPC_INFINITE_ASSASIN = 17835, + NPC_INFINITE_ASSASSIN = 17835, NPC_INFINITE_WHELP = 21818, NPC_INFINITE_CHRONOMANCER = 17892, NPC_INFINITE_EXECUTIONER = 18994, NPC_INFINITE_VANQUISHER = 18995, - NPC_INFINITE_ASSASIN_2 = 21137, + NPC_INFINITE_ASSASSIN_2 = 21137, NPC_INFINITE_CHRONOMANCER_2 = 21136, NPC_INFINITE_EXECUTIONER_2 = 21138, NPC_INFINITE_VANQUISHER_2 = 21139, From 7ae4b85c43d7cc5909e3778f5f76833c960250e7 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:54:05 -0300 Subject: [PATCH 05/13] =?UTF-8?q?fix(Scripts/HellfireRamparts):=20Fix=20Ga?= =?UTF-8?q?rgolmar=20Retalliation=20procs=20with=20=E2=80=A6=20(#16585)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(Scripts/HellfireRamparts): Fix Gargolmar Retalliation procs with targets behind him --- .../rev_1687098356342753500.sql | 4 ++++ .../boss_watchkeeper_gargolmar.cpp | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1687098356342753500.sql diff --git a/data/sql/updates/pending_db_world/rev_1687098356342753500.sql b/data/sql/updates/pending_db_world/rev_1687098356342753500.sql new file mode 100644 index 000000000..fe07a55ef --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1687098356342753500.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_gargolmar_retalliation' AND `spell_id` = 22857; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(22857, 'spell_gargolmar_retalliation'); diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp index 4718cc6fb..91a59b4f6 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp @@ -144,7 +144,28 @@ private: }; +class spell_gargolmar_retalliation : public AuraScript +{ + PrepareAuraScript(spell_gargolmar_retalliation); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (!eventInfo.GetActor() || !eventInfo.GetProcTarget()) + { + return false; + } + + return GetTarget()->isInFront(eventInfo.GetActor(), M_PI); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_gargolmar_retalliation::CheckProc); + } +}; + void AddSC_boss_watchkeeper_gargolmar() { RegisterHellfireRampartsCreatureAI(boss_watchkeeper_gargolmar); + RegisterSpellScript(spell_gargolmar_retalliation); } From 58c6a515d743a016f01d3c77916f87d2bb770f6e Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sun, 18 Jun 2023 14:56:34 +0000 Subject: [PATCH 06/13] chore(DB): import pending files Referenced commit(s): 7ae4b85c43d7cc5909e3778f5f76833c960250e7 --- .../rev_1687098356342753500.sql => db_world/2023_06_18_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1687098356342753500.sql => db_world/2023_06_18_02.sql} (83%) diff --git a/data/sql/updates/pending_db_world/rev_1687098356342753500.sql b/data/sql/updates/db_world/2023_06_18_02.sql similarity index 83% rename from data/sql/updates/pending_db_world/rev_1687098356342753500.sql rename to data/sql/updates/db_world/2023_06_18_02.sql index fe07a55ef..71f6603e1 100644 --- a/data/sql/updates/pending_db_world/rev_1687098356342753500.sql +++ b/data/sql/updates/db_world/2023_06_18_02.sql @@ -1,3 +1,4 @@ +-- DB update 2023_06_18_01 -> 2023_06_18_02 -- DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_gargolmar_retalliation' AND `spell_id` = 22857; INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES From a15016ac08a06207b50fff544cd3f7fafc375c9f Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Sun, 18 Jun 2023 17:06:59 +0200 Subject: [PATCH 07/13] fix(Scripts/ZulFarrak): add Hearthstone mechanic to Blys party when event not started in time (#16333) * initial * codestyle * remove unused taskscheduler * fix unsummon mechanic better syntax * fix other issues * another issue * dummy fix * should fix gossip and event * attempt to fix movement * attempt at fixing Bly walk * also make Weegli hostile + another attempt at move ment fix * another attempt at walk fix * initialise and debug * debuggo * v2 * moooore * oops * try to fix with boolean again * fix? * fixmaybe * revert * remove leftovers * and more on Weegli --- .../scripts/Kalimdor/ZulFarrak/zulfarrak.cpp | 93 ++++++++++++++----- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp index ce7a3af22..1689944cf 100644 --- a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp +++ b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp @@ -44,6 +44,7 @@ enum blySays enum blySpells { + SPELL_BLYS_BAND_ESCAPE = 11365, SPELL_SHIELD_BASH = 11972, SPELL_REVENGE = 12170 }; @@ -64,6 +65,7 @@ public: void InitializeAI() override { + ableToPortHome = false; startedFight = false; me->SetFaction(FACTION_FRIENDLY); postGossipStep = 0; @@ -74,16 +76,33 @@ public: InstanceScript* instance; bool startedFight; + bool ableToPortHome; uint32 postGossipStep; uint32 Text_Timer; uint32 ShieldBash_Timer; - uint32 Revenge_Timer; //this is wrong, spell should never be used unless me->GetVictim() dodge, parry or block attack. Trinity support required. + uint32 Revenge_Timer; //this is wrong, spell should never be used unless me->GetVictim() dodge, parry or block attack. Trinity support required. + uint32 Porthome_Timer; ObjectGuid PlayerGUID; void Reset() override { ShieldBash_Timer = 5000; Revenge_Timer = 8000; + Porthome_Timer = 156000; + ableToPortHome = false; + startedFight = false; + } + + void EnterEvadeMode(EvadeReason /*reason*/) override + { + if (ableToPortHome) + return; + + if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS) + { + ableToPortHome = true; + Porthome_Timer = 156000; + } } void MovementInform(uint32 type, uint32 /*id*/) override @@ -112,6 +131,7 @@ public: switch (postGossipStep) { case 1: + startedFight = true; //weegli doesn't fight - he goes & blows up the door if (Creature* pWeegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI))) { @@ -128,6 +148,7 @@ public: me->SetFaction(FACTION_MONSTER); Player* target = ObjectAccessor::GetPlayer(*me, PlayerGUID); + switchFactionIfAlive(NPC_WEEGLI, target); switchFactionIfAlive(NPC_RAVEN, target); switchFactionIfAlive(NPC_ORO, target); switchFactionIfAlive(NPC_MURTA, target); @@ -146,6 +167,37 @@ public: } } + if (Porthome_Timer <= diff && ableToPortHome == true) + { + if (Creature* weegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI))) + { + weegli->CastSpell(weegli, SPELL_BLYS_BAND_ESCAPE); + weegli->DespawnOrUnsummon(10000); + } + if (Creature* raven = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_RAVEN))) + { + raven->CastSpell(raven, SPELL_BLYS_BAND_ESCAPE); + raven->DespawnOrUnsummon(10000); + } + if (Creature* oro = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ORO))) + { + oro->CastSpell(oro, SPELL_BLYS_BAND_ESCAPE); + oro->DespawnOrUnsummon(10000); + } + if (Creature* murta = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURTA))) + { + murta->CastSpell(murta, SPELL_BLYS_BAND_ESCAPE); + murta->DespawnOrUnsummon(10000); + } + DoCastSelf(SPELL_BLYS_BAND_ESCAPE); + me->DespawnOrUnsummon(10000); + Porthome_Timer = 156000; //set timer back so that the event doesn't keep triggering + } + else + { + Porthome_Timer -= diff; + } + if (!UpdateVictim()) { return; @@ -176,6 +228,7 @@ public: void DoAction(int32 /*param*/) override { + ableToPortHome = false; postGossipStep = 1; Text_Timer = 0; } @@ -211,9 +264,8 @@ public: void sGossipHello(Player* player) override { - if (instance->GetData(DATA_PYRAMID) >= PYRAMID_DESTROY_GATES && !startedFight) + if (instance->GetData(DATA_PYRAMID) >= PYRAMID_MOVED_DOWNSTAIRS && !startedFight) { - startedFight = true; AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_BLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); SendGossipMenuFor(player, 1517, me->GetGUID()); } @@ -261,6 +313,17 @@ public: instance->SetData(DATA_PYRAMID, PYRAMID_CAGES_OPEN); + //setting gossip option as soon as the cages open + if(Creature* bly = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BLY))) + { + bly->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + + if(Creature* weegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI))) + { + weegli->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + //set bly & co to aggressive & start moving to top of stairs initBlyCrewMember(NPC_BLY, 1884.99f, 1263, 41.52f); initBlyCrewMember(NPC_RAVEN, 1882.5f, 1263, 41.52f); @@ -281,15 +344,6 @@ public: crew->GetMotionMaster()->MovePoint(1, { x, y, z, 4.78f }); crew->SetFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); - switch (entry) - { - case NPC_BLY: - case NPC_WEEGLI: - crew->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - break; - default: - break; - } } } }; @@ -429,13 +483,13 @@ public: { if (instance->GetData(DATA_PYRAMID) == PYRAMID_CAGES_OPEN) { + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); instance->SetData(DATA_PYRAMID, PYRAMID_ARRIVED_AT_STAIR); Talk(SAY_WEEGLI_OHNO); } - else if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS) + else if (instance->GetData(DATA_PYRAMID) >= PYRAMID_KILLED_ALL_TROLLS && instance->GetData(DATA_PYRAMID) < PYRAMID_DESTROY_GATES) { instance->SetData(DATA_PYRAMID, PYRAMID_MOVED_DOWNSTAIRS); - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); } else if (instance->GetData(DATA_PYRAMID) == PYRAMID_DESTROY_GATES) { @@ -452,13 +506,13 @@ public: if (instance->GetData(DATA_PYRAMID) == PYRAMID_CAGES_OPEN) { + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); instance->SetData(DATA_PYRAMID, PYRAMID_ARRIVED_AT_STAIR); Talk(SAY_WEEGLI_OHNO); } - else if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS) + else if (instance->GetData(DATA_PYRAMID) >= PYRAMID_KILLED_ALL_TROLLS && instance->GetData(DATA_PYRAMID) < PYRAMID_DESTROY_GATES) { instance->SetData(DATA_PYRAMID, PYRAMID_MOVED_DOWNSTAIRS); - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); } else if (instance->GetData(DATA_PYRAMID) == PYRAMID_DESTROY_GATES) { @@ -476,10 +530,6 @@ public: me->SetHomePosition(1858.57f, 1146.35f, 14.745f, 3.85f); Talk(SAY_WEEGLI_OK_I_GO); instance->SetData(DATA_PYRAMID, PYRAMID_DESTROY_GATES); - if (Creature* sergeantBly = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BLY))) - { - sergeantBly->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - } } } @@ -501,6 +551,7 @@ public: switch (instance->GetData(DATA_PYRAMID)) { case PYRAMID_MOVED_DOWNSTAIRS: + case PYRAMID_KILLED_ALL_TROLLS: AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_WEEGLI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); SendGossipMenuFor(player, 1514, me->GetGUID()); //if event can proceed to end break; @@ -508,7 +559,7 @@ public: SendGossipMenuFor(player, 1511, me->GetGUID()); //if event not started break; default: - SendGossipMenuFor(player, 1513, me->GetGUID()); //if event are in progress + SendGossipMenuFor(player, 1513, me->GetGUID()); //if event is in progress } } }; From 52154521fa2c1ce62885229c7de74c9d96fcb1a9 Mon Sep 17 00:00:00 2001 From: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Date: Sun, 18 Jun 2023 19:08:02 +0200 Subject: [PATCH 08/13] fix(DB/Item): Remove wrong RandomProperties enchantments (#16584) fix(DB/Item): Remove wrong RandomProperties --- data/sql/updates/pending_db_world/rev_1687097711262524400.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1687097711262524400.sql diff --git a/data/sql/updates/pending_db_world/rev_1687097711262524400.sql b/data/sql/updates/pending_db_world/rev_1687097711262524400.sql new file mode 100644 index 000000000..ef8675384 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1687097711262524400.sql @@ -0,0 +1,3 @@ +-- + +DELETE FROM `item_enchantment_template` WHERE `entry` = 5173 AND `ench` IN (29,33,91,197,231,927,1399,1913,1952,2067,2068,2069); From 418e407c2a988e980f74cea49f86a3bf5a310664 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sun, 18 Jun 2023 17:10:16 +0000 Subject: [PATCH 09/13] chore(DB): import pending files Referenced commit(s): 52154521fa2c1ce62885229c7de74c9d96fcb1a9 --- .../rev_1687097711262524400.sql => db_world/2023_06_18_03.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1687097711262524400.sql => db_world/2023_06_18_03.sql} (75%) diff --git a/data/sql/updates/pending_db_world/rev_1687097711262524400.sql b/data/sql/updates/db_world/2023_06_18_03.sql similarity index 75% rename from data/sql/updates/pending_db_world/rev_1687097711262524400.sql rename to data/sql/updates/db_world/2023_06_18_03.sql index ef8675384..b9b51f1a5 100644 --- a/data/sql/updates/pending_db_world/rev_1687097711262524400.sql +++ b/data/sql/updates/db_world/2023_06_18_03.sql @@ -1,3 +1,4 @@ +-- DB update 2023_06_18_02 -> 2023_06_18_03 -- DELETE FROM `item_enchantment_template` WHERE `entry` = 5173 AND `ench` IN (29,33,91,197,231,927,1399,1913,1952,2067,2068,2069); From ec5eabce25192b5768172838f9a4a2d45ec1ef72 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 18 Jun 2023 15:29:19 -0300 Subject: [PATCH 10/13] fix(Scripts/Karazhan): Malchezaar should not cast Enfeeble on phase 3 (#16587) --- .../Karazhan/boss_prince_malchezaar.cpp | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp index 439451504..9c8a293f9 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp @@ -119,6 +119,47 @@ struct boss_malchezaar : public BossAI { Initialize(); _Reset(); + + ScheduleHealthCheckEvent(60, [&] { + me->InterruptNonMeleeSpells(false); + _phase = 2; + DoCastSelf(SPELL_EQUIP_AXES); + Talk(SAY_AXE_TOSS1); + DoCastSelf(SPELL_THRASH_AURA, true); + SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE); + me->SetCanDualWield(true); + me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK) * 150) / 100); + + scheduler.Schedule(5s, 10s, [this](TaskContext context) + { + DoCastVictim(SPELL_SUNDER_ARMOR); + context.Repeat(); + }); + + scheduler.CancelGroup(GROUP_SHADOW_WORD_PAIN); + }); + + ScheduleHealthCheckEvent(30, [&] { + me->RemoveAurasDueToSpell(SPELL_THRASH_AURA); + Talk(SAY_AXE_TOSS2); + _phase = PHASE_THREE; + clearweapons(); + + me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); + + scheduler.Schedule(20s, 30s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_AMPLIFY_DAMAGE, 1); + context.Repeat(); + }).Schedule(20s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN); + context.SetGroup(GROUP_SHADOW_WORD_PAIN); + context.Repeat(); + }); + + scheduler.CancelGroup(GROUP_ENFEEBLE); + }); } void KilledUnit(Unit* /*victim*/) override @@ -183,49 +224,6 @@ struct boss_malchezaar : public BossAI }); } - void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (me->HealthBelowPctDamaged(60, damage) && _phase == PHASE_ONE) - { - me->InterruptNonMeleeSpells(false); - _phase = 2; - DoCastSelf( SPELL_EQUIP_AXES); - Talk(SAY_AXE_TOSS1); - DoCastSelf( SPELL_THRASH_AURA, true); - SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE); - me->SetCanDualWield(true); - me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK) * 150) / 100); - - scheduler.Schedule(5s, 10s, [this](TaskContext context) - { - DoCastVictim(SPELL_SUNDER_ARMOR); - context.Repeat(); - }); - - scheduler.CancelGroup(GROUP_SHADOW_WORD_PAIN); - } - else if (me->HealthBelowPctDamaged(30, damage) && _phase == PHASE_TWO) - { - me->RemoveAurasDueToSpell(SPELL_THRASH_AURA); - Talk(SAY_AXE_TOSS2); - _phase = PHASE_THREE; - clearweapons(); - - me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - - scheduler.Schedule(20s, 30s, [this](TaskContext context) - { - DoCastRandomTarget(SPELL_AMPLIFY_DAMAGE, 1); - context.Repeat(); - }).Schedule(20s, [this](TaskContext context) - { - DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN); - context.SetGroup(GROUP_SHADOW_WORD_PAIN); - context.Repeat(); - });; - } - } - void EnfeebleHealthEffect() { std::list targetList; From ee3ab6fe2a02b38a5b42da3a8be38213543d4fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDan=20Skamlji=C4=8D?= Date: Mon, 19 Jun 2023 21:12:20 +0200 Subject: [PATCH 11/13] chore(Core/ScriptMgr): Add Hooks for profession skill gains (#16526) --- .../game/Entities/Player/PlayerUpdates.cpp | 2 ++ .../Scripting/ScriptDefines/PlayerScript.cpp | 14 +++++++++++ src/server/game/Scripting/ScriptMgr.h | 25 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 71b31db10..4e703b433 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -727,6 +727,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 gathering_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING); + sScriptMgr->OnUpdateGatheringSkill(this, SkillId, SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25, gathering_skill_gain); // For skinning and Mining chance decrease with level. 1-74 - no decrease, // 75-149 - 2 times, 225-299 - 8 times @@ -804,6 +805,7 @@ bool Player::UpdateCraftSkill(uint32 spellid) uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING); + sScriptMgr->OnUpdateCraftingSkill(this, _spell_idx->second, SkillValue, craft_skill_gain); return UpdateSkillPro( _spell_idx->second->SkillLine, diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index a21f15f1d..2682193d4 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -975,6 +975,20 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, }); } +void ScriptMgr::OnUpdateGatheringSkill(Player *player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32 &gain) { + ExecuteScript([&](PlayerScript* script) + { + script->OnUpdateGatheringSkill(player, skillId, gray, green, yellow, currentLevel, gain); + }); +} + +void ScriptMgr::OnUpdateCraftingSkill(Player *player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain) { + ExecuteScript([&](PlayerScript* script) + { + script->OnUpdateCraftingSkill(player, skill, currentLevel, gain); + }); +} + bool ScriptMgr::OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll) { auto ret = IsValidBoolScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 52575dc6d..3a543c2c3 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1274,6 +1274,29 @@ public: virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { } + /** + * @brief This hook called before gathering skill gain is applied to the character. + * + * @param player Contains information about the Player sender + * @param skill_id Contains information about the skill line + * @param current Contains the current skill level for skill + * @param gray Contains the gray skill level for current application + * @param green Contains the green skill level for current application + * @param yellow Contains the yellow skill level for current application + * @param gain Contains the amount of points that should be added to the Player + */ + virtual void OnUpdateGatheringSkill(Player* /*player*/, uint32 /*skill_id*/, uint32 /*current*/, uint32 /*gray*/, uint32 /*green*/, uint32 /*yellow*/, uint32& /*gain*/) { } + + /** + * @brief This hook is called before crafting skill gain is applied to the character. + * + * @param player Contains information about the Player sender + * @param skill Contains information about the skill line + * @param current_level Contains the current skill level for skill + * @param gain Contains the amount of points that should be added to the Player + */ + virtual void OnUpdateCraftingSkill(Player* /*player*/, SkillLineAbilityEntry const* /*skill*/, uint32 /*current_level*/, uint32& /*gain*/) { } + [[nodiscard]] virtual bool OnUpdateFishingSkill(Player* /*player*/, int32 /*skill*/, int32 /*zone_skill*/, int32 /*chance*/, int32 /*roll*/) { return true; } [[nodiscard]] virtual bool CanAreaExploreAndOutdoor(Player* /*player*/) { return true; } @@ -2334,6 +2357,8 @@ public: /* PlayerScript */ void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid); bool CanRepopAtGraveyard(Player* player); void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure); + void OnUpdateGatheringSkill(Player* player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32& gain); + void OnUpdateCraftingSkill(Player* player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain); bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll); bool CanAreaExploreAndOutdoor(Player* player); void OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title); From 9a854e8da182efe5bb28b32b6c0ed9046bc32285 Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 21 Jun 2023 20:35:44 +0200 Subject: [PATCH 12/13] fix(DB/Creature): Netherweb Victim should not move or attack (#14407) * fix(DB/Creature): Netherweb Victim should not move or attack * Update netherwebvictim.sql * Update netherwebvictim.sql * Update netherwebvictim.sql --------- Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com> --- data/sql/updates/pending_db_world/netherwebvictim.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 data/sql/updates/pending_db_world/netherwebvictim.sql diff --git a/data/sql/updates/pending_db_world/netherwebvictim.sql b/data/sql/updates/pending_db_world/netherwebvictim.sql new file mode 100644 index 000000000..e17c17a9e --- /dev/null +++ b/data/sql/updates/pending_db_world/netherwebvictim.sql @@ -0,0 +1,7 @@ +DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 22355); +INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES +(22355, 1, 0, 0, 1, 0, 0, 0); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 22355 AND `id` IN (8); +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 +(22355, 0, 8, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Netherweb Victim - On Respawn - Set Reactstate Passive'); From 4d3756262d7a841afb55ffdf7161cbc4117f2cd0 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Wed, 21 Jun 2023 18:38:11 +0000 Subject: [PATCH 13/13] chore(DB): import pending files Referenced commit(s): 9a854e8da182efe5bb28b32b6c0ed9046bc32285 --- .../netherwebvictim.sql => db_world/2023_06_21_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/netherwebvictim.sql => db_world/2023_06_21_00.sql} (95%) diff --git a/data/sql/updates/pending_db_world/netherwebvictim.sql b/data/sql/updates/db_world/2023_06_21_00.sql similarity index 95% rename from data/sql/updates/pending_db_world/netherwebvictim.sql rename to data/sql/updates/db_world/2023_06_21_00.sql index e17c17a9e..5b1b9ebaf 100644 --- a/data/sql/updates/pending_db_world/netherwebvictim.sql +++ b/data/sql/updates/db_world/2023_06_21_00.sql @@ -1,3 +1,4 @@ +-- DB update 2023_06_18_03 -> 2023_06_21_00 DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 22355); INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES (22355, 1, 0, 0, 1, 0, 0, 0);