diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 75f1c3995..e2cd312ee 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -572,6 +572,7 @@ void BossAI::_Reset() if (!me->IsAlive()) return; + me->SetCombatPulseDelay(0); me->ResetLootMode(); events.Reset(); scheduler.CancelAll(); @@ -594,6 +595,7 @@ void BossAI::_JustDied() void BossAI::_EnterCombat() { + me->SetCombatPulseDelay(5); me->setActive(true); DoZoneInCombat(); ScheduleTasks(); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index fbb36033a..cc2fc741e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -217,7 +217,7 @@ bool TemporaryThreatModifierEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), - m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), + m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0), @@ -718,6 +718,24 @@ void Creature::Update(uint32 diff) SelectVictim(); } + // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now + if (m_combatPulseDelay > 0 && IsInCombat() && GetMap()->IsDungeon()) + { + if (diff > m_combatPulseTime) + m_combatPulseTime = 0; + else + m_combatPulseTime -= diff; + + if (m_combatPulseTime == 0) + { + if (AI()) + AI()->DoZoneInCombat(); + else + SetInCombatWithZone(); + m_combatPulseTime = m_combatPulseDelay * IN_MILLISECONDS; + } + } + // periodic check to see if the creature has passed an evade boundary if (IsAIEnabled && !IsInEvadeMode() && IsEngaged()) { diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 5ab1d1d07..83c93fa34 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -283,6 +283,14 @@ public: [[nodiscard]] uint32 GetRespawnDelay() const { return m_respawnDelay; } void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; } + uint32 GetCombatPulseDelay() const { return m_combatPulseDelay; } + void SetCombatPulseDelay(uint32 delay) // (secs) interval at which the creature pulses the entire zone into combat (only works in dungeons) + { + m_combatPulseDelay = delay; + if (m_combatPulseTime == 0 || m_combatPulseTime > delay) + m_combatPulseTime = delay; + } + [[nodiscard]] float GetWanderDistance() const { return m_wanderDistance; } void SetWanderDistance(float dist) { m_wanderDistance = dist; } @@ -408,6 +416,8 @@ protected: uint32 m_boundaryCheckTime; // (msecs) remaining time for next evade boundary check uint16 m_transportCheckTimer; uint32 lootPickPocketRestoreTime; + uint32 m_combatPulseTime; // (msecs) remaining time for next zone-in-combat pulse + uint32 m_combatPulseDelay; ReactStates m_reactState; // for AI, not charmInfo void RegenerateHealth();