Merge cd4dfa2166b223a4ead351869d791a958e0379b2 into 5bef92d5eaca3e2ecc317f9d599312bc23eb71aa

This commit is contained in:
Seamthesis 2025-11-10 10:05:57 +08:00 committed by GitHub
commit 7ae6db02ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 50 additions and 8 deletions

View File

@ -185,7 +185,7 @@ void CreatureAI::MoveInLineOfSight(Unit* who)
!me->IsWithinDist(who, ATTACK_DISTANCE, true, false, false)) // if in combat and in dist - neutral to all can actually assist other creatures
return;
if (me->HasReactState(REACT_AGGRESSIVE) && me->CanStartAttack(who))
if (me->HasReactState(REACT_AGGRESSIVE) && me->CanStartAttack(who) && (me->IsAggroGracePeriodExpired() || me->GetMap()->Instanceable()))
AttackStart(who);
}

View File

@ -274,7 +274,7 @@ Creature::Creature(): Unit(), MovableMapObject(), m_groupLootTimer(0), lootingGr
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_alreadyCallForHelp(false), 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),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr), m_cannotReachTimer(0),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _aggroGracePeriodExpired(false), m_lastLeashExtensionTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
@ -944,6 +944,21 @@ void Creature::Update(uint32 diff)
}
}
void Creature::Heartbeat()
{
Unit::Heartbeat();
// creatures should only attack surroundings initially after heartbeat has passed or until attacked
if (!_aggroGracePeriodExpired)
{
_aggroGracePeriodExpired = true;
// trigger MoveInLineOfSight
Acore::CreatureAggroGracePeriodExpiredNotifier notifier(*this);
Cell::VisitObjects(this, notifier, GetVisibilityRange());
}
}
bool Creature::IsFreeToMove()
{
uint32 moveFlags = m_movementInfo.GetMovementFlags();
@ -2654,12 +2669,6 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const
if (victim->IsCreature() && victim->ToCreature()->IsInEvadeMode())
return false;
// cannot attack if is during 5 second grace period, unless being attacked
if (m_respawnedTime && (GameTime::GetGameTime().count() - m_respawnedTime) < 5 && !IsEngagedBy(victim))
{
return false;
}
// if victim is in FD and we can't see that
if (victim->HasUnitFlag2(UNIT_FLAG2_FEIGN_DEATH) && !CanIgnoreFeignDeath())
{

View File

@ -69,6 +69,8 @@ public:
[[nodiscard]] ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
void Update(uint32 time) override; // overwrited Unit::Update
void Heartbeat() override;
void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr, float* dist = nullptr) const;
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
@ -187,6 +189,8 @@ public:
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
bool IsAggroGracePeriodExpired() { return _aggroGracePeriodExpired; }
void LoadSparringPct();
[[nodiscard]] float GetSparringPct() const { return _sparringPct; }
@ -516,6 +520,8 @@ private:
CreatureGroup* m_formation;
bool TriggerJustRespawned;
bool _aggroGracePeriodExpired;
// Shared timer between mobs who assist another.
// Damaging one extends leash range on all of them.
mutable std::shared_ptr<time_t> m_lastLeashExtensionTime;

View File

@ -186,6 +186,25 @@ void AIRelocationNotifier::Visit(CreatureMapType& m)
}
}
void CreatureAggroGracePeriodExpiredNotifier::Visit(CreatureMapType& m)
{
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
Creature* c = iter->GetSource();
CreatureUnitRelocationWorker(c, &i_creature);
CreatureUnitRelocationWorker(&i_creature, c);
}
}
void CreatureAggroGracePeriodExpiredNotifier::Visit(PlayerMapType& m)
{
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
Player* player = iter->GetSource();
CreatureUnitRelocationWorker(&i_creature, player);
}
}
// Uses visibility map
void MessageDistDeliverer::Visit(VisiblePlayersMap const& m)
{

View File

@ -96,6 +96,14 @@ namespace Acore
void Visit(CreatureMapType&);
};
struct CreatureAggroGracePeriodExpiredNotifier
{
Creature& i_creature;
CreatureAggroGracePeriodExpiredNotifier(Creature& c) : i_creature(c) {}
template<class T> void Visit(GridRefMgr<T>&) {}
void Visit(CreatureMapType&);
void Visit(PlayerMapType&);
};
struct MessageDistDeliverer
{
WorldObject const* i_source;