From 0499e5da46edb305945a6840e95e65f6396da9fd Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 14 Apr 2024 13:03:18 +0800 Subject: [PATCH] Auto avoid aoe config --- conf/playerbots.conf.dist | 3 +++ src/AiFactory.cpp | 7 +++++- src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 3 ++- src/strategy/actions/MovementActions.cpp | 24 +++++++++++++------ src/strategy/actions/MovementActions.h | 3 +++ src/strategy/values/AoeValues.h | 1 + src/strategy/values/NearestGameObjects.cpp | 28 ++++++++++++++++++++++ src/strategy/values/NearestGameObjects.h | 13 ++++++++++ src/strategy/values/ValueContext.h | 2 ++ 10 files changed, 76 insertions(+), 9 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e883c56e..c3afc2a3 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -322,6 +322,9 @@ AiPlayerbot.AutoSaveMana = 1 # Default: 60 (60%) AiPlayerbot.SaveManaThreshold = 60 +# Enable auto avoid aoe (experimental) +# Default: 0 (disable) +AiPlayerbot.AutoAvoidAoe = 0 # Random bot default strategies (applied after defaults) AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 12beba33..bd903b5c 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -266,9 +266,14 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa { engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr); } - if (sPlayerbotAIConfig->autoSaveMana) { + if (sPlayerbotAIConfig->autoSaveMana) + { engine->addStrategy("auto save mana"); } + if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster()) + { + engine->addStrategy("avoid aoe"); + } switch (player->getClass()) { case CLASS_PRIEST: diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 8ddc3e0d..f56592e9 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -91,6 +91,7 @@ bool PlayerbotAIConfig::Initialize() mediumMana = sConfigMgr->GetOption("AiPlayerbot.MediumMana", 40); autoSaveMana = sConfigMgr->GetOption("AiPlayerbot.AutoSaveMana", true); saveManaThreshold = sConfigMgr->GetOption("AiPlayerbot.SaveManaThreshold", 60); + autoAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.AutoAvoidAoe", false); randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.15f); randomBotMaxLevelChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 22930b86..46740aa0 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -64,7 +64,8 @@ class PlayerbotAIConfig uint32 lowMana, mediumMana; bool autoSaveMana; uint32 saveManaThreshold; - + bool autoAvoidAoe; + uint32 openGoSpell; bool randomBotAutologin; bool botAutologin; diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index d701b293..185b7848 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1492,6 +1492,16 @@ bool AvoidAoeAction::isUseful() bool AvoidAoeAction::Execute(Event event) { // Case #1: Aura with dynamic object + if (AvoidAuraWithDynamicObj()) { + return true; + } + // Case #2: Trap game object with spell + // Case #3: Trigger npc + return false; +} + +bool AvoidAoeAction::AvoidAuraWithDynamicObj() +{ Aura* aura = AI_VALUE(Aura*, "area debuff"); if (!aura) { return false; @@ -1523,24 +1533,24 @@ bool AvoidAoeAction::Execute(Event event) } float farestDis = 0.0f; Position bestPos; - // float disToDyn = bot->GetExactDist(dynOwner); - // float maxDisToGo = radius > disToDyn ? std::sqrt(radius * radius - disToDyn * disToDyn) + 0.5f : 0.5f; for (float &angle : possibleAngles) { float fleeDis = sPlayerbotAIConfig->fleeDistance; Position pos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; - // todo(Yunfan): check carefully + // todo (Yunfan): check carefully if (dynOwner->GetExactDist(pos) > farestDis) { farestDis = dynOwner->GetExactDist(pos); bestPos = pos; } } if (farestDis > 0.0f) { - std::ostringstream out; - out << "I'm avoiding aoe spell [" << aura->GetSpellInfo()->SpellName[0] << "]..."; - bot->Say(out.str(), LANG_UNIVERSAL); - return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true); + if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { + std::ostringstream out; + out << "I'm avoiding aoe spell [" << aura->GetSpellInfo()->SpellName[0] << "]..."; + bot->Say(out.str(), LANG_UNIVERSAL); + return true; + } } return false; } diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 4865d7e1..58507e0c 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -73,6 +73,9 @@ class AvoidAoeAction : public MovementAction bool isUseful() override; bool Execute(Event event) override; + + protected: + bool AvoidAuraWithDynamicObj(); }; class RunAwayAction : public MovementAction diff --git a/src/strategy/values/AoeValues.h b/src/strategy/values/AoeValues.h index a6cde02a..45fedf87 100644 --- a/src/strategy/values/AoeValues.h +++ b/src/strategy/values/AoeValues.h @@ -5,6 +5,7 @@ #ifndef _PLAYERBOT_AOEVALUES_H #define _PLAYERBOT_AOEVALUES_H +#include "GameObject.h" #include "Object.h" #include "Value.h" #include "AiObjectContext.h" diff --git a/src/strategy/values/NearestGameObjects.cpp b/src/strategy/values/NearestGameObjects.cpp index 842b6a63..3380d4a2 100644 --- a/src/strategy/values/NearestGameObjects.cpp +++ b/src/strategy/values/NearestGameObjects.cpp @@ -7,6 +7,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "Playerbots.h" +#include "SharedDefines.h" class AnyGameObjectInObjectRangeCheck { @@ -42,3 +43,30 @@ GuidVector NearestGameObjects::Calculate() return result; } + +GuidVector NearestTrapWithDamageValue::Calculate() +{ + std::list targets; + AnyGameObjectInObjectRangeCheck u_check(bot, range); + Acore::GameObjectListSearcher searcher(bot, targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); + + GuidVector result; + for (GameObject* go : targets) + { + if (go->GetGoType() != GAMEOBJECT_TYPE_TRAP) + { + continue; + } + uint32 spellId = go->GetSpellId(); + if (!spellId) + { + continue; + } + // if (ignoreLos || bot->IsWithinLOSInMap(go)) + result.push_back(go->GetGUID()); + } + + return result; +} + diff --git a/src/strategy/values/NearestGameObjects.h b/src/strategy/values/NearestGameObjects.h index 73fec151..2321c728 100644 --- a/src/strategy/values/NearestGameObjects.h +++ b/src/strategy/values/NearestGameObjects.h @@ -24,4 +24,17 @@ class NearestGameObjects : public ObjectGuidListCalculatedValue bool ignoreLos; }; +class NearestTrapWithDamageValue : public ObjectGuidListCalculatedValue +{ + public: + NearestTrapWithDamageValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) : + ObjectGuidListCalculatedValue(botAI, "nearest trap with damage", 1 * 1000), range(range) { } + + protected: + GuidVector Calculate() override; + + private: + float range; +}; + #endif diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 9cba19d4..72e65185 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -299,6 +299,7 @@ class ValueContext : public NamedObjectContext creators["expected lifetime"] = &ValueContext::expected_lifetime; creators["expected group dps"] = &ValueContext::expected_group_dps; creators["area debuff"] = &ValueContext::area_debuff; + creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange; } private: @@ -501,6 +502,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* expected_lifetime(PlayerbotAI* ai) { return new ExpectedLifetimeValue(ai); } static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); } static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); } + static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); } }; #endif