Files
mod-playerbots/src/strategy/actions/BuyAction.cpp
2024-07-13 11:41:16 +08:00

187 lines
6.1 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "BuyAction.h"
#include "BudgetValues.h"
#include "Event.h"
#include "ItemVisitors.h"
#include "ItemCountValue.h"
#include "ItemUsageValue.h"
#include "Playerbots.h"
bool BuyAction::Execute(Event event)
{
bool buyUseful = false;
ItemIds itemIds;
std::string const link = event.getParam();
if (link == "vendor")
buyUseful = true;
else
{
itemIds = chat->parseItems(link);
}
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
bool vendored = false;
bool result = false;
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
{
ObjectGuid vendorguid = *i;
Creature* pCreature = bot->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
continue;
vendored = true;
if (buyUseful)
{
// Items are evaluated from high-level to low level.
// For each item the bot checks again if an item is usefull.
// Bot will buy until no usefull items are left.
VendorItemData const* tItems = pCreature->GetVendorItems();
if (!tItems)
continue;
VendorItemList m_items_sorted = tItems->m_items;
m_items_sorted.erase(std::remove_if(m_items_sorted.begin(), m_items_sorted.end(), [](VendorItem* i)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->item);
return !proto;
}), m_items_sorted.end());
if (m_items_sorted.empty())
continue;
std::sort(m_items_sorted.begin(), m_items_sorted.end(), [](VendorItem* i, VendorItem* j) { return sObjectMgr->GetItemTemplate(i->item)->ItemLevel > sObjectMgr->GetItemTemplate(j->item)->ItemLevel; });
for (auto& tItem : m_items_sorted)
{
for (uint32 i = 0; i < 10; i++) // Buy 10 times or until no longer usefull/possible
{
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", tItem->item);
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(tItem->item);
uint32 price = proto->BuyPrice;
// reputation discount
price = uint32(floor(price * bot->GetReputationPriceDiscount(pCreature)));
NeedMoneyFor needMoneyFor = NeedMoneyFor::none;
switch (usage)
{
case ITEM_USAGE_REPLACE:
case ITEM_USAGE_EQUIP:
needMoneyFor = NeedMoneyFor::gear;
break;
case ITEM_USAGE_AMMO:
needMoneyFor = NeedMoneyFor::ammo;
break;
case ITEM_USAGE_QUEST:
needMoneyFor = NeedMoneyFor::anything;
break;
case ITEM_USAGE_USE:
needMoneyFor = NeedMoneyFor::consumables;
break;
case ITEM_USAGE_SKILL:
needMoneyFor = NeedMoneyFor::tradeskill;
break;
default:
break;
}
if (needMoneyFor == NeedMoneyFor::none)
break;
if (AI_VALUE2(uint32, "free money for", uint32(needMoneyFor)) < price)
break;
if (!BuyItem(tItems, vendorguid, proto))
break;
if (usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_EQUIP) // Equip upgrades and stop buying this time.
{
botAI->DoSpecificAction("equip upgrades");
break;
}
}
}
}
else
{
if (itemIds.empty())
return false;
for (ItemIds::iterator i = itemIds.begin(); i != itemIds.end(); i++)
{
uint32 itemId = *i;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
continue;
result |= BuyItem(pCreature->GetVendorItems(), vendorguid, proto);
if (!result)
{
std::ostringstream out;
out << "Nobody sells " << ChatHelper::FormatItem(proto) << " nearby";
botAI->TellMaster(out.str());
}
}
}
}
if (!vendored)
{
botAI->TellError("There are no vendors nearby");
return false;
}
return true;
}
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
{
uint32 oldCount = AI_VALUE2(uint32, "item count", proto->Name1);
if (!tItems)
return false;
uint32 itemId = proto->ItemId;
for (uint32 slot = 0; slot < tItems->GetItemCount(); slot++)
{
if (tItems->GetItem(slot)->item == itemId)
{
uint32 botMoney = bot->GetMoney();
if (botAI->HasCheat(BotCheatMask::gold))
{
bot->SetMoney(10000000);
}
bot->BuyItemFromVendorSlot(vendorguid, slot, itemId, 1, NULL_BAG, NULL_SLOT);
if (botAI->HasCheat(BotCheatMask::gold))
{
bot->SetMoney(botMoney);
}
if (oldCount < AI_VALUE2(uint32, "item count", proto->Name1)) // BuyItem Always returns false (unless unique) so we have to check the item counts.
{
std::ostringstream out;
out << "Buying " << ChatHelper::FormatItem(proto);
botAI->TellMaster(out.str());
return true;
}
return false;
}
}
return false;
}