diff --git a/common/ruletypes.h b/common/ruletypes.h index 93257885c..d8ffbeae5 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -713,6 +713,7 @@ RULE_INT(Aggro, BardAggroCap, 40, "per song bard aggro cap.") RULE_INT(Aggro, InitialAggroBonus, 100, "Initial Aggro Bonus, Default: 100") RULE_INT(Aggro, InitialPetAggroBonus, 100, "Initial Pet Aggro Bonus, Default 100") RULE_STRING(Aggro, ExcludedFleeAllyFactionIDs, "0|5013|5014|5023|5032", "Common Faction IDs that are excluded from faction checks in EntityList::FleeAllyCount") +RULE_BOOL(Aggro, AggroBotPets, false, "If enabled, NPCs will aggro bot pets") RULE_CATEGORY_END() RULE_CATEGORY(TaskSystem) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 4990f88bb..3447787df 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -405,17 +405,12 @@ bool Mob::CheckWillAggro(Mob *mob) { return false; } - Mob *pet_owner = mob->GetOwner(); - if ( - pet_owner && - pet_owner->IsClient() && - ( - !RuleB(Aggro, AggroPlayerPets) || - pet_owner->CastToClient()->GetGM() || - mob->GetSpecialAbility(SpecialAbility::AggroImmunity) - ) - ) { - return false; + Mob* pet_owner = mob->GetOwner(); + + if (pet_owner && pet_owner->IsOfClientBot()) { + if (mob->IsPetAggroExempt(pet_owner)) { + return false; + } } if (IsNPC() && mob->IsNPC() && mob->GetSpecialAbility(SpecialAbility::NPCAggroImmunity)) { @@ -582,6 +577,34 @@ bool Mob::CheckWillAggro(Mob *mob) { return false; } +bool Mob::IsPetAggroExempt(Mob* pet_owner) { + if (!pet_owner) { + return false; + } + + bool exempt_client_pet = pet_owner->IsClient() && !RuleB(Aggro, AggroPlayerPets); + bool exempt_bot_pet = pet_owner->IsBot() && !RuleB(Aggro, AggroBotPets); + + if (exempt_client_pet || exempt_bot_pet) { + return true; + } + + Mob* ultimate_owner = GetUltimateOwner(); + Client* client_owner = (ultimate_owner && ultimate_owner->IsClient()) + ? ultimate_owner->CastToClient() + : nullptr; + + if (client_owner && client_owner->GetGM()) { + return true; + } + + if (GetSpecialAbility(SpecialAbility::AggroImmunity)) { + return true; + } + + return false; +} + int EntityList::FleeAllyCount(Mob* attacker, Mob* skipped) { // Return a list of how many NPCs of the same faction or race are within aggro range of the given exclude Mob. diff --git a/zone/mob.h b/zone/mob.h index c03914202..f424444b4 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1289,6 +1289,7 @@ public: void SetLooting(uint16 val) { entity_id_being_looted = val; } bool CheckWillAggro(Mob *mob); + bool IsPetAggroExempt(Mob *pet_owner); void InstillDoubt(Mob *who); bool Charmed() const { return type_of_pet == petCharmed; }