diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index ef87ec6f1..f68b45cdc 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -311,6 +311,29 @@ Creature* ScriptedAI::DoSpawnCreature(uint32 entry, float offsetX, float offsetY return me->SummonCreature(entry, me->GetPositionX() + offsetX, me->GetPositionY() + offsetY, me->GetPositionZ() + offsetZ, angle, TempSummonType(type), despawntime); } +void ScriptedAI::ScheduleTimedEvent(Milliseconds timer, std::function exec, Milliseconds repeatMin, Milliseconds repeatMax, uint32 uniqueId) +{ + if (uniqueId && IsUniqueTimedEventDone(uniqueId)) + { + return; + } + + scheduler.Schedule(timer, [exec, repeatMin, repeatMax, uniqueId](TaskContext context) + { + exec(); + + if (!uniqueId) + { + repeatMax > 0s ? context.Repeat(repeatMin, repeatMax) : context.Repeat(repeatMin); + } + }); + + if (uniqueId) + { + SetUniqueTimedEventDone(uniqueId); + } +} + SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effects) { //No target so we can't cast @@ -588,6 +611,7 @@ void BossAI::_Reset() events.Reset(); scheduler.CancelAll(); summons.DespawnAll(); + ClearUniqueTimedEventsDone(); _healthCheckEvents.clear(); if (instance) instance->SetBossState(_bossId, NOT_STARTED); diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 77735c464..29519906f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -353,6 +353,12 @@ struct ScriptedAI : public CreatureAI //Spawns a creature relative to me Creature* DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, uint32 despawntime); + bool IsUniqueTimedEventDone(uint32 id) const { return _uniqueTimedEvents.find(id) != _uniqueTimedEvents.end(); } + void SetUniqueTimedEventDone(uint32 id) { _uniqueTimedEvents.insert(id); } + void ResetUniqueTimedEvent(uint32 id) { _uniqueTimedEvents.erase(id); } + void ClearUniqueTimedEventsDone() { _uniqueTimedEvents.clear(); } + void ScheduleTimedEvent(Milliseconds timer, std::function exec, Milliseconds repeatMin, Milliseconds repeatMax = 0s, uint32 uniqueId = 0); + bool HealthBelowPct(uint32 pct) const { return me->HealthBelowPct(pct); } bool HealthAbovePct(uint32 pct) const { return me->HealthAbovePct(pct); } @@ -442,6 +448,7 @@ private: Difficulty _difficulty; bool _isCombatMovementAllowed; bool _isHeroic; + std::unordered_set _uniqueTimedEvents; }; struct HealthCheckEventData diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp index 84d8ed7a9..1d6e1c4bd 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp @@ -44,37 +44,39 @@ enum Spells struct boss_commander_sarannis : public BossAI { - boss_commander_sarannis(Creature* creature) : BossAI(creature, DATA_COMMANDER_SARANNIS), _summoned(false) { } - - void Reset() override - { - _Reset(); - _summoned = false; - } + boss_commander_sarannis(Creature* creature) : BossAI(creature, DATA_COMMANDER_SARANNIS) { } void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); Talk(SAY_AGGRO); - scheduler.Schedule(20s, [this](TaskContext context) + if (!IsHeroic()) { - if (roll_chance_i(50)) - Talk(SAY_ARCANE_RESONANCE); - DoCastVictim(SPELL_ARCANE_RESONANCE); - context.Repeat(27s); - }).Schedule(10s, [this](TaskContext context) - { - if (roll_chance_i(50)) - Talk(SAY_ARCANE_DEVASTATION); - DoCastVictim(SPELL_ARCANE_DEVASTATION); - context.Repeat(17s); - }); - - if (IsHeroic()) + ScheduleHealthCheckEvent(55, [&] { + ScheduleReinforcements(); + }); + } + else { ScheduleReinforcements(); } + + ScheduleTimedEvent(20s, [&] { + if (roll_chance_i(50)) + { + Talk(SAY_ARCANE_RESONANCE); + } + DoCastVictim(SPELL_ARCANE_RESONANCE); + }, 27s); + + ScheduleTimedEvent(10s, [&] { + if (roll_chance_i(50)) + { + Talk(SAY_ARCANE_DEVASTATION); + } + DoCastVictim(SPELL_ARCANE_DEVASTATION); + }, 17s); } void KilledUnit(Unit* victim) override @@ -91,15 +93,6 @@ struct boss_commander_sarannis : public BossAI Talk(SAY_DEATH); } - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override - { - if (!_summoned && me->HealthBelowPctDamaged(55, damage) && !IsHeroic()) - { - _summoned = true; - ScheduleReinforcements(); - } - } - void ScheduleReinforcements() { scheduler.Schedule(IsHeroic() ? 1min : 1s, [this](TaskContext context) @@ -114,9 +107,6 @@ struct boss_commander_sarannis : public BossAI } }); } - - private: - bool _summoned; }; // 34799 - Arcane Devastation