mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
187 lines
6.1 KiB
C++
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;
|
|
}
|