diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 6aada410e..09173c063 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -14,6 +14,21 @@ #include "SpellMgr.h" #include "Vehicle.h" +class PhasedRespawn : public BasicEvent +{ +public: + PhasedRespawn(Creature& owner) : BasicEvent(), _owner(owner) {} + + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override + { + _owner.RespawnOnEvade(); + return true; + } + +private: + Creature& _owner; +}; + //Disable CreatureAI when charmed void CreatureAI::OnCharmed(bool /*apply*/) { @@ -170,10 +185,50 @@ void CreatureAI::EnterEvadeMode() } } - Reset(); + // @todo: Turn into a flags_extra in creature_template + // despawn bosses at reset - only verified tbc/woltk bosses with this reset type - add bosses in last line respectively (dungeon/raid) and increase array limit + static constexpr std::array bosses = { + /* dungeons */ + 28684, /* Krik'thir the Gatewatcher */ + 36502, /* Devourer of Souls */ + 36658, /* Scourgelord Tyrannus */ + /* raids */ + 32871, /* Algalon */ + 39863, /* Halion */ + 33186, /* Razorscale */ + 36626, /* Festergut */ + 32867, /* Steelbreaker - Assembly of Iron */ + 32927, /* Runemaster Molgeim - Assembly of Iron */ + 32857, /* Stormcaller Brundir - Assembly of Iron */ + 33350, /* Mimiron */ + 16060, /* Gothik the Harvester */ + 36678, /* Professor Putricide */ + 15990, /* Kel'Thuzad */ + 33993, /* Emalon the Storm Watcher */ + 17257, /* Magtheridon */ + 25315, /* Kil'jaeden */ + 15928, /* Thaddius */ + 32930, /* Kologarn */ + 32906, /* Freya */ + 36597, /* The Lich King */ + 36853, /* Sindragosa */ + 36855, /* Lady Deathwhisper */ + 37955 /* Blood-Queen Lana'thel */ + }; - if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons! - me->GetVehicleKit()->Reset(true); + if (std::find(std::begin(bosses), std::end(bosses), me->GetEntry()) != std::end(bosses)) + { + me->DespawnOnEvade(); + me->m_Events.AddEvent(new PhasedRespawn(*me), me->m_Events.CalculateTime(20000)); + } + else // bosses will run back to the spawnpoint at reset + { + Reset(); + if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons! + { + me->GetVehicleKit()->Reset(true); + } + } } /*void CreatureAI::AttackedBy(Unit* attacker) diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 848a58502..e485ca73c 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -103,6 +103,7 @@ public: virtual void SummonedCreatureDespawn(Creature* /*summon*/) {} virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) {} + virtual void SummonedCreatureDespawnAll() {} // Called when hit by a spell virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) {} diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 6991e0763..b6a1b60cf 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -604,6 +604,11 @@ void BossAI::SummonedCreatureDespawn(Creature* summon) summons.Despawn(summon); } +void BossAI::SummonedCreatureDespawnAll() +{ + summons.DespawnAll(); +} + void BossAI::UpdateAI(uint32 diff) { if (!UpdateVictim()) diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 7521bed16..9e47f4d08 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -418,6 +418,7 @@ public: void JustSummoned(Creature* summon) override; void SummonedCreatureDespawn(Creature* summon) override; + void SummonedCreatureDespawnAll() override; void UpdateAI(uint32 diff) override; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 4e3ec0972..49e7bc366 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1921,6 +1921,36 @@ void Creature::DespawnOrUnsummon(uint32 msTimeToDespawn /*= 0*/) ForcedDespawn(msTimeToDespawn); } +void Creature::DespawnOnEvade() +{ + SetVisible(false); + AI()->SummonedCreatureDespawnAll(); + RemoveEvadeAuras(); + + float x, y, z, o; + GetRespawnPosition(x, y, z, &o); + SetHomePosition(x, y, z, o); + SetPosition(x, y, z, o); + + if (IsFalling()) + { + RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); + } + StopMoving(); +} + +void Creature::RespawnOnEvade() +{ + SetVisible(true); + UpdateMovementFlags(); + AI()->Reset(); + AI()->JustReachedHome(); + if (IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons! + { + GetVehicleKit()->Reset(true); + } +} + void Creature::InitializeReactState() { if ((IsTotem() || IsTrigger() || IsCritter() || IsSpiritService()) && GetAIName() != "SmartAI" && !GetScriptId()) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 1cb77bf96..c0e352ff2 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -257,6 +257,8 @@ public: void RemoveCorpse(bool setSpawnTime = true, bool skipVisibility = false); void DespawnOrUnsummon(uint32 msTimeToDespawn = 0); + void DespawnOnEvade(); + void RespawnOnEvade(); [[nodiscard]] time_t const& GetRespawnTime() const { return m_respawnTime; } [[nodiscard]] time_t GetRespawnTimeEx() const;