diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 10b46a356..01507174f 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -107,6 +107,7 @@ void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage) entity->hatelist_damage = in_damage; if (in_hate > 0) entity->stored_hate_amount = in_hate; + entity->last_modified = Timer::GetCurrentTime(); } } @@ -208,6 +209,7 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, in_entity->CastToClient()->IncrementAggroCount(); } } + entity->last_modified = Timer::GetCurrentTime(); } bool HateList::RemoveEntFromHateList(Mob *in_entity) @@ -646,3 +648,31 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent iter++; } } + +void HateList::RemoveStaleEntries(int time_ms, float dist) +{ + auto it = list.begin(); + + auto cur_time = Timer::GetCurrentTime(); + + while (it != list.end()) { + auto m = (*it)->entity_on_hatelist; + if (m) { + // 10 mins or distance + if ((cur_time - (*it)->last_modified > time_ms) || hate_owner->CalculateDistance(m->GetX(), m->GetY(), m->GetZ()) > dist) { + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0); + + if (m->IsClient()) { + m->CastToClient()->DecrementAggroCount(); + m->CastToClient()->RemoveXTarget(hate_owner, true); + } + + delete (*it); + it = list.erase(it); + continue; + } + } + ++it; + } +} + diff --git a/zone/hate_list.h b/zone/hate_list.h index f0e2b7618..1ffb1eaf8 100644 --- a/zone/hate_list.h +++ b/zone/hate_list.h @@ -31,6 +31,7 @@ struct struct_HateList int32 hatelist_damage; uint32 stored_hate_amount; bool is_entity_frenzy; + uint32 last_modified; // we need to remove this if it gets higher than 10 mins }; class HateList @@ -65,6 +66,7 @@ public: void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; } void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr); void WipeHateList(); + void RemoveStaleEntries(int time_ms, float dist); protected: diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index a05aa1343..920ec8863 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1021,6 +1021,10 @@ void Mob::AI_Process() { if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) SendAddPlayerState(PlayerState::Aggressive); + + // NPCs will forget people after 10 mins of not interacting with them or out of range + // both of these maybe zone specific, hardcoded for now + hate_list.RemoveStaleEntries(600000, 600.0f); // we are prevented from getting here if we are blind and don't have a target in range // from above, so no extra blind checks needed if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())