From 7d7edbd961a65dc0a568cc956dce7b58956b2440 Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Wed, 23 Jul 2025 11:26:55 -0700 Subject: [PATCH 1/5] Warlock Soul Shard/Soulstone ID conversion Hello everyone, I'm still working on fixing issue #1439 , and I have a theory - it could be because the clients that are having the issue are not english, and the code currently checks for strings "soul shard" and "soulstone". This PR converts the check over to the item IDs, so it should work regardless of what client is being used. I tested it myself with the english client and there is functionally no difference than before - but I hope it solves the issue #1439 for the non-english clients and community. --- src/strategy/warlock/WarlockTriggers.cpp | 32 ++++++++++++++++++++++++ src/strategy/warlock/WarlockTriggers.h | 6 ++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/strategy/warlock/WarlockTriggers.cpp b/src/strategy/warlock/WarlockTriggers.cpp index 7f414f2e..e0493e20 100644 --- a/src/strategy/warlock/WarlockTriggers.cpp +++ b/src/strategy/warlock/WarlockTriggers.cpp @@ -7,6 +7,32 @@ #include "GenericTriggers.h" #include "Playerbots.h" +static const uint32 SOUL_SHARD_ITEM_ID = 6265; + +uint32 GetSoulShardCount(Player* bot) +{ + return bot->GetItemCount(SOUL_SHARD_ITEM_ID, false); // false = only bags +} + +// List of all Soulstone item IDs +static const std::vector soulstoneItemIds = { + 5232, // Minor Soulstone + 16892, // Lesser Soulstone + 16893, // Soulstone + 16895, // Greater Soulstone + 16896, // Major Soulstone + 22116, // Master Soulstone + 36895 // Demonic Soulstone +}; + +uint32 GetSoulstoneCount(Player* bot) +{ + uint32 count = 0; + for (uint32 id : soulstoneItemIds) + count += bot->GetItemCount(id, false); // false = only bags + return count; +} + bool SpellstoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; } bool FirestoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; } @@ -16,6 +42,12 @@ bool WarlockConjuredItemTrigger::IsActive() return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0; } +bool OutOfSoulShardsTrigger::IsActive() { return GetSoulShardCount(botAI->GetBot()) == 0; } + +bool TooManySoulShardsTrigger::IsActive() { return GetSoulShardCount(botAI->GetBot()) >= 6; } + +bool HasSoulstoneTrigger::IsActive() { return GetSoulstoneCount(botAI->GetBot()) == 0; } + // Checks if the target marked with the moon icon can be banished bool BanishTrigger::IsActive() { diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index ca85a999..3a448973 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -34,14 +34,14 @@ class OutOfSoulShardsTrigger : public Trigger { public: OutOfSoulShardsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soul shard", 2) {} - bool IsActive() override { return AI_VALUE2(uint32, "item count", "soul shard") == 0; } + bool IsActive() override; }; class TooManySoulShardsTrigger : public Trigger { public: TooManySoulShardsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "too many soul shards") {} - bool IsActive() override { return AI_VALUE2(uint32, "item count", "soul shard") >= 6; } + bool IsActive() override; }; class FirestoneTrigger : public BuffTrigger @@ -62,7 +62,7 @@ class HasSoulstoneTrigger : public Trigger { public: HasSoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soulstone") {} - bool IsActive() override { return AI_VALUE2(uint32, "item count", "soulstone") == 0; } + bool IsActive() override; }; class SoulstoneTrigger : public Trigger From 5ac6e8751cbfd0241f8a296b6d742b28d3006a39 Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Wed, 23 Jul 2025 12:45:02 -0700 Subject: [PATCH 2/5] Bagspace checks This commit is adding checks to the createsoulshard and createsoulstone actions, to check and see if there is enough bagspace to create an item. --- src/strategy/warlock/WarlockActions.cpp | 44 ++++++++++++++++++++++++- src/strategy/warlock/WarlockActions.h | 1 + 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/strategy/warlock/WarlockActions.cpp b/src/strategy/warlock/WarlockActions.cpp index c57a21c2..69f1f335 100644 --- a/src/strategy/warlock/WarlockActions.cpp +++ b/src/strategy/warlock/WarlockActions.cpp @@ -145,9 +145,51 @@ bool CreateSoulShardAction::isUseful() uint32 currentShards = bot->GetItemCount(ITEM_SOUL_SHARD, false); // false = only bags const uint32 SHARD_CAP = 6; // adjust as needed - return currentShards < SHARD_CAP; + // Only allow if under cap AND there is space for a new shard + ItemPosCountVec dest; + uint32 count = 1; + bool hasSpace = (bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_SOUL_SHARD, count) == EQUIP_ERR_OK); + + return (currentShards < SHARD_CAP) && hasSpace; } +bool CastCreateSoulstoneAction::isUseful() +{ + Player* bot = botAI->GetBot(); + if (!bot) + return false; + + // List of all Soulstone item IDs + static const std::vector soulstoneIds = { + 5232, // Minor Soulstone + 16892, // Lesser Soulstone + 16893, // Soulstone + 16895, // Greater Soulstone + 16896, // Major Soulstone + 22116, // Master Soulstone + 36895 // Demonic Soulstone + }; + + // Check if the bot already has any soulstone + uint32 currentSoulstones = 0; + for (uint32 id : soulstoneIds) + currentSoulstones += bot->GetItemCount(id, false); // false = only bags + + // Allow only if the bot has no soulstone AND there is space for one + ItemPosCountVec dest; + uint32 count = 1; + bool hasSpace = false; + for (uint32 id : soulstoneIds) + { + if (bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count) == EQUIP_ERR_OK) + { + hasSpace = true; + break; + } + } + + return (currentSoulstones == 0) && hasSpace; +} bool DestroySoulShardAction::Execute(Event event) { diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index 69530775..b3b7a3e2 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -84,6 +84,7 @@ class CastCreateSoulstoneAction : public CastBuffSpellAction { public: CastCreateSoulstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create soulstone") {} + bool isUseful() override; }; class UseSoulstoneSelfAction : public UseSpellItemAction From feda619066eedfa610e0ab562c380c0e1c6643f6 Mon Sep 17 00:00:00 2001 From: Yunfan Li <56597220+liyunfan1223@users.noreply.github.com> Date: Fri, 25 Jul 2025 18:11:03 +0800 Subject: [PATCH 3/5] Engine optimization for better performance and mem usage (#1462) * Optimize loot * World channel talk * General improvement * Engine rebuild for performance and memory usage * Fix crash with AutoDoQuest = 0 --- src/LootObjectStack.cpp | 79 ++++--- src/LootObjectStack.h | 2 +- src/PlayerbotAI.cpp | 3 + src/PlayerbotAIConfig.cpp | 7 +- src/strategy/AiObjectContext.cpp | 121 +++++++---- src/strategy/AiObjectContext.h | 29 ++- src/strategy/Engine.cpp | 21 +- src/strategy/Engine.h | 1 + src/strategy/NamedObjectContext.h | 194 +++++++++++------- src/strategy/Strategy.h | 2 +- src/strategy/Trigger.cpp | 3 +- src/strategy/Trigger.h | 2 +- .../deathknight/DKAiObjectContext.cpp | 51 ++++- src/strategy/deathknight/DKAiObjectContext.h | 11 + src/strategy/druid/DruidAiObjectContext.cpp | 38 +++- src/strategy/druid/DruidAiObjectContext.h | 11 + src/strategy/hunter/HunterAiObjectContext.cpp | 46 ++++- src/strategy/hunter/HunterAiObjectContext.h | 11 + src/strategy/mage/MageAiObjectContext.cpp | 38 +++- src/strategy/mage/MageAiObjectContext.h | 11 + .../paladin/PaladinAiObjectContext.cpp | 68 +++++- src/strategy/paladin/PaladinAiObjectContext.h | 11 + src/strategy/priest/PriestAiObjectContext.cpp | 44 +++- src/strategy/priest/PriestAiObjectContext.h | 11 + src/strategy/rogue/RogueAiObjectContext.cpp | 38 +++- src/strategy/rogue/RogueAiObjectContext.h | 12 ++ src/strategy/rpg/NewRpgBaseAction.cpp | 6 +- src/strategy/shaman/ShamanAiObjectContext.cpp | 36 +++- src/strategy/shaman/ShamanAiObjectContext.h | 11 + src/strategy/values/GrindTargetValue.cpp | 16 +- src/strategy/values/NearestCorpsesValue.h | 2 +- src/strategy/values/SharedValueContext.h | 7 +- .../warlock/WarlockAiObjectContext.cpp | 67 +++++- src/strategy/warlock/WarlockAiObjectContext.h | 11 + .../warrior/WarriorAiObjectContext.cpp | 36 +++- src/strategy/warrior/WarriorAiObjectContext.h | 11 + 36 files changed, 831 insertions(+), 237 deletions(-) diff --git a/src/LootObjectStack.cpp b/src/LootObjectStack.cpp index e1d2bc46..adce7f39 100644 --- a/src/LootObjectStack.cpp +++ b/src/LootObjectStack.cpp @@ -6,6 +6,8 @@ #include "LootObjectStack.h" #include "LootMgr.h" +#include "Object.h" +#include "ObjectAccessor.h" #include "Playerbots.h" #include "Unit.h" @@ -287,7 +289,7 @@ bool LootObject::IsLootPossible(Player* bot) if (reqItem && !bot->HasItemCount(reqItem, 1)) return false; - if (abs(worldObj->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE -2.0f) + if (abs(worldObj->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE - 2.0f) return false; Creature* creature = botAI->GetCreature(guid); @@ -299,7 +301,7 @@ bool LootObject::IsLootPossible(Player* bot) // Prevent bot from running to chests that are unlootable (e.g. Gunship Armory before completing the event) GameObject* go = botAI->GetGameObject(guid); - if (go && go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE)) + if (go && go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE)) return false; if (skillId == SKILL_NONE) @@ -317,29 +319,17 @@ bool LootObject::IsLootPossible(Player* bot) uint32 skillValue = uint32(bot->GetSkillValue(skillId)); if (reqSkillValue > skillValue) return false; - - if (skillId == SKILL_MINING && - !bot->HasItemCount(756, 1) && - !bot->HasItemCount(778, 1) && - !bot->HasItemCount(1819, 1) && - !bot->HasItemCount(1893, 1) && - !bot->HasItemCount(1959, 1) && - !bot->HasItemCount(2901, 1) && - !bot->HasItemCount(9465, 1) && - !bot->HasItemCount(20723, 1) && - !bot->HasItemCount(40772, 1) && - !bot->HasItemCount(40892, 1) && - !bot->HasItemCount(40893, 1)) + + if (skillId == SKILL_MINING && !bot->HasItemCount(756, 1) && !bot->HasItemCount(778, 1) && + !bot->HasItemCount(1819, 1) && !bot->HasItemCount(1893, 1) && !bot->HasItemCount(1959, 1) && + !bot->HasItemCount(2901, 1) && !bot->HasItemCount(9465, 1) && !bot->HasItemCount(20723, 1) && + !bot->HasItemCount(40772, 1) && !bot->HasItemCount(40892, 1) && !bot->HasItemCount(40893, 1)) { return false; // Bot is missing a mining pick } - - if (skillId == SKILL_SKINNING && - !bot->HasItemCount(7005, 1) && - !bot->HasItemCount(40772, 1) && - !bot->HasItemCount(40893, 1) && - !bot->HasItemCount(12709, 1) && - !bot->HasItemCount(19901, 1)) + + if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1) && !bot->HasItemCount(40772, 1) && + !bot->HasItemCount(40893, 1) && !bot->HasItemCount(12709, 1) && !bot->HasItemCount(19901, 1)) { return false; // Bot is missing a skinning knife } @@ -376,42 +366,45 @@ void LootObjectStack::Clear() { availableLoot.clear(); } bool LootObjectStack::CanLoot(float maxDistance) { - std::vector ordered = OrderByDistance(maxDistance); - return !ordered.empty(); + LootObject nearest = GetNearest(maxDistance); + return !nearest.IsEmpty(); } LootObject LootObjectStack::GetLoot(float maxDistance) { - std::vector ordered = OrderByDistance(maxDistance); - return ordered.empty() ? LootObject() : *ordered.begin(); + LootObject nearest = GetNearest(maxDistance); + return nearest.IsEmpty() ? LootObject() : nearest; } -std::vector LootObjectStack::OrderByDistance(float maxDistance) + +LootObject LootObjectStack::GetNearest(float maxDistance) { availableLoot.shrink(time(nullptr) - 30); - std::map sortedMap; + LootObject nearest; + float nearestDistance = std::numeric_limits::max(); + LootTargetList safeCopy(availableLoot); for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++) { ObjectGuid guid = i->guid; - LootObject lootObject(bot, guid); - if (!lootObject.IsLootPossible(bot)) // Ensure loot object is valid - continue; - WorldObject* worldObj = lootObject.GetWorldObject(bot); - if (!worldObj) // Prevent null pointer dereference - { + WorldObject* worldObj = ObjectAccessor::GetWorldObject(*bot, guid); + if (!worldObj) continue; - } float distance = bot->GetDistance(worldObj); - if (!maxDistance || distance <= maxDistance) - sortedMap[distance] = lootObject; + + if (distance >= nearestDistance || (maxDistance && distance > maxDistance)) + continue; + + LootObject lootObject(bot, guid); + + if (!lootObject.IsLootPossible(bot)) + continue; + + nearestDistance = distance; + nearest = lootObject; } - std::vector result; - for (auto& [_, lootObject] : sortedMap) - result.push_back(lootObject); - - return result; -} + return nearest; +} \ No newline at end of file diff --git a/src/LootObjectStack.h b/src/LootObjectStack.h index b17e7fcc..9ff7dd99 100644 --- a/src/LootObjectStack.h +++ b/src/LootObjectStack.h @@ -78,7 +78,7 @@ public: LootObject GetLoot(float maxDistance = 0); private: - std::vector OrderByDistance(float maxDistance = 0); + LootObject GetNearest(float maxDistance = 0); Player* bot; LootTargetList availableLoot; diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 5b2b707f..d2e0f293 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1049,6 +1049,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) default: return; } + + if (chanName == "World") + return; // do not reply to self but always try to reply to real player if (guid1 != bot->GetGUID()) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index cd03c7f1..db1419a4 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -627,12 +627,7 @@ bool PlayerbotAIConfig::Initialize() sPlayerbotTextMgr->LoadBotTextChance(); PlayerbotFactory::Init(); - if (!sPlayerbotAIConfig->autoDoQuests) - { - LOG_INFO("server.loading", "Loading Quest Detail Data..."); - sTravelMgr->LoadQuestTravelTable(); - } - + AiObjectContext::BuildAllSharedContexts(); if (sPlayerbotAIConfig->randomBotSuggestDungeons) { diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index c308a7cd..dd025c2e 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -8,39 +8,89 @@ #include "ActionContext.h" #include "ChatActionContext.h" #include "ChatTriggerContext.h" +#include "DKAiObjectContext.h" +#include "DruidAiObjectContext.h" +#include "HunterAiObjectContext.h" +#include "MageAiObjectContext.h" +#include "PaladinAiObjectContext.h" #include "Playerbots.h" -#include "RaidUlduarTriggerContext.h" +#include "PriestAiObjectContext.h" #include "RaidUlduarActionContext.h" +#include "RaidUlduarTriggerContext.h" +#include "RogueAiObjectContext.h" +#include "ShamanAiObjectContext.h" #include "SharedValueContext.h" #include "StrategyContext.h" #include "TriggerContext.h" #include "ValueContext.h" +#include "WarlockAiObjectContext.h" +#include "WarriorAiObjectContext.h" #include "WorldPacketActionContext.h" #include "WorldPacketTriggerContext.h" -#include "raids/RaidStrategyContext.h" -#include "raids/blackwinglair/RaidBwlActionContext.h" -#include "raids/blackwinglair/RaidBwlTriggerContext.h" -#include "raids/naxxramas/RaidNaxxActionContext.h" -#include "raids/naxxramas/RaidNaxxTriggerContext.h" -#include "raids/icecrown/RaidIccActionContext.h" -#include "raids/icecrown/RaidIccTriggerContext.h" -#include "raids/obsidiansanctum/RaidOsActionContext.h" -#include "raids/obsidiansanctum/RaidOsTriggerContext.h" -#include "raids/eyeofeternity/RaidEoEActionContext.h" -#include "raids/vaultofarchavon/RaidVoATriggerContext.h" -#include "raids/onyxia/RaidOnyxiaActionContext.h" -#include "raids/onyxia/RaidOnyxiaTriggerContext.h" -#include "raids/vaultofarchavon/RaidVoAActionContext.h" -#include "raids/eyeofeternity/RaidEoETriggerContext.h" -#include "raids/moltencore/RaidMcActionContext.h" -#include "raids/moltencore/RaidMcTriggerContext.h" -#include "raids/aq20/RaidAq20ActionContext.h" -#include "raids/aq20/RaidAq20TriggerContext.h" #include "dungeons/DungeonStrategyContext.h" #include "dungeons/wotlk/WotlkDungeonActionContext.h" #include "dungeons/wotlk/WotlkDungeonTriggerContext.h" +#include "raids/RaidStrategyContext.h" +#include "raids/aq20/RaidAq20ActionContext.h" +#include "raids/aq20/RaidAq20TriggerContext.h" +#include "raids/blackwinglair/RaidBwlActionContext.h" +#include "raids/blackwinglair/RaidBwlTriggerContext.h" +#include "raids/eyeofeternity/RaidEoEActionContext.h" +#include "raids/eyeofeternity/RaidEoETriggerContext.h" +#include "raids/icecrown/RaidIccActionContext.h" +#include "raids/icecrown/RaidIccTriggerContext.h" +#include "raids/moltencore/RaidMcActionContext.h" +#include "raids/moltencore/RaidMcTriggerContext.h" +#include "raids/naxxramas/RaidNaxxActionContext.h" +#include "raids/naxxramas/RaidNaxxTriggerContext.h" +#include "raids/obsidiansanctum/RaidOsActionContext.h" +#include "raids/obsidiansanctum/RaidOsTriggerContext.h" +#include "raids/onyxia/RaidOnyxiaActionContext.h" +#include "raids/onyxia/RaidOnyxiaTriggerContext.h" +#include "raids/vaultofarchavon/RaidVoAActionContext.h" +#include "raids/vaultofarchavon/RaidVoATriggerContext.h" -AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) +SharedNamedObjectContextList AiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList AiObjectContext::sharedActionContexts; +SharedNamedObjectContextList AiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList AiObjectContext::sharedValueContexts; + +AiObjectContext::AiObjectContext(PlayerbotAI* botAI, SharedNamedObjectContextList& sharedStrategyContext, + SharedNamedObjectContextList& sharedActionContext, + SharedNamedObjectContextList& sharedTriggerContext, + SharedNamedObjectContextList& sharedValueContext) + : PlayerbotAIAware(botAI), + strategyContexts(sharedStrategyContext), + actionContexts(sharedActionContext), + triggerContexts(sharedTriggerContext), + valueContexts(sharedValueContext) +{ +} + +void AiObjectContext::BuildAllSharedContexts() +{ + AiObjectContext::BuildSharedContexts(); + PriestAiObjectContext::BuildSharedContexts(); + MageAiObjectContext::BuildSharedContexts(); + WarlockAiObjectContext::BuildSharedContexts(); + WarriorAiObjectContext::BuildSharedContexts(); + ShamanAiObjectContext::BuildSharedContexts(); + PaladinAiObjectContext::BuildSharedContexts(); + DruidAiObjectContext::BuildSharedContexts(); + HunterAiObjectContext::BuildSharedContexts(); + RogueAiObjectContext::BuildSharedContexts(); + DKAiObjectContext::BuildSharedContexts(); +} + +void AiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void AiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) { strategyContexts.Add(new StrategyContext()); strategyContexts.Add(new MovementStrategyContext()); @@ -48,7 +98,10 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) strategyContexts.Add(new QuestStrategyContext()); strategyContexts.Add(new RaidStrategyContext()); strategyContexts.Add(new DungeonStrategyContext()); +} +void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ actionContexts.Add(new ActionContext()); actionContexts.Add(new ChatActionContext()); actionContexts.Add(new WorldPacketActionContext()); @@ -77,7 +130,10 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonFoSActionContext()); actionContexts.Add(new WotlkDungeonPoSActionContext()); actionContexts.Add(new WotlkDungeonToCActionContext()); +} +void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ triggerContexts.Add(new TriggerContext()); triggerContexts.Add(new ChatTriggerContext()); triggerContexts.Add(new WorldPacketTriggerContext()); @@ -106,26 +162,11 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonFoSTriggerContext()); triggerContexts.Add(new WotlkDungeonPoSTriggerContext()); triggerContexts.Add(new WotlkDungeonToCTriggerContext()); +} +void AiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ valueContexts.Add(new ValueContext()); - - valueContexts.Add(sSharedValueContext); -} - -void AiObjectContext::Update() -{ - strategyContexts.Update(); - triggerContexts.Update(); - actionContexts.Update(); - valueContexts.Update(); -} - -void AiObjectContext::Reset() -{ - strategyContexts.Reset(); - triggerContexts.Reset(); - actionContexts.Reset(); - valueContexts.Reset(); } std::vector AiObjectContext::Save() @@ -218,5 +259,3 @@ std::string const AiObjectContext::FormatValues() return out.str(); } - -void AiObjectContext::AddShared(NamedObjectContext* sharedValues) { valueContexts.Add(sharedValues); } diff --git a/src/strategy/AiObjectContext.h b/src/strategy/AiObjectContext.h index 07fa78a6..cfa7d4db 100644 --- a/src/strategy/AiObjectContext.h +++ b/src/strategy/AiObjectContext.h @@ -19,10 +19,19 @@ class PlayerbotAI; +typedef Strategy* (*StrategyCreator)(PlayerbotAI* botAI); +typedef Action* (*ActionCreator)(PlayerbotAI* botAI); +typedef Trigger* (*TriggerCreator)(PlayerbotAI* botAI); +typedef UntypedValue* (*ValueCreator)(PlayerbotAI* botAI); + class AiObjectContext : public PlayerbotAIAware { public: - AiObjectContext(PlayerbotAI* botAI); + AiObjectContext(PlayerbotAI* botAI, + SharedNamedObjectContextList& sharedStrategyContext = sharedStrategyContexts, + SharedNamedObjectContextList& sharedActionContext = sharedActionContexts, + SharedNamedObjectContextList& sharedTriggerContext = sharedTriggerContexts, + SharedNamedObjectContextList& sharedValueContext = sharedValueContexts); virtual ~AiObjectContext() {} virtual Strategy* GetStrategy(std::string const name); @@ -56,20 +65,30 @@ public: std::set GetSupportedActions(); std::string const FormatValues(); - virtual void Update(); - virtual void Reset(); - virtual void AddShared(NamedObjectContext* sharedValues); - std::vector Save(); void Load(std::vector data); std::vector performanceStack; + static void BuildAllSharedContexts(); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + protected: NamedObjectContextList strategyContexts; NamedObjectContextList actionContexts; NamedObjectContextList triggerContexts; NamedObjectContextList valueContexts; + +private: + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index 39524596..15055f0e 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -11,6 +11,7 @@ #include "Playerbots.h" #include "Queue.h" #include "Strategy.h" +#include "Timer.h" Engine::Engine(PlayerbotAI* botAI, AiObjectContext* factory) : PlayerbotAIAware(botAI), aiObjectContext(factory) { @@ -108,6 +109,8 @@ void Engine::Reset() } multipliers.clear(); + + actionNodeFactories.creators.clear(); } void Engine::Init() @@ -120,9 +123,10 @@ void Engine::Init() strategyTypeMask |= strategy->GetType(); strategy->InitMultipliers(multipliers); strategy->InitTriggers(triggers); - - Event emptyEvent; - MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent, "default"); + for (auto &iter : strategy->actionNodeFactories.creators) + { + actionNodeFactories.creators[iter.first] = iter.second; + } } if (testMode) @@ -248,11 +252,9 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) ActionNode* Engine::CreateActionNode(std::string const name) { - for (std::map::iterator i = strategies.begin(); i != strategies.end(); i++) - { - if (ActionNode* node = i->second->GetAction(name)) - return node; - } + ActionNode* node = actionNodeFactories.GetContextObject(name, botAI); + if (node) + return node; return new ActionNode(name, /*P*/ nullptr, @@ -432,6 +434,7 @@ bool Engine::HasStrategy(std::string const name) { return strategies.find(name) void Engine::ProcessTriggers(bool minimal) { std::unordered_map fires; + uint32 now = getMSTime(); for (std::vector::iterator i = triggers.begin(); i != triggers.end(); i++) { TriggerNode* node = *i; @@ -451,7 +454,7 @@ void Engine::ProcessTriggers(bool minimal) if (fires.find(trigger) != fires.end()) continue; - if (testMode || trigger->needCheck()) + if (testMode || trigger->needCheck(now)) { if (minimal && node->getFirstRelevance() < 100) continue; diff --git a/src/strategy/Engine.h b/src/strategy/Engine.h index c3a5d743..8a662997 100644 --- a/src/strategy/Engine.h +++ b/src/strategy/Engine.h @@ -114,6 +114,7 @@ protected: float lastRelevance; std::string lastAction; uint32 strategyTypeMask; + NamedObjectFactoryList actionNodeFactories; }; #endif diff --git a/src/strategy/NamedObjectContext.h b/src/strategy/NamedObjectContext.h index 78797b0a..c7ecffc6 100644 --- a/src/strategy/NamedObjectContext.h +++ b/src/strategy/NamedObjectContext.h @@ -29,7 +29,8 @@ public: std::string const getQualifier() { return qualifier; } - static std::string const MultiQualify(std::vector qualifiers, const std::string& separator, const std::string_view brackets = "{}"); + static std::string const MultiQualify(std::vector qualifiers, const std::string& separator, + const std::string_view brackets = "{}"); static std::vector getMultiQualifiers(std::string const qualifier1); static int32 getMultiQualifier(std::string const qualifier1, uint32 pos); @@ -40,9 +41,9 @@ protected: template class NamedObjectFactory { -protected: - typedef T* (*ActionCreator)(PlayerbotAI* botAI); - std::unordered_map creators; +public: + typedef T* (*ObjectCreator)(PlayerbotAI* botAI); + std::unordered_map creators; public: T* create(std::string name, PlayerbotAI* botAI) @@ -58,7 +59,7 @@ public: if (creators.find(name) == creators.end()) return nullptr; - ActionCreator creator = creators[name]; + ObjectCreator creator = creators[name]; if (!creator) return nullptr; @@ -73,7 +74,7 @@ public: std::set supports() { std::set keys; - for (typename std::unordered_map::iterator it = creators.begin(); + for (typename std::unordered_map::iterator it = creators.begin(); it != creators.end(); it++) keys.insert(it->first); @@ -111,24 +112,6 @@ public: created.clear(); } - void Update() - { - for (typename std::unordered_map::iterator i = created.begin(); i != created.end(); i++) - { - if (i->second) - i->second->Update(); - } - } - - void Reset() - { - for (typename std::unordered_map::iterator i = created.begin(); i != created.end(); i++) - { - if (i->second) - i->second->Reset(); - } - } - bool IsShared() { return shared; } bool IsSupportsSiblings() { return supportsSiblings; } @@ -147,53 +130,93 @@ protected: bool supportsSiblings; }; +template +class SharedNamedObjectContextList +{ +public: + typedef T* (*ObjectCreator)(PlayerbotAI* botAI); + std::unordered_map creators; + std::vector*> contexts; + + ~SharedNamedObjectContextList() + { + for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) + delete *i; + } + + void Add(NamedObjectContext* context) + { + contexts.push_back(context); + for (const auto& iter : context->creators) + { + creators[iter.first] = iter.second; + } + } +}; + template class NamedObjectContextList { public: - virtual ~NamedObjectContextList() + typedef T* (*ObjectCreator)(PlayerbotAI* botAI); + const std::unordered_map& creators; + const std::vector*>& contexts; + std::unordered_map created; + + NamedObjectContextList(const SharedNamedObjectContextList& shared) + : creators(shared.creators), contexts(shared.contexts) { - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) - { - NamedObjectContext* context = *i; - if (!context->IsShared()) - delete context; - } } - void Add(NamedObjectContext* context) { contexts.push_back(context); } + ~NamedObjectContextList() + { + for (typename std::unordered_map::iterator i = created.begin(); i != created.end(); i++) + { + if (i->second) + delete i->second; + } + + created.clear(); + } + + T* create(std::string name, PlayerbotAI* botAI) + { + size_t found = name.find("::"); + std::string qualifier; + if (found != std::string::npos) + { + qualifier = name.substr(found + 2); + name = name.substr(0, found); + } + + if (creators.find(name) == creators.end()) + return nullptr; + + ObjectCreator creator = creators.at(name); + if (!creator) + return nullptr; + + T* object = (*creator)(botAI); + Qualified* q = dynamic_cast(object); + if (q && found != std::string::npos) + q->Qualify(qualifier); + + return object; + } T* GetContextObject(std::string const name, PlayerbotAI* botAI) { - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) + if (created.find(name) == created.end()) { - if (T* object = (*i)->create(name, botAI)) - return object; - } - - return nullptr; - } - - void Update() - { - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) - { - if (!(*i)->IsShared()) - (*i)->Update(); - } - } - - void Reset() - { - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) - { - (*i)->Reset(); + if (T* object = create(name, botAI)) + return created[name] = object; } + return created[name]; } std::set GetSiblings(std::string const name) { - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) + for (auto i = contexts.begin(); i != contexts.end(); i++) { if (!(*i)->IsSupportsSiblings()) continue; @@ -213,7 +236,7 @@ public: std::set supports() { std::set result; - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) + for (auto i = contexts.begin(); i != contexts.end(); i++) { std::set supported = (*i)->supports(); @@ -227,46 +250,69 @@ public: std::set GetCreated() { std::set result; - for (typename std::vector*>::iterator i = contexts.begin(); i != contexts.end(); i++) + for (typename std::unordered_map::iterator i = created.begin(); i != created.end(); i++) { - std::set createdKeys = (*i)->GetCreated(); - - for (std::set::iterator j = createdKeys.begin(); j != createdKeys.end(); j++) - result.insert(*j); + result.insert(i->first); } return result; } - -private: - std::vector*> contexts; }; template class NamedObjectFactoryList { public: + typedef T* (*ObjectCreator)(PlayerbotAI* botAI); + std::vector*> factories; + std::unordered_map creators; + virtual ~NamedObjectFactoryList() { - for (typename std::list*>::iterator i = factories.begin(); i != factories.end(); i++) + for (typename std::vector*>::iterator i = factories.begin(); i != factories.end(); i++) delete *i; } - void Add(NamedObjectFactory* context) { factories.push_front(context); } - - T* GetContextObject(std::string const& name, PlayerbotAI* botAI) + T* create(std::string name, PlayerbotAI* botAI) { - for (typename std::list*>::iterator i = factories.begin(); i != factories.end(); i++) + size_t found = name.find("::"); + std::string qualifier; + if (found != std::string::npos) { - if (T* object = (*i)->create(name, botAI)) - return object; + qualifier = name.substr(found + 2); + name = name.substr(0, found); } - return nullptr; + if (creators.find(name) == creators.end()) + return nullptr; + + ObjectCreator creator = creators[name]; + if (!creator) + return nullptr; + + T* object = (*creator)(botAI); + Qualified* q = dynamic_cast(object); + if (q && found != std::string::npos) + q->Qualify(qualifier); + + return object; } -private: - std::list*> factories; + void Add(NamedObjectFactory* context) + { + factories.push_back(context); + for (const auto& iter : context->creators) + { + creators[iter.first] = iter.second; + } + } + + T* GetContextObject(std::string const name, PlayerbotAI* botAI) + { + if (T* object = create(name, botAI)) + return object; + return nullptr; + } }; #endif diff --git a/src/strategy/Strategy.h b/src/strategy/Strategy.h index 47edd397..1206490c 100644 --- a/src/strategy/Strategy.h +++ b/src/strategy/Strategy.h @@ -69,7 +69,7 @@ public: void Update() {} void Reset() {} -protected: +public: NamedObjectFactoryList actionNodeFactories; }; diff --git a/src/strategy/Trigger.cpp b/src/strategy/Trigger.cpp index b2c97499..89f61696 100644 --- a/src/strategy/Trigger.cpp +++ b/src/strategy/Trigger.cpp @@ -32,12 +32,11 @@ Value* Trigger::GetTargetValue() { return context->GetValue(GetTar Unit* Trigger::GetTarget() { return GetTargetValue()->Get(); } -bool Trigger::needCheck() +bool Trigger::needCheck(uint32 now) { if (checkInterval < 2) return true; - uint32 now = getMSTime(); if (!lastCheckTime || now - lastCheckTime >= checkInterval) { lastCheckTime = now; diff --git a/src/strategy/Trigger.h b/src/strategy/Trigger.h index ce2dd06d..af8d0528 100644 --- a/src/strategy/Trigger.h +++ b/src/strategy/Trigger.h @@ -30,7 +30,7 @@ public: virtual Value* GetTargetValue(); virtual std::string const GetTargetName() { return "self target"; } - bool needCheck(); + bool needCheck(uint32 now); protected: int32 checkInterval; diff --git a/src/strategy/deathknight/DKAiObjectContext.cpp b/src/strategy/deathknight/DKAiObjectContext.cpp index c02ff82b..a26f96c0 100644 --- a/src/strategy/deathknight/DKAiObjectContext.cpp +++ b/src/strategy/deathknight/DKAiObjectContext.cpp @@ -108,14 +108,20 @@ private: static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(botAI); } static Trigger* plague_strike(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); } static Trigger* plague_strike_3s(PlayerbotAI* botAI) { return new PlagueStrike3sDebuffTrigger(botAI); } - static Trigger* dd_cd_and_plague_strike_3s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 3s"); } + static Trigger* dd_cd_and_plague_strike_3s(PlayerbotAI* botAI) + { + return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 3s"); + } static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI) { return new PlagueStrikeDebuffOnAttackerTrigger(botAI); } static Trigger* icy_touch(PlayerbotAI* botAI) { return new IcyTouchDebuffTrigger(botAI); } static Trigger* icy_touch_3s(PlayerbotAI* botAI) { return new IcyTouch3sDebuffTrigger(botAI); } - static Trigger* dd_cd_and_icy_touch_3s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 3s"); } + static Trigger* dd_cd_and_icy_touch_3s(PlayerbotAI* botAI) + { + return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 3s"); + } static Trigger* death_coil(PlayerbotAI* botAI) { return new DeathCoilTrigger(botAI); } static Trigger* icy_touch_on_attacker(PlayerbotAI* botAI) { return new IcyTouchDebuffOnAttackerTrigger(botAI); } static Trigger* improved_icy_talons(PlayerbotAI* botAI) { return new ImprovedIcyTalonsTrigger(botAI); } @@ -140,7 +146,10 @@ private: static Trigger* no_rune(PlayerbotAI* botAI) { return new NoRuneTrigger(botAI); } static Trigger* freezing_fog(PlayerbotAI* botAI) { return new FreezingFogTrigger(botAI); } static Trigger* no_desolation(PlayerbotAI* botAI) { return new DesolationTrigger(botAI); } - static Trigger* dd_cd_and_no_desolation(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "no desolation"); } + static Trigger* dd_cd_and_no_desolation(PlayerbotAI* botAI) + { + return new TwoTriggers(botAI, "death and decay cooldown", "no desolation"); + } static Trigger* death_and_decay_cooldown(PlayerbotAI* botAI) { return new DeathAndDecayCooldownTrigger(botAI); } static Trigger* army_of_the_dead(PlayerbotAI* botAI) { return new ArmyOfTheDeadTrigger(botAI); } }; @@ -265,11 +274,45 @@ private: } }; -DKAiObjectContext::DKAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList DKAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList DKAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList DKAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList DKAiObjectContext::sharedValueContexts; + +DKAiObjectContext::DKAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void DKAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void DKAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new DeathKnightStrategyFactoryInternal()); strategyContexts.Add(new DeathKnightCombatStrategyFactoryInternal()); strategyContexts.Add(new DeathKnightDKBuffStrategyFactoryInternal()); +} + +void DKAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new DeathKnightAiObjectContextInternal()); +} + +void DKAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new DeathKnightTriggerFactoryInternal()); } + +void DKAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} diff --git a/src/strategy/deathknight/DKAiObjectContext.h b/src/strategy/deathknight/DKAiObjectContext.h index 7729868b..b45a778a 100644 --- a/src/strategy/deathknight/DKAiObjectContext.h +++ b/src/strategy/deathknight/DKAiObjectContext.h @@ -14,6 +14,17 @@ class DKAiObjectContext : public AiObjectContext { public: DKAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/druid/DruidAiObjectContext.cpp b/src/strategy/druid/DruidAiObjectContext.cpp index cec9eeb0..3866e1cd 100644 --- a/src/strategy/druid/DruidAiObjectContext.cpp +++ b/src/strategy/druid/DruidAiObjectContext.cpp @@ -8,7 +8,6 @@ #include "BearTankDruidStrategy.h" #include "CasterDruidStrategy.h" #include "CatDpsDruidStrategy.h" -#include "OffhealDruidCatStrategy.h" #include "DruidActions.h" #include "DruidBearActions.h" #include "DruidCatActions.h" @@ -18,6 +17,7 @@ #include "GenericDruidStrategy.h" #include "HealDruidStrategy.h" #include "MeleeDruidStrategy.h" +#include "OffhealDruidCatStrategy.h" #include "Playerbots.h" class DruidStrategyFactoryInternal : public NamedObjectContext @@ -324,10 +324,44 @@ private: static Action* force_of_nature(PlayerbotAI* ai) { return new CastForceOfNatureAction(ai); } }; -DruidAiObjectContext::DruidAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList DruidAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList DruidAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList DruidAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList DruidAiObjectContext::sharedValueContexts; + +DruidAiObjectContext::DruidAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void DruidAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void DruidAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new DruidStrategyFactoryInternal()); strategyContexts.Add(new DruidDruidStrategyFactoryInternal()); +} + +void DruidAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new DruidAiObjectContextInternal()); +} + +void DruidAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new DruidTriggerFactoryInternal()); } + +void DruidAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} diff --git a/src/strategy/druid/DruidAiObjectContext.h b/src/strategy/druid/DruidAiObjectContext.h index 22d00e18..7c1c7c8e 100644 --- a/src/strategy/druid/DruidAiObjectContext.h +++ b/src/strategy/druid/DruidAiObjectContext.h @@ -14,6 +14,17 @@ class DruidAiObjectContext : public AiObjectContext { public: DruidAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/hunter/HunterAiObjectContext.cpp b/src/strategy/hunter/HunterAiObjectContext.cpp index b8e2e41f..904e7a9f 100644 --- a/src/strategy/hunter/HunterAiObjectContext.cpp +++ b/src/strategy/hunter/HunterAiObjectContext.cpp @@ -4,16 +4,17 @@ */ #include "HunterAiObjectContext.h" + #include "BeastMasteryHunterStrategy.h" -#include "MarksmanshipHunterStrategy.h" -#include "SurvivalHunterStrategy.h" #include "GenericHunterNonCombatStrategy.h" #include "GenericHunterStrategy.h" #include "HunterActions.h" #include "HunterBuffStrategies.h" #include "HunterTriggers.h" +#include "MarksmanshipHunterStrategy.h" #include "NamedObjectContext.h" #include "Playerbots.h" +#include "SurvivalHunterStrategy.h" class HunterStrategyFactoryInternal : public NamedObjectContext { @@ -105,7 +106,10 @@ public: private: static Trigger* auto_shot(PlayerbotAI* botAI) { return new AutoShotTrigger(botAI); } static Trigger* scare_beast(PlayerbotAI* botAI) { return new ScareBeastTrigger(botAI); } - static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI) { return new ConsussiveShotSnareTrigger(botAI); } + static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI) + { + return new ConsussiveShotSnareTrigger(botAI); + } static Trigger* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); } static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(botAI); } static Trigger* trueshot_aura(PlayerbotAI* botAI) { return new TrueshotAuraTrigger(botAI); } @@ -258,10 +262,44 @@ private: static Action* intimidation(PlayerbotAI* ai) { return new CastIntimidationAction(ai); } }; -HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList HunterAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList HunterAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList HunterAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList HunterAiObjectContext::sharedValueContexts; + +HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void HunterAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void HunterAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new HunterStrategyFactoryInternal()); strategyContexts.Add(new HunterBuffStrategyFactoryInternal()); +} + +void HunterAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new HunterAiObjectContextInternal()); +} + +void HunterAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new HunterTriggerFactoryInternal()); } + +void HunterAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} diff --git a/src/strategy/hunter/HunterAiObjectContext.h b/src/strategy/hunter/HunterAiObjectContext.h index e06e8f54..5acd3ba2 100644 --- a/src/strategy/hunter/HunterAiObjectContext.h +++ b/src/strategy/hunter/HunterAiObjectContext.h @@ -14,6 +14,17 @@ class HunterAiObjectContext : public AiObjectContext { public: HunterAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index 2d09f1a0..ba1e4e2d 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -24,7 +24,7 @@ public: creators["nc"] = &MageStrategyFactoryInternal::nc; creators["pull"] = &MageStrategyFactoryInternal::pull; creators["fire aoe"] = &MageStrategyFactoryInternal::fire_aoe; - creators["frostfire aoe"] = &MageStrategyFactoryInternal::frostfire_aoe; + creators["frostfire aoe"] = &MageStrategyFactoryInternal::frostfire_aoe; creators["frost aoe"] = &MageStrategyFactoryInternal::frost_aoe; creators["arcane aoe"] = &MageStrategyFactoryInternal::arcane_aoe; creators["cure"] = &MageStrategyFactoryInternal::cure; @@ -268,11 +268,45 @@ private: static Action* blink_back(PlayerbotAI* botAI) { return new CastBlinkBackAction(botAI); } }; -MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList MageAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList MageAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList MageAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList MageAiObjectContext::sharedValueContexts; + +MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void MageAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void MageAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new MageStrategyFactoryInternal()); strategyContexts.Add(new MageCombatStrategyFactoryInternal()); strategyContexts.Add(new MageBuffStrategyFactoryInternal()); +} + +void MageAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new MageAiObjectContextInternal()); +} + +void MageAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new MageTriggerFactoryInternal()); } + +void MageAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/mage/MageAiObjectContext.h b/src/strategy/mage/MageAiObjectContext.h index 3388faf9..435b43d0 100644 --- a/src/strategy/mage/MageAiObjectContext.h +++ b/src/strategy/mage/MageAiObjectContext.h @@ -14,6 +14,17 @@ class MageAiObjectContext : public AiObjectContext { public: MageAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/paladin/PaladinAiObjectContext.cpp b/src/strategy/paladin/PaladinAiObjectContext.cpp index 4dbcb0af..74869bb1 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.cpp +++ b/src/strategy/paladin/PaladinAiObjectContext.cpp @@ -8,8 +8,8 @@ #include "DpsPaladinStrategy.h" #include "GenericPaladinNonCombatStrategy.h" #include "HealPaladinStrategy.h" -#include "OffhealRetPaladinStrategy.h" #include "NamedObjectContext.h" +#include "OffhealRetPaladinStrategy.h" #include "PaladinActions.h" #include "PaladinBuffStrategies.h" #include "PaladinTriggers.h" @@ -207,9 +207,15 @@ private: static Trigger* sacred_shield_on_main_tank(PlayerbotAI* ai) { return new SacredShieldOnMainTankTrigger(ai); } static Trigger* blessing_of_kings_on_party(PlayerbotAI* botAI) { return new BlessingOfKingsOnPartyTrigger(botAI); } - static Trigger* blessing_of_wisdom_on_party(PlayerbotAI* botAI) { return new BlessingOfWisdomOnPartyTrigger(botAI); } + static Trigger* blessing_of_wisdom_on_party(PlayerbotAI* botAI) + { + return new BlessingOfWisdomOnPartyTrigger(botAI); + } static Trigger* blessing_of_might_on_party(PlayerbotAI* botAI) { return new BlessingOfMightOnPartyTrigger(botAI); } - static Trigger* blessing_of_sanctuary_on_party(PlayerbotAI* botAI) { return new BlessingOfSanctuaryOnPartyTrigger(botAI); } + static Trigger* blessing_of_sanctuary_on_party(PlayerbotAI* botAI) + { + return new BlessingOfSanctuaryOnPartyTrigger(botAI); + } static Trigger* avenging_wrath(PlayerbotAI* botAI) { return new AvengingWrathTrigger(botAI); } }; @@ -317,10 +323,22 @@ private: static Action* blessing_of_wisdom(PlayerbotAI* botAI) { return new CastBlessingOfWisdomAction(botAI); } static Action* blessing_of_kings(PlayerbotAI* botAI) { return new CastBlessingOfKingsAction(botAI); } static Action* divine_storm(PlayerbotAI* botAI) { return new CastDivineStormAction(botAI); } - static Action* blessing_of_kings_on_party(PlayerbotAI* botAI) { return new CastBlessingOfKingsOnPartyAction(botAI); } - static Action* blessing_of_might_on_party(PlayerbotAI* botAI) { return new CastBlessingOfMightOnPartyAction(botAI); } - static Action* blessing_of_wisdom_on_party(PlayerbotAI* botAI) { return new CastBlessingOfWisdomOnPartyAction(botAI); } - static Action* blessing_of_sanctuary_on_party(PlayerbotAI* botAI) { return new CastBlessingOfSanctuaryOnPartyAction(botAI); } + static Action* blessing_of_kings_on_party(PlayerbotAI* botAI) + { + return new CastBlessingOfKingsOnPartyAction(botAI); + } + static Action* blessing_of_might_on_party(PlayerbotAI* botAI) + { + return new CastBlessingOfMightOnPartyAction(botAI); + } + static Action* blessing_of_wisdom_on_party(PlayerbotAI* botAI) + { + return new CastBlessingOfWisdomOnPartyAction(botAI); + } + static Action* blessing_of_sanctuary_on_party(PlayerbotAI* botAI) + { + return new CastBlessingOfSanctuaryOnPartyAction(botAI); + } static Action* redemption(PlayerbotAI* botAI) { return new CastRedemptionAction(botAI); } static Action* crusader_strike(PlayerbotAI* botAI) { return new CastCrusaderStrikeAction(botAI); } static Action* crusader_aura(PlayerbotAI* botAI) { return new CastCrusaderAuraAction(botAI); } @@ -394,12 +412,46 @@ private: static Action* cancel_divine_sacrifice(PlayerbotAI* ai) { return new CastCancelDivineSacrificeAction(ai); } }; -PaladinAiObjectContext::PaladinAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList PaladinAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList PaladinAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList PaladinAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList PaladinAiObjectContext::sharedValueContexts; + +PaladinAiObjectContext::PaladinAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void PaladinAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void PaladinAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new PaladinStrategyFactoryInternal()); strategyContexts.Add(new PaladinCombatStrategyFactoryInternal()); strategyContexts.Add(new PaladinBuffStrategyFactoryInternal()); strategyContexts.Add(new PaladinResistanceStrategyFactoryInternal()); +} + +void PaladinAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new PaladinAiObjectContextInternal()); +} + +void PaladinAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new PaladinTriggerFactoryInternal()); } + +void PaladinAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/paladin/PaladinAiObjectContext.h b/src/strategy/paladin/PaladinAiObjectContext.h index c865a8fc..e8b867ae 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.h +++ b/src/strategy/paladin/PaladinAiObjectContext.h @@ -14,6 +14,17 @@ class PaladinAiObjectContext : public AiObjectContext { public: PaladinAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/priest/PriestAiObjectContext.cpp b/src/strategy/priest/PriestAiObjectContext.cpp index 4f057718..444ed3a1 100644 --- a/src/strategy/priest/PriestAiObjectContext.cpp +++ b/src/strategy/priest/PriestAiObjectContext.cpp @@ -175,8 +175,7 @@ public: creators["power word: shield on party"] = &PriestAiObjectContextInternal::power_word_shield_on_party; creators["power word: shield on almost full health below"] = &PriestAiObjectContextInternal::power_word_shield_on_almost_full_health_below; - creators["power word: shield on not full"] = - &PriestAiObjectContextInternal::power_word_shield_on_not_full; + creators["power word: shield on not full"] = &PriestAiObjectContextInternal::power_word_shield_on_not_full; creators["renew"] = &PriestAiObjectContextInternal::renew; creators["renew on party"] = &PriestAiObjectContextInternal::renew_on_party; creators["greater heal"] = &PriestAiObjectContextInternal::greater_heal; @@ -289,10 +288,7 @@ private: { return new CastPowerWordShieldOnAlmostFullHealthBelowAction(ai); } - static Action* power_word_shield_on_not_full(PlayerbotAI* ai) - { - return new CastPowerWordShieldOnNotFullAction(ai); - } + static Action* power_word_shield_on_not_full(PlayerbotAI* ai) { return new CastPowerWordShieldOnNotFullAction(ai); } static Action* renew(PlayerbotAI* botAI) { return new CastRenewAction(botAI); } static Action* renew_on_party(PlayerbotAI* botAI) { return new CastRenewOnPartyAction(botAI); } static Action* greater_heal(PlayerbotAI* botAI) { return new CastGreaterHealAction(botAI); } @@ -352,10 +348,44 @@ private: static Action* guardian_spirit_on_party(PlayerbotAI* ai) { return new CastGuardianSpiritOnPartyAction(ai); } }; -PriestAiObjectContext::PriestAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList PriestAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList PriestAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList PriestAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList PriestAiObjectContext::sharedValueContexts; + +PriestAiObjectContext::PriestAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void PriestAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void PriestAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new PriestStrategyFactoryInternal()); strategyContexts.Add(new PriestCombatStrategyFactoryInternal()); +} + +void PriestAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new PriestAiObjectContextInternal()); +} + +void PriestAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new PriestTriggerFactoryInternal()); } + +void PriestAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/priest/PriestAiObjectContext.h b/src/strategy/priest/PriestAiObjectContext.h index 81c491b7..bb6efb4e 100644 --- a/src/strategy/priest/PriestAiObjectContext.h +++ b/src/strategy/priest/PriestAiObjectContext.h @@ -14,6 +14,17 @@ class PriestAiObjectContext : public AiObjectContext { public: PriestAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/rogue/RogueAiObjectContext.cpp b/src/strategy/rogue/RogueAiObjectContext.cpp index a63b97e1..39941bed 100644 --- a/src/strategy/rogue/RogueAiObjectContext.cpp +++ b/src/strategy/rogue/RogueAiObjectContext.cpp @@ -5,6 +5,7 @@ #include "RogueAiObjectContext.h" +#include "AiObjectContext.h" #include "AssassinationRogueStrategy.h" #include "DpsRogueStrategy.h" #include "GenericRogueNonCombatStrategy.h" @@ -185,10 +186,45 @@ private: static Action* killing_spree(PlayerbotAI* ai) { return new CastKillingSpreeAction(ai); } }; -RogueAiObjectContext::RogueAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList RogueAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList RogueAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList RogueAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList RogueAiObjectContext::sharedValueContexts; + +RogueAiObjectContext::RogueAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, + sharedTriggerContexts, sharedValueContexts) { +} + +void RogueAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void RogueAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new RogueStrategyFactoryInternal()); strategyContexts.Add(new RogueCombatStrategyFactoryInternal()); +} + +void RogueAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new RogueAiObjectContextInternal()); +} + +void RogueAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new RogueTriggerFactoryInternal()); } + +void RogueAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/rogue/RogueAiObjectContext.h b/src/strategy/rogue/RogueAiObjectContext.h index e641623f..f1b3f98b 100644 --- a/src/strategy/rogue/RogueAiObjectContext.h +++ b/src/strategy/rogue/RogueAiObjectContext.h @@ -7,6 +7,7 @@ #define _PLAYERBOT_ROGUEAIOBJECTCONTEXT_H #include "AiObjectContext.h" +#include "Strategy.h" class PlayerbotAI; @@ -14,6 +15,17 @@ class RogueAiObjectContext : public AiObjectContext { public: RogueAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/rpg/NewRpgBaseAction.cpp b/src/strategy/rpg/NewRpgBaseAction.cpp index bd2a8221..5e71c5c5 100644 --- a/src/strategy/rpg/NewRpgBaseAction.cpp +++ b/src/strategy/rpg/NewRpgBaseAction.cpp @@ -84,7 +84,7 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest) float rx, ry, rz; bool found = false; int attempt = 3; - while (--attempt) + while (attempt--) { float angle = bot->GetAngle(&dest); float delta = urand(1, 100) <= 75 ? (rand_norm() - 0.5) * M_PI * 0.5 : (rand_norm() - 0.5) * M_PI * 2; @@ -163,8 +163,8 @@ bool NewRpgBaseAction::MoveRandomNear(float moveStep, MovementPriority priority) const float x = bot->GetPositionX(); const float y = bot->GetPositionY(); const float z = bot->GetPositionZ(); - int attempts = 5; - while (--attempts) + int attempts = 1; + while (attempts--) { float angle = (float)rand_norm() * 2 * static_cast(M_PI); float dx = x + distance * cos(angle); diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index 9e79f792..182251d1 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -328,11 +328,45 @@ private: static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); } }; -ShamanAiObjectContext::ShamanAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList ShamanAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList ShamanAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList ShamanAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList ShamanAiObjectContext::sharedValueContexts; + +ShamanAiObjectContext::ShamanAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void ShamanAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void ShamanAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new ShamanStrategyFactoryInternal()); strategyContexts.Add(new ShamanCombatStrategyFactoryInternal()); strategyContexts.Add(new ShamanBuffStrategyFactoryInternal()); +} + +void ShamanAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new ShamanAiObjectContextInternal()); +} + +void ShamanAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new ShamanATriggerFactoryInternal()); } + +void ShamanAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/shaman/ShamanAiObjectContext.h b/src/strategy/shaman/ShamanAiObjectContext.h index ad1c0af4..d168f7af 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.h +++ b/src/strategy/shaman/ShamanAiObjectContext.h @@ -14,6 +14,17 @@ class ShamanAiObjectContext : public AiObjectContext { public: ShamanAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/values/GrindTargetValue.cpp b/src/strategy/values/GrindTargetValue.cpp index 1737b7a7..cd368741 100644 --- a/src/strategy/values/GrindTargetValue.cpp +++ b/src/strategy/values/GrindTargetValue.cpp @@ -192,16 +192,16 @@ bool GrindTargetValue::needForQuest(Unit* target) return true; } } + } + } - if (CreatureTemplate const* data = sObjectMgr->GetCreatureTemplate(target->GetEntry())) + if (CreatureTemplate const* data = sObjectMgr->GetCreatureTemplate(target->GetEntry())) + { + if (uint32 lootId = data->lootid) + { + if (LootTemplates_Creature.HaveQuestLootForPlayer(lootId, bot)) { - if (uint32 lootId = data->lootid) - { - if (LootTemplates_Creature.HaveQuestLootForPlayer(lootId, bot)) - { - return true; - } - } + return true; } } } diff --git a/src/strategy/values/NearestCorpsesValue.h b/src/strategy/values/NearestCorpsesValue.h index 9bda863b..6453bb09 100644 --- a/src/strategy/values/NearestCorpsesValue.h +++ b/src/strategy/values/NearestCorpsesValue.h @@ -15,7 +15,7 @@ class NearestCorpsesValue : public NearestUnitsValue { public: NearestCorpsesValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) - : NearestUnitsValue(botAI, "nearest corpses", range) + : NearestUnitsValue(botAI, "nearest corpses", range, true) { } diff --git a/src/strategy/values/SharedValueContext.h b/src/strategy/values/SharedValueContext.h index 5edb41f4..54c3f309 100644 --- a/src/strategy/values/SharedValueContext.h +++ b/src/strategy/values/SharedValueContext.h @@ -50,9 +50,12 @@ public: template Value* getGlobalValue(std::string const name) { - NamedObjectContextList valueContexts; - valueContexts.Add(this); + // should never reach here + SharedNamedObjectContextList sValueContexts; + sValueContexts.Add(this); + NamedObjectContextList valueContexts(sValueContexts); PlayerbotAI* botAI = new PlayerbotAI(); + UntypedValue* value = valueContexts.GetContextObject(name, botAI); delete botAI; return dynamic_cast*>(value); diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 155ded9f..acd92a6d 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -4,16 +4,17 @@ */ #include "WarlockAiObjectContext.h" + #include "AfflictionWarlockStrategy.h" #include "DemonologyWarlockStrategy.h" #include "DestructionWarlockStrategy.h" -#include "TankWarlockStrategy.h" #include "GenericTriggers.h" #include "GenericWarlockNonCombatStrategy.h" #include "NamedObjectContext.h" #include "Playerbots.h" #include "PullStrategy.h" #include "Strategy.h" +#include "TankWarlockStrategy.h" #include "UseItemAction.h" #include "WarlockActions.h" #include "WarlockTriggers.h" @@ -22,14 +23,14 @@ class WarlockStrategyFactoryInternal : public NamedObjectContext { public: WarlockStrategyFactoryInternal() - { + { creators["nc"] = &WarlockStrategyFactoryInternal::nc; creators["pull"] = &WarlockStrategyFactoryInternal::pull; creators["boost"] = &WarlockStrategyFactoryInternal::boost; creators["cc"] = &WarlockStrategyFactoryInternal::cc; creators["pet"] = &WarlockStrategyFactoryInternal::pet; creators["spellstone"] = &WarlockStrategyFactoryInternal::spellstone; - creators["firestone"] = &WarlockStrategyFactoryInternal::firestone; + creators["firestone"] = &WarlockStrategyFactoryInternal::firestone; creators["meta melee"] = &WarlockStrategyFactoryInternal::meta_melee_aoe; creators["tank"] = &WarlockStrategyFactoryInternal::tank; creators["aoe"] = &WarlockStrategyFactoryInternal::aoe; @@ -196,7 +197,10 @@ private: static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); } static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); } static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); } - static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); } + static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) + { + return new UnstableAfflictionOnAttackerTrigger(ai); + } static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); } static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); } static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); } @@ -287,7 +291,7 @@ public: creators["curse of exhaustion"] = &WarlockAiObjectContextInternal::curse_of_exhaustion; creators["curse of tongues"] = &WarlockAiObjectContextInternal::curse_of_tongues; creators["curse of weakness"] = &WarlockAiObjectContextInternal::curse_of_weakness; - } + } private: static Action* conflagrate(PlayerbotAI* botAI) { return new CastConflagrateAction(botAI); } @@ -328,13 +332,19 @@ private: static Action* devour_magic_purge(PlayerbotAI* botAI) { return new CastDevourMagicPurgeAction(botAI); } static Action* devour_magic_cleanse(PlayerbotAI* botAI) { return new CastDevourMagicCleanseAction(botAI); } static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); } - static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) { return new CastSeedOfCorruptionOnAttackerAction(botAI); } + static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) + { + return new CastSeedOfCorruptionOnAttackerAction(botAI); + } static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); } static Action* hellfire(PlayerbotAI* botAI) { return new CastHellfireAction(botAI); } static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); } static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); } static Action* unstable_affliction(PlayerbotAI* ai) { return new CastUnstableAfflictionAction(ai); } - static Action* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new CastUnstableAfflictionOnAttackerAction(ai); } + static Action* unstable_affliction_on_attacker(PlayerbotAI* ai) + { + return new CastUnstableAfflictionOnAttackerAction(ai); + } static Action* haunt(PlayerbotAI* ai) { return new CastHauntAction(ai); } static Action* demonic_empowerment(PlayerbotAI* ai) { return new CastDemonicEmpowermentAction(ai); } static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); } @@ -345,11 +355,14 @@ private: static Action* shadowflame(PlayerbotAI* botAI) { return new CastShadowflameAction(botAI); } static Action* immolation_aura(PlayerbotAI* botAI) { return new CastImmolationAuraAction(botAI); } static Action* chaos_bolt(PlayerbotAI* botAI) { return new CastChaosBoltAction(botAI); } - static Action* soulshatter(PlayerbotAI* botAI) { return new CastSoulshatterAction(botAI);} + static Action* soulshatter(PlayerbotAI* botAI) { return new CastSoulshatterAction(botAI); } static Action* searing_pain(PlayerbotAI* botAI) { return new CastSearingPainAction(botAI); } static Action* shadow_ward(PlayerbotAI* botAI) { return new CastShadowWardAction(botAI); } static Action* curse_of_agony(PlayerbotAI* botAI) { return new CastCurseOfAgonyAction(botAI); } - static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CastCurseOfAgonyOnAttackerAction(botAI); } + static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI) + { + return new CastCurseOfAgonyOnAttackerAction(botAI); + } static Action* curse_of_the_elements(PlayerbotAI* ai) { return new CastCurseOfTheElementsAction(ai); } static Action* curse_of_doom(PlayerbotAI* ai) { return new CastCurseOfDoomAction(ai); } static Action* curse_of_exhaustion(PlayerbotAI* ai) { return new CastCurseOfExhaustionAction(ai); } @@ -357,13 +370,47 @@ private: static Action* curse_of_weakness(PlayerbotAI* ai) { return new CastCurseOfWeaknessAction(ai); } }; -WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList WarlockAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList WarlockAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList WarlockAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList WarlockAiObjectContext::sharedValueContexts; + +WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void WarlockAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void WarlockAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new WarlockStrategyFactoryInternal()); strategyContexts.Add(new WarlockCombatStrategyFactoryInternal()); strategyContexts.Add(new WarlockPetStrategyFactoryInternal()); strategyContexts.Add(new WarlockSoulstoneStrategyFactoryInternal()); strategyContexts.Add(new WarlockCurseStrategyFactoryInternal()); +} + +void WarlockAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new WarlockAiObjectContextInternal()); +} + +void WarlockAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new WarlockTriggerFactoryInternal()); } + +void WarlockAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/warlock/WarlockAiObjectContext.h b/src/strategy/warlock/WarlockAiObjectContext.h index c1feb912..08e6d0f5 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.h +++ b/src/strategy/warlock/WarlockAiObjectContext.h @@ -14,6 +14,17 @@ class WarlockAiObjectContext : public AiObjectContext { public: WarlockAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif diff --git a/src/strategy/warrior/WarriorAiObjectContext.cpp b/src/strategy/warrior/WarriorAiObjectContext.cpp index 0a761c56..bcec922c 100644 --- a/src/strategy/warrior/WarriorAiObjectContext.cpp +++ b/src/strategy/warrior/WarriorAiObjectContext.cpp @@ -318,10 +318,44 @@ private: static Action* enraged_regeneration(PlayerbotAI* botAI) { return new CastEnragedRegenerationAction(botAI); } }; -WarriorAiObjectContext::WarriorAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) +SharedNamedObjectContextList WarriorAiObjectContext::sharedStrategyContexts; +SharedNamedObjectContextList WarriorAiObjectContext::sharedActionContexts; +SharedNamedObjectContextList WarriorAiObjectContext::sharedTriggerContexts; +SharedNamedObjectContextList WarriorAiObjectContext::sharedValueContexts; + +WarriorAiObjectContext::WarriorAiObjectContext(PlayerbotAI* botAI) + : AiObjectContext(botAI, sharedStrategyContexts, sharedActionContexts, sharedTriggerContexts, sharedValueContexts) { +} + +void WarriorAiObjectContext::BuildSharedContexts() +{ + BuildSharedStrategyContexts(sharedStrategyContexts); + BuildSharedActionContexts(sharedActionContexts); + BuildSharedTriggerContexts(sharedTriggerContexts); + BuildSharedValueContexts(sharedValueContexts); +} + +void WarriorAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts) +{ + AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new WarriorStrategyFactoryInternal()); strategyContexts.Add(new WarriorCombatStrategyFactoryInternal()); +} + +void WarriorAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) +{ + AiObjectContext::BuildSharedActionContexts(actionContexts); actionContexts.Add(new WarriorAiObjectContextInternal()); +} + +void WarriorAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts) +{ + AiObjectContext::BuildSharedTriggerContexts(triggerContexts); triggerContexts.Add(new WarriorTriggerFactoryInternal()); } + +void WarriorAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) +{ + AiObjectContext::BuildSharedValueContexts(valueContexts); +} \ No newline at end of file diff --git a/src/strategy/warrior/WarriorAiObjectContext.h b/src/strategy/warrior/WarriorAiObjectContext.h index ab522922..2c9bab97 100644 --- a/src/strategy/warrior/WarriorAiObjectContext.h +++ b/src/strategy/warrior/WarriorAiObjectContext.h @@ -14,6 +14,17 @@ class WarriorAiObjectContext : public AiObjectContext { public: WarriorAiObjectContext(PlayerbotAI* botAI); + + static void BuildSharedContexts(); + static void BuildSharedStrategyContexts(SharedNamedObjectContextList& strategyContexts); + static void BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts); + static void BuildSharedTriggerContexts(SharedNamedObjectContextList& triggerContexts); + static void BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts); + + static SharedNamedObjectContextList sharedStrategyContexts; + static SharedNamedObjectContextList sharedActionContexts; + static SharedNamedObjectContextList sharedTriggerContexts; + static SharedNamedObjectContextList sharedValueContexts; }; #endif From a33bb3b51effd0e311c71e17981b747eab9b9458 Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Fri, 25 Jul 2025 14:02:20 -0700 Subject: [PATCH 4/5] Changes requested Updating based on changes requested for commit --- src/strategy/warlock/WarlockActions.cpp | 25 ++++++++----------- .../warlock/WarlockAiObjectContext.cpp | 4 +-- src/strategy/warlock/WarlockTriggers.cpp | 2 +- src/strategy/warlock/WarlockTriggers.h | 4 +-- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/strategy/warlock/WarlockActions.cpp b/src/strategy/warlock/WarlockActions.cpp index 69f1f335..b3b57871 100644 --- a/src/strategy/warlock/WarlockActions.cpp +++ b/src/strategy/warlock/WarlockActions.cpp @@ -171,24 +171,21 @@ bool CastCreateSoulstoneAction::isUseful() }; // Check if the bot already has any soulstone - uint32 currentSoulstones = 0; - for (uint32 id : soulstoneIds) - currentSoulstones += bot->GetItemCount(id, false); // false = only bags - - // Allow only if the bot has no soulstone AND there is space for one - ItemPosCountVec dest; - uint32 count = 1; - bool hasSpace = false; for (uint32 id : soulstoneIds) { - if (bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count) == EQUIP_ERR_OK) - { - hasSpace = true; - break; - } + if (bot->GetItemCount(id, false) > 0) + return false; // Already has a soulstone } - return (currentSoulstones == 0) && hasSpace; + // Only need to check one soulstone type for bag space (usually the highest-tier) + ItemPosCountVec dest; + uint32 count = 1; + // Use the last in the list (highest tier) + uint32 soulstoneToCreate = soulstoneIds.back(); + + bool hasSpace = (bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, soulstoneToCreate, count) == EQUIP_ERR_OK); + + return hasSpace; } bool DestroySoulShardAction::Execute(Event event) diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 155ded9f..840ee8cd 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -137,7 +137,7 @@ public: creators["no healthstone"] = &WarlockTriggerFactoryInternal::HasHealthstone; creators["no firestone"] = &WarlockTriggerFactoryInternal::HasFirestone; creators["no spellstone"] = &WarlockTriggerFactoryInternal::HasSpellstone; - creators["no soulstone"] = &WarlockTriggerFactoryInternal::HasSoulstone; + creators["no soulstone"] = &WarlockTriggerFactoryInternal::OutOfSoulstone; creators["firestone"] = &WarlockTriggerFactoryInternal::firestone; creators["spellstone"] = &WarlockTriggerFactoryInternal::spellstone; creators["soulstone"] = &WarlockTriggerFactoryInternal::soulstone; @@ -181,7 +181,7 @@ private: static Trigger* HasHealthstone(PlayerbotAI* botAI) { return new HasHealthstoneTrigger(botAI); } static Trigger* HasFirestone(PlayerbotAI* botAI) { return new HasFirestoneTrigger(botAI); } static Trigger* HasSpellstone(PlayerbotAI* botAI) { return new HasSpellstoneTrigger(botAI); } - static Trigger* HasSoulstone(PlayerbotAI* botAI) { return new HasSoulstoneTrigger(botAI); } + static Trigger* OutOfSoulstone(PlayerbotAI* botAI) { return new OutOfSoulstoneTrigger(botAI); } static Trigger* firestone(PlayerbotAI* botAI) { return new FirestoneTrigger(botAI); } static Trigger* spellstone(PlayerbotAI* botAI) { return new SpellstoneTrigger(botAI); } static Trigger* soulstone(PlayerbotAI* botAI) { return new SoulstoneTrigger(botAI); } diff --git a/src/strategy/warlock/WarlockTriggers.cpp b/src/strategy/warlock/WarlockTriggers.cpp index e0493e20..b9794935 100644 --- a/src/strategy/warlock/WarlockTriggers.cpp +++ b/src/strategy/warlock/WarlockTriggers.cpp @@ -46,7 +46,7 @@ bool OutOfSoulShardsTrigger::IsActive() { return GetSoulShardCount(botAI->GetBot bool TooManySoulShardsTrigger::IsActive() { return GetSoulShardCount(botAI->GetBot()) >= 6; } -bool HasSoulstoneTrigger::IsActive() { return GetSoulstoneCount(botAI->GetBot()) == 0; } +bool OutOfSoulstoneTrigger::IsActive() { return GetSoulstoneCount(botAI->GetBot()) == 0; } // Checks if the target marked with the moon icon can be banished bool BanishTrigger::IsActive() diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index 3a448973..e5ce9ad1 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -58,10 +58,10 @@ public: bool IsActive() override; }; -class HasSoulstoneTrigger : public Trigger +class OutOfSoulstoneTrigger : public Trigger { public: - HasSoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soulstone") {} + OutOfSoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soulstone") {} bool IsActive() override; }; From c04477b54db2a5b81cb0f52f99c035973abe39fd Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Fri, 25 Jul 2025 19:00:37 -0700 Subject: [PATCH 5/5] Warlock Pet Re-Summon on Strategy Change Hello everyone, This PR addresses issue #1464 - Now, when you change a strategy, the new pet will be summoned accordingly - as long as the warlock knows the pet. I tested this myself with level 80 warlocks, then moved to lower level warlocks. It was nice to see that when my affliction warlock went from level 29 to 30, it automatically summoned the felhunter (while having the succubus out prior). List of changes per file: src\AiFactory.cpp: Set default level 1 spec to demonology for altbots - it was affliction prior. This will allow them to use Curse of agony, corruption, and immolate between levels 1-10. src\strategy\warlock\GenericWarlockNonCombatStrategy.cpp: Added the "wrong pet" trigger to each of the 5 pet strategies, coupled with the appropriate summon action. src\strategy\warlock\WarlockAiObjectContext.cpp: Registered the "wrong pet" trigger and moved the unstable affliction static trigger all to 1 line, cleaning it up a bit. src\strategy\warlock\WarlockTriggers.cpp: Added the logic for the wrong pet trigger here. I tried to leave detailed comments as much as possible explaining it's thought process. src\strategy\warlock\WarlockTriggers.h: Added the WrongPetTrigger. --- src/AiFactory.cpp | 3 + .../GenericWarlockNonCombatStrategy.cpp | 5 ++ .../warlock/WarlockAiObjectContext.cpp | 9 ++- src/strategy/warlock/WarlockTriggers.cpp | 63 +++++++++++++++++++ src/strategy/warlock/WarlockTriggers.h | 8 +++ 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 7c18070b..722e46b5 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -88,6 +88,9 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot) case CLASS_PRIEST: tab = PRIEST_TAB_HOLY; break; + case CLASS_WARLOCK: + tab = WARLOCK_TAB_DEMONOLOGY; + break; } return tab; diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index 1e2b89af..2fd3c78c 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -98,6 +98,7 @@ SummonImpStrategy::SummonImpStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} void SummonImpStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL))); + triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL))); } // Non-combat strategy for summoning a Voidwalker @@ -109,6 +110,7 @@ SummonVoidwalkerStrategy::SummonVoidwalkerStrategy(PlayerbotAI* ai) : NonCombatS void SummonVoidwalkerStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL))); + triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL))); } // Non-combat strategy for summoning a Succubus @@ -120,6 +122,7 @@ SummonSuccubusStrategy::SummonSuccubusStrategy(PlayerbotAI* ai) : NonCombatStrat void SummonSuccubusStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL))); + triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL))); } // Non-combat strategy for summoning a Felhunter @@ -131,6 +134,7 @@ SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai) : NonCombatStr void SummonFelhunterStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL))); + triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL))); } // Non-combat strategy for summoning a Felguard @@ -142,6 +146,7 @@ SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrat void SummonFelguardStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL))); + triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL))); } // Non-combat strategy for selecting themselves to receive soulstone diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 7603a5e2..8a87a823 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -171,6 +171,7 @@ public: creators["curse of exhaustion"] = &WarlockTriggerFactoryInternal::curse_of_exhaustion; creators["curse of tongues"] = &WarlockTriggerFactoryInternal::curse_of_tongues; creators["curse of weakness"] = &WarlockTriggerFactoryInternal::curse_of_weakness; + creators["wrong pet"] = &WarlockTriggerFactoryInternal::wrong_pet; } private: @@ -197,10 +198,7 @@ private: static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); } static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); } static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); } - static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) - { - return new UnstableAfflictionOnAttackerTrigger(ai); - } + static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); } static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); } static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); } static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); } @@ -218,6 +216,7 @@ private: static Trigger* curse_of_exhaustion(PlayerbotAI* ai) { return new CurseOfExhaustionTrigger(ai); } static Trigger* curse_of_tongues(PlayerbotAI* ai) { return new CurseOfTonguesTrigger(ai); } static Trigger* curse_of_weakness(PlayerbotAI* ai) { return new CurseOfWeaknessTrigger(ai); } + static Trigger* wrong_pet(PlayerbotAI* ai) { return new WrongPetTrigger(ai); } }; class WarlockAiObjectContextInternal : public NamedObjectContext @@ -413,4 +412,4 @@ void WarlockAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContext void WarlockAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) { AiObjectContext::BuildSharedValueContexts(valueContexts); -} \ No newline at end of file +} diff --git a/src/strategy/warlock/WarlockTriggers.cpp b/src/strategy/warlock/WarlockTriggers.cpp index b9794935..e8198c1a 100644 --- a/src/strategy/warlock/WarlockTriggers.cpp +++ b/src/strategy/warlock/WarlockTriggers.cpp @@ -165,3 +165,66 @@ bool CurseOfWeaknessTrigger::IsActive() // Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring) return BuffTrigger::IsActive(); } + +struct WarlockPetDef +{ + const char* strategy; // The strategy string as recognized by the AI (e.g., "imp", "voidwalker", etc.) + uint32 spellId; // The spell ID required to summon this pet + uint32 npcEntry; // The NPC entry ID for the summoned pet creature +}; + +// Static array with all relevant Warlock pets and their data +static const WarlockPetDef pets[] = {{"imp", 688, 416}, + {"voidwalker", 697, 1860}, + {"succubus", 712, 1863}, + {"felhunter", 691, 417}, + {"felguard", 30146, 17252}}; + +bool WrongPetTrigger::IsActive() +{ + // Retrieve the bot player and its current pet (if any) + Player* bot = botAI->GetBot(); + Pet* pet = bot->GetPet(); + + // Step 1: Count how many pet strategies are currently enabled for this bot. + // While doing so, also remember which pet strategy is the only enabled one (if that's the case). + int enabledCount = 0; + const WarlockPetDef* enabledPet = + nullptr; // Pointer to the pet definition of the enabled strategy, if only one is enabled + for (const WarlockPetDef& pd : pets) + { + if (botAI->HasStrategy(pd.strategy, BOT_STATE_NON_COMBAT)) + { + enabledCount++; + enabledPet = &pd; // Save the pointer to last enabled pet + } + } + + // Step 2: If not exactly one pet strategy is enabled, we should not trigger. + // This prevents ambiguous or conflicting situations. + if (enabledCount != 1) + return false; + + // Step 3: At this point, we know only one pet strategy is enabled. + // We check if the currently summoned pet matches the enabled strategy. + bool correctPet = false; + if (pet) + { + CreatureTemplate const* ct = pet->GetCreatureTemplate(); + // Check if the pet's NPC entry matches the expected one for the enabled strategy + if (ct && ct->Entry == enabledPet->npcEntry) + correctPet = true; + } + + // Step 4: If the correct pet is already summoned, the trigger should not activate. + if (correctPet) + return false; + + // Step 5: Finally, check if the bot actually knows the spell to summon the desired pet. + // If so, the trigger is active (bot should summon the correct pet). + if (bot->HasSpell(enabledPet->spellId)) + return true; + + // Step 6: If we get here, the bot doesn't know the spell required to support the active pet strategy + return false; +} diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index e5ce9ad1..e886635a 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -112,6 +112,14 @@ public: HasHealthstoneTrigger(PlayerbotAI* botAI) : WarlockConjuredItemTrigger(botAI, "healthstone") {} }; +class WrongPetTrigger : public Trigger +{ +public: + WrongPetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "wrong pet") {} + bool IsActive() override; +}; + + // CC and Pet Triggers class BanishTrigger : public HasCcTargetTrigger