/* * Copyright (C) 2016+ AzerothCore , 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("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; }