[Bug Fix] NPC Faction War prevention. (#3595)

* [Bug] NPC Faction War prevention.

This should assist with prevention of NPC Faction waring. I have been using this code on my server for over 5 years with no coredumps or any noted bugs. This was brought up as users have reported a few events where they can trigger NPC's to fight each other.

* Correct a few entries to line up with updated code.

* Re-add missing RestTimer functionality
This commit is contained in:
Fryguy 2023-11-19 11:40:15 -05:00 committed by GitHub
parent c0fe0f11f7
commit f7780b0247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 69 additions and 63 deletions

View File

@ -42,27 +42,26 @@ HateList::~HateList()
{
}
void HateList::WipeHateList()
{
void HateList::WipeHateList(bool npc_only) {
auto iterator = list.begin();
while (iterator != list.end()) {
Mob *m = (*iterator)->entity_on_hatelist;
if (m && (m->IsClient() || (m->IsPet() && m->GetOwner()->IsClient())) && npc_only) {
iterator++;
} else {
if (m) {
if (parse->HasQuestSub(hate_owner->GetNPCTypeID(), EVENT_HATE_LIST)) {
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
}
while (iterator != list.end())
{
Mob* m = (*iterator)->entity_on_hatelist;
if (m)
{
if (parse->HasQuestSub(hate_owner->GetNPCTypeID(), EVENT_HATE_LIST)) {
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
}
if (m->IsClient()) {
m->CastToClient()->DecrementAggroCount();
m->CastToClient()->RemoveXTarget(hate_owner, true);
if (m->IsClient()) {
m->CastToClient()->DecrementAggroCount();
m->CastToClient()->RemoveXTarget(hate_owner, true);
}
delete (*iterator);
iterator = list.erase(iterator);
}
}
delete (*iterator);
iterator = list.erase(iterator);
}
}

View File

@ -88,7 +88,7 @@ public:
void SetHateAmountOnEnt(Mob *other, int64 in_hate, uint64 in_damage);
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 WipeHateList(bool npc_only = false);
void RemoveStaleEntries(int time_ms, float dist);

View File

@ -4888,16 +4888,14 @@ bool Mob::RemoveFromHateList(Mob* mob)
return bFound;
}
void Mob::WipeHateList()
{
if(IsEngaged())
{
hate_list.WipeHateList();
AI_Event_NoLongerEngaged();
}
else
{
hate_list.WipeHateList();
void Mob::WipeHateList(bool npc_only) {
if (IsEngaged()) {
hate_list.WipeHateList(npc_only);
if (hate_list.IsHateListEmpty()) {
AI_Event_NoLongerEngaged();
}
} else {
hate_list.WipeHateList(npc_only);
}
}

View File

@ -767,7 +767,7 @@ public:
void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; }
bool HateSummon();
void FaceTarget(Mob* mob_to_face = 0);
void WipeHateList();
void WipeHateList(bool npc_only = false);
void AddFeignMemory(Mob* attacker);
void RemoveFromFeignMemory(Mob* attacker);
void ClearFeignMemory();

View File

@ -1062,6 +1062,10 @@ void Mob::AI_Process() {
SetTarget(hate_list.GetClosestEntOnHateList(this));
else {
if (AI_target_check_timer->Check()) {
if (IsNPC() && (!IsPet() || (HasOwner() && GetOwner()->IsNPC())) && !CastToNPC()->WillAggroNPCs()) {
WipeHateList(true); // wipe NPCs from hate list to prevent faction war
}
if (IsFocused()) {
if (!target) {
SetTarget(hate_list.GetEntWithMostHateOnList(this));

View File

@ -3885,11 +3885,12 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
if (IsDetrimentalSpell(buff.spellid)) {
if (caster->IsClient()) {
if (!caster->CastToClient()->GetFeigned())
if (!caster->CastToClient()->GetFeigned()) {
AddToHateList(caster, -effect_value);
} else if (!IsClient()) // Allow NPC's to generate hate if casted on other
// NPC's.
}
} else if (!IsClient()) { // Allow NPC's to generate hate if casted on other NPC's
AddToHateList(caster, -effect_value);
}
}
effect_value = caster->GetActDoTDamage(buff.spellid, effect_value, this);
@ -3990,6 +3991,12 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
case SE_Charm: {
if (!caster || !PassCharismaCheck(caster, buff.spellid)) {
BuffFadeByEffect(SE_Charm);
// Remove from hate list of any NPC's hate list and remove all NPCs this hate list
if (IsNPC()) {
entity_list.RemoveFromHateLists(this);
WipeHateList(true);
}
}
break;

View File

@ -4244,41 +4244,39 @@ bool Mob::SpellOnTarget(
spelltar->DamageShield(this, true);
}
if (
spelltar->IsAIControlled() &&
IsDetrimentalSpell(spell_id) &&
!IsHarmonySpell(spell_id)
) {
auto aggro_amount = CheckAggroAmount(spell_id, spelltar, isproc);
LogSpells("Spell [{}] cast on [{}] generated [{}] hate", spell_id,
spelltar->GetName(), aggro_amount);
if (aggro_amount > 0) {
spelltar->AddToHateList(this, aggro_amount);
} else {
int64 newhate = spelltar->GetHateAmount(this) + aggro_amount;
spelltar->SetHateAmountOnEnt(this, std::max(newhate, static_cast<int64>(1)));
}
} else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) {
if (this != spelltar && IsClient()){
if (spelltar->IsClient()) {
CastToClient()->UpdateRestTimer(spelltar->CastToClient()->GetRestTimer());
} else if (spelltar->IsPet()) {
auto* owner = spelltar->GetOwner();
if (owner && owner != this && owner->IsClient()) {
CastToClient()->UpdateRestTimer(owner->CastToClient()->GetRestTimer());
if (!(spelltar->IsNPC() && IsNPC() && !(IsPet() && GetOwner()->IsClient()))) {
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
auto aggro_amount = CheckAggroAmount(spell_id, spelltar, isproc);
LogSpellsDetail("Spell {} cast on {} generated {} hate", spell_id,
spelltar->GetName(), aggro_amount);
if (aggro_amount > 0) {
spelltar->AddToHateList(this, aggro_amount);
} else {
int64 newhate = spelltar->GetHateAmount(this) + aggro_amount;
spelltar->SetHateAmountOnEnt(this, std::max(newhate, static_cast<int64>(1)));
}
} else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) {
if (this != spelltar && IsClient()){
if (spelltar->IsClient()) {
CastToClient()->UpdateRestTimer(spelltar->CastToClient()->GetRestTimer());
} else if (spelltar->IsPet()) {
auto* owner = spelltar->GetOwner();
if (owner && owner != this && owner->IsClient()) {
CastToClient()->UpdateRestTimer(owner->CastToClient()->GetRestTimer());
}
}
}
}
entity_list.AddHealAggro(
spelltar,
this,
CheckHealAggroAmount(
spell_id,
entity_list.AddHealAggro(
spelltar,
(spelltar->GetMaxHP() - spelltar->GetHP())
)
);
this,
CheckHealAggroAmount(
spell_id,
spelltar,
(spelltar->GetMaxHP() - spelltar->GetHP())
)
);
}
}
// make sure spelltar is high enough level for the buff