mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
ItemUsageValue: Handle items that create required items (#1091)
* Updated IsItemUsefulForQuest to handle items that create required quest items * Debug output * Removed unneeded botAI-> * Debug output in Calculate * -> not . * Comprehensive debug output for quest usage * Corrected logic for lootable items when sync quest is enabled * #include "LootObjectStack.h" * Corrected call to IsItem * Removed debug statements * Reimplement ItemCount >= RequiredItemCount * Modified CanLoot to loot all items when loot source is an item in their bags * Set loot target when sending Open packet
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
bool OpenItemAction::Execute(Event event)
|
||||
{
|
||||
bool foundOpenable = false;
|
||||
@@ -27,6 +30,11 @@ void OpenItemAction::OpenItem(Item* item, uint8 bag, uint8 slot)
|
||||
packet << bag << slot;
|
||||
bot->GetSession()->HandleOpenItemOpcode(packet);
|
||||
|
||||
// Store the item GUID as the loot target
|
||||
LootObject lootObject;
|
||||
lootObject.guid = item->GetGUID();
|
||||
botAI->GetAiObjectContext()->GetValue<LootObject>("loot target")->Set(lootObject);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Opened item: " << item->GetTemplate()->Name1;
|
||||
botAI->TellMaster(out.str());
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "AiFactory.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "GuildTaskMgr.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
@@ -112,12 +113,38 @@ ItemUsage ItemUsageValue::Calculate()
|
||||
return ITEM_USAGE_DISENCHANT;
|
||||
}
|
||||
|
||||
// While sync is on, do not loot quest items that are also Useful for master. Master
|
||||
if (!botAI->GetMaster() || !sPlayerbotAIConfig->syncQuestWithPlayer ||
|
||||
!IsItemUsefulForQuest(botAI->GetMaster(), proto))
|
||||
if (IsItemUsefulForQuest(bot, proto))
|
||||
return ITEM_USAGE_QUEST;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
bool isSelfBot = (master == bot);
|
||||
bool botNeedsItemForQuest = IsItemUsefulForQuest(bot, proto);
|
||||
bool masterNeedsItemForQuest = master && sPlayerbotAIConfig->syncQuestWithPlayer && IsItemUsefulForQuest(master, proto);
|
||||
|
||||
// Identify the source of loot
|
||||
LootObject lootObject = AI_VALUE(LootObject, "loot target");
|
||||
|
||||
// Get GUID of loot source
|
||||
ObjectGuid lootGuid = lootObject.guid;
|
||||
|
||||
// Check if loot source is an item
|
||||
bool isLootFromItem = lootGuid.IsItem();
|
||||
|
||||
// If the loot is from an item in the bot’s bags, ignore syncQuestWithPlayer
|
||||
if (isLootFromItem && botNeedsItemForQuest)
|
||||
{
|
||||
return ITEM_USAGE_QUEST;
|
||||
}
|
||||
|
||||
// If the bot is NOT acting alone and the master needs this quest item, defer to the master
|
||||
if (!isSelfBot && masterNeedsItemForQuest)
|
||||
{
|
||||
return ITEM_USAGE_NONE;
|
||||
}
|
||||
|
||||
// If the bot itself needs the item for a quest, allow looting
|
||||
if (botNeedsItemForQuest)
|
||||
{
|
||||
return ITEM_USAGE_QUEST;
|
||||
}
|
||||
|
||||
if (proto->Class == ITEM_CLASS_PROJECTILE && bot->CanUseItem(proto) == EQUIP_ERR_OK)
|
||||
{
|
||||
if (bot->getClass() == CLASS_HUNTER || bot->getClass() == CLASS_ROGUE || bot->getClass() == CLASS_WARRIOR)
|
||||
@@ -464,6 +491,10 @@ uint32 ItemUsageValue::GetSmallestBagSize()
|
||||
|
||||
bool ItemUsageValue::IsItemUsefulForQuest(Player* player, ItemTemplate const* proto)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
if (!botAI)
|
||||
return false;
|
||||
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 entry = player->GetQuestSlotQuestId(slot);
|
||||
@@ -471,20 +502,52 @@ bool ItemUsageValue::IsItemUsefulForQuest(Player* player, ItemTemplate const* pr
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
// Check if the item itself is needed for the quest
|
||||
for (uint8 i = 0; i < 4; i++)
|
||||
{
|
||||
if (quest->RequiredItemId[i] != proto->ItemId)
|
||||
if (quest->RequiredItemId[i] == proto->ItemId)
|
||||
{
|
||||
if (AI_VALUE2(uint32, "item count", proto->Name1) >= quest->RequiredItemCount[i])
|
||||
continue;
|
||||
|
||||
return true; // Item is directly required for a quest
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the item has spells that create a required quest item
|
||||
for (uint8 i = 0; i < MAX_ITEM_SPELLS; i++)
|
||||
{
|
||||
uint32 spellId = proto->Spells[i].SpellId;
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
if (GET_PLAYERBOT_AI(player) &&
|
||||
AI_VALUE2(uint32, "item count", proto->Name1) >= quest->RequiredItemCount[i])
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
return true;
|
||||
for (uint8 effectIndex = 0; effectIndex < MAX_SPELL_EFFECTS; effectIndex++)
|
||||
{
|
||||
if (spellInfo->Effects[effectIndex].Effect == SPELL_EFFECT_CREATE_ITEM)
|
||||
{
|
||||
uint32 createdItemId = spellInfo->Effects[effectIndex].ItemType;
|
||||
|
||||
// Check if the created item is required for a quest
|
||||
for (uint8 j = 0; j < 4; j++)
|
||||
{
|
||||
if (quest->RequiredItemId[j] == createdItemId)
|
||||
{
|
||||
if (AI_VALUE2(uint32, "item count", createdItemId) >= quest->RequiredItemCount[j])
|
||||
continue;
|
||||
|
||||
return true; // Item is useful because it creates a required quest item
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false; // Item is not useful for any active quests
|
||||
}
|
||||
|
||||
bool ItemUsageValue::IsItemNeededForSkill(ItemTemplate const* proto)
|
||||
|
||||
@@ -15,6 +15,15 @@ class NormalLootStrategy : public LootStrategy
|
||||
public:
|
||||
bool CanLoot(ItemTemplate const* proto, AiObjectContext* context) override
|
||||
{
|
||||
// Identify the source of loot, loot it if the source is an item in the bots inventory
|
||||
LootObject lootObject = AI_VALUE(LootObject, "loot target");
|
||||
ObjectGuid lootGuid = lootObject.guid;
|
||||
if (lootGuid.IsItem())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, continue with the normal loot logic
|
||||
std::ostringstream out;
|
||||
out << proto->ItemId;
|
||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", out.str());
|
||||
|
||||
Reference in New Issue
Block a user