diff --git a/zone/attack.cpp b/zone/attack.cpp index f9edb46ac..ce96675a0 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3363,6 +3363,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const damage = DMG_INVULNERABLE; } + // this should actually happen MUCH sooner, need to investigate though -- good enough for now + if ((skill_used == EQEmu::skills::SkillArchery || skill_used == EQEmu::skills::SkillThrowing) && GetSpecialAbility(IMMUNE_RANGED_ATTACKS)) { + Log(Logs::Detail, Logs::Combat, "Avoiding %d damage due to IMMUNE_RANGED_ATTACKS.", damage); + damage = DMG_INVULNERABLE; + } + if (spell_id != SPELL_UNKNOWN || attacker == nullptr) avoidable = false; diff --git a/zone/common.h b/zone/common.h index f7b157115..df6b22637 100644 --- a/zone/common.h +++ b/zone/common.h @@ -194,7 +194,8 @@ enum { CASTING_RESIST_DIFF = 43, COUNTER_AVOID_DAMAGE = 44, PROX_AGGRO = 45, - MAX_SPECIAL_ATTACK = 46 + IMMUNE_RANGED_ATTACKS = 46, + MAX_SPECIAL_ATTACK = 47 }; typedef enum { //fear states diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 01507174f..8da223b04 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -200,6 +200,7 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0; entity->stored_hate_amount = in_hate; entity->is_entity_frenzy = in_is_entity_frenzied; + entity->oor_count = 0; list.push_back(entity); parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0); @@ -658,8 +659,20 @@ void HateList::RemoveStaleEntries(int time_ms, float dist) 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) { + bool remove = false; + + if (cur_time - (*it)->last_modified > time_ms) + remove = true; + + if (!remove && hate_owner->CalculateDistance(m->GetX(), m->GetY(), m->GetZ()) > dist) { + (*it)->oor_count++; + if ((*it)->oor_count == 2) + remove = true; + } else if ((*it)->oor_count != 0) { + (*it)->oor_count = 0; + } + + if (remove) { parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0); if (m->IsClient()) { diff --git a/zone/hate_list.h b/zone/hate_list.h index 1ffb1eaf8..0ac1840ac 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; + int8 oor_count; // count on how long we've been out of range uint32 last_modified; // we need to remove this if it gets higher than 10 mins }; diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 8b88ba12f..98ca32569 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -2499,7 +2499,8 @@ luabind::scope lua_register_special_abilities() { luabind::value("allow_to_tank", static_cast(ALLOW_TO_TANK)), luabind::value("ignore_root_aggro_rules", static_cast(IGNORE_ROOT_AGGRO_RULES)), luabind::value("casting_resist_diff", static_cast(CASTING_RESIST_DIFF)), - luabind::value("counter_avoid_damage", static_cast(COUNTER_AVOID_DAMAGE)) + luabind::value("counter_avoid_damage", static_cast(COUNTER_AVOID_DAMAGE)), + luabind::value("immune_ranged_attacks", static_cast(IMMUNE_RANGED_ATTACKS)) ]; } diff --git a/zone/mob.cpp b/zone/mob.cpp index 322bc7658..39efb1d3d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -115,7 +115,8 @@ Mob::Mob(const char* in_name, fix_z_timer(300), fix_z_timer_engaged(100), attack_anim_timer(1000), - position_update_melee_push_timer(1000) + position_update_melee_push_timer(1000), + mHateListCleanup(6000) { targeted = 0; tar_ndx = 0; diff --git a/zone/mob.h b/zone/mob.h index deb24f640..d5de43e0c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1419,6 +1419,7 @@ protected: void AddItemFactionBonus(uint32 pFactionID,int32 bonus); int32 GetItemFactionBonus(uint32 pFactionID); void ClearItemFactionBonuses(); + Timer mHateListCleanup; void CalculateFearPosition(); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 920ec8863..07e7770b0 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1024,7 +1024,8 @@ void Mob::AI_Process() { // 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); + if (mHateListCleanup.Check()) + 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())