From a5b4aecd52ddd7e478b14dfc31f9f701fa8e192b Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:14:46 -0300 Subject: [PATCH] fix(Scripts/TheBotanica): Rework Laj (#15279) --- src/common/Utilities/Containers.h | 15 ++ src/server/game/Entities/Creature/Creature.h | 6 + .../Outland/TempestKeep/botanica/boss_laj.cpp | 157 ++++++++---------- 3 files changed, 88 insertions(+), 90 deletions(-) diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index 84947d671..c77a48be7 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -139,6 +139,21 @@ namespace Acore::Containers return *it; } + /* + * Select a random element from a container. + * + * Note: container cannot be empty + */ + template + inline auto SelectRandomContainerElementIf(C const& container, Predicate&& predicate) -> typename std::add_const::type& + { + C containerCopy; + std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate); + auto it = std::begin(containerCopy); + std::advance(it, urand(0, uint32(std::size(containerCopy)) - 1)); + return *it; + } + /* * Select a random element from a container where each element has a different chance to be selected. * diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index ef2033317..903ae7099 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -392,6 +392,12 @@ public: void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration); + /** + * @brief Helper to resume chasing current victim. + * + * */ + void ResumeChasingVictim() { GetMotionMaster()->MoveChase(GetVictim()); }; + std::string GetDebugInfo() const override; protected: diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp index b9399aff0..5e15308d4 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp @@ -48,109 +48,86 @@ enum Misc MODEL_FIRE = 13110, MODEL_FROST = 14112, MODEL_NATURE = 14214, - - EVENT_ALERGIC_REACTION = 1, - EVENT_TRANSFORM = 2, - EVENT_TELEPORT = 3, - EVENT_SUMMON = 4 }; -class boss_laj : public CreatureScript +struct LajTransformData { -public: - boss_laj() : CreatureScript("boss_laj") { } + uint32 spellId; + uint32 modelId; +}; - struct boss_lajAI : public BossAI +LajTransformData const LajTransform[5] = +{ + { SPELL_DAMAGE_IMMUNE_SHADOW, MODEL_DEFAULT }, + { SPELL_DAMAGE_IMMUNE_ARCANE, MODEL_ARCANE }, + { SPELL_DAMAGE_IMMUNE_FIRE, MODEL_FIRE }, + { SPELL_DAMAGE_IMMUNE_FROST, MODEL_FROST }, + { SPELL_DAMAGE_IMMUNE_NATURE, MODEL_NATURE } +}; + +struct boss_laj : public BossAI +{ + boss_laj(Creature* creature) : BossAI(creature, DATA_LAJ) { } + + void Reset() override { - boss_lajAI(Creature* creature) : BossAI(creature, DATA_LAJ) { } + _Reset(); + me->SetDisplayId(MODEL_DEFAULT); + _lastTransform = LajTransform[0]; + DoCastSelf(SPELL_DAMAGE_IMMUNE_SHADOW, true); - void Reset() override + if (_transformContainer.empty()) { - _Reset(); - me->SetDisplayId(MODEL_DEFAULT); - _lastTransform = SPELL_DAMAGE_IMMUNE_SHADOW; - me->CastSpell(me, SPELL_DAMAGE_IMMUNE_SHADOW, true); - } - - void DoTransform() - { - me->RemoveAurasDueToSpell(_lastTransform); - - switch (_lastTransform = RAND(SPELL_DAMAGE_IMMUNE_SHADOW, SPELL_DAMAGE_IMMUNE_FIRE, SPELL_DAMAGE_IMMUNE_FROST, SPELL_DAMAGE_IMMUNE_NATURE, SPELL_DAMAGE_IMMUNE_ARCANE)) + for (auto const& val : LajTransform) { - case SPELL_DAMAGE_IMMUNE_SHADOW: - me->SetDisplayId(MODEL_DEFAULT); - break; - case SPELL_DAMAGE_IMMUNE_ARCANE: - me->SetDisplayId(MODEL_ARCANE); - break; - case SPELL_DAMAGE_IMMUNE_FIRE: - me->SetDisplayId(MODEL_FIRE); - break; - case SPELL_DAMAGE_IMMUNE_FROST: - me->SetDisplayId(MODEL_FROST); - break; - case SPELL_DAMAGE_IMMUNE_NATURE: - me->SetDisplayId(MODEL_NATURE); - break; + _transformContainer.push_back(val); } - - me->CastSpell(me, _lastTransform, true); } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - - events.ScheduleEvent(EVENT_ALERGIC_REACTION, 5000); - events.ScheduleEvent(EVENT_TRANSFORM, 30000); - events.ScheduleEvent(EVENT_TELEPORT, 20000); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ALERGIC_REACTION: - me->CastSpell(me->GetVictim(), SPELL_ALLERGIC_REACTION, false); - events.ScheduleEvent(EVENT_ALERGIC_REACTION, 25000); - break; - case EVENT_TELEPORT: - me->CastSpell(me, SPELL_TELEPORT_SELF, false); - events.ScheduleEvent(EVENT_SUMMON, 2500); - events.ScheduleEvent(EVENT_TELEPORT, 30000); - break; - case EVENT_SUMMON: - Talk(EMOTE_SUMMON); - me->CastSpell(me, SPELL_SUMMON_LASHER_1, true); - me->CastSpell(me, SPELL_SUMMON_FLAYER_1, true); - break; - case EVENT_TRANSFORM: - DoTransform(); - events.ScheduleEvent(EVENT_TRANSFORM, 35000); - break; - } - - DoMeleeAttackIfReady(); - } - private: - uint32 _lastTransform; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTheBotanicaAI(creature); } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + + scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_ALLERGIC_REACTION); + context.Repeat(25s); + }).Schedule(30s, [this](TaskContext context) + { + me->RemoveAurasDueToSpell(_lastTransform.spellId); + _lastTransform = Acore::Containers::SelectRandomContainerElementIf(_transformContainer, [&](LajTransformData data) -> bool + { + return data.spellId != _lastTransform.spellId; + }); + me->SetDisplayId(_lastTransform.modelId); + DoCastSelf(_lastTransform.spellId, true); + context.Repeat(35s); + }).Schedule(20s, [this](TaskContext context) + { + DoCastSelf(SPELL_TELEPORT_SELF); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->Clear(); + + scheduler.Schedule(2500ms, [this](TaskContext) + { + Talk(EMOTE_SUMMON); + DoCastAOE(SPELL_SUMMON_LASHER_1, true); + DoCastAOE(SPELL_SUMMON_FLAYER_1, true); + me->SetReactState(REACT_AGGRESSIVE); + me->ResumeChasingVictim(); + }); + + context.Repeat(30s); + }); + } + +private: + LajTransformData _lastTransform; + std::vector _transformContainer; }; void AddSC_boss_laj() { - new boss_laj(); + RegisterTheBotanicaCreatureAI(boss_laj); }