Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions conf/playerbots.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,16 @@ AiPlayerbot.RandomBotMaps = 0,1,530,571
# Default: 0.25
AiPlayerbot.ProbTeleToBankers = 0.25

# Let guilded randombots use their normal city-banker visits to deposit surplus crafting materials into their guild bank.
# The bot must have a depositable material, a guild-bank tab, and permission to deposit into it.
# Default: 1 (enabled)
AiPlayerbot.EnableRandomBotGuildBankDeposits = 1

# Minimum seconds between successful automatic guild-bank material deposits per randombot.
# Set to 0 to allow a deposit on every eligible city visit.
# Default: 14400 (4 hours)
AiPlayerbot.RandomBotGuildBankDepositCooldown = 14400

# Control probability weights for bots teleporting to Capital city bankers
# Sum of weights need not be 100. Set to 0 to disable teleporting to the city.
AiPlayerbot.EnableWeightTeleToCityBankers = 1
Expand Down
3 changes: 3 additions & 0 deletions src/Ai/Base/ActionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "ChooseTravelTargetAction.h"
#include "CombatActions.h"
#include "DelayAction.h"
#include "DepositGuildMaterialsAction.h"
#include "DestroyItemAction.h"
#include "EmoteAction.h"
#include "FollowActions.h"
Expand Down Expand Up @@ -161,6 +162,7 @@ class ActionContext : public NamedObjectContext<Action>
creators["outfit"] = &ActionContext::outfit;
creators["random bot update"] = &ActionContext::random_bot_update;
creators["delay"] = &ActionContext::delay;
creators["deposit guild materials"] = &ActionContext::deposit_guild_materials;
creators["greet"] = &ActionContext::greet;
creators["check values"] = &ActionContext::check_values;
creators["ra"] = &ActionContext::ra;
Expand Down Expand Up @@ -372,6 +374,7 @@ class ActionContext : public NamedObjectContext<Action>
static Action* outfit(PlayerbotAI* botAI) { return new OutfitAction(botAI); }
static Action* random_bot_update(PlayerbotAI* botAI) { return new RandomBotUpdateAction(botAI); }
static Action* delay(PlayerbotAI* botAI) { return new DelayAction(botAI); }
static Action* deposit_guild_materials(PlayerbotAI* botAI) { return new DepositGuildMaterialsAction(botAI); }

static Action* apply_poison(PlayerbotAI* botAI) { return new ImbueWithPoisonAction(botAI); }
static Action* apply_oil(PlayerbotAI* botAI) { return new ImbueWithOilAction(botAI); }
Expand Down
107 changes: 107 additions & 0 deletions src/Ai/Base/Actions/DepositGuildMaterialsAction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* This file is part of the mod-playerbots module for AzerothCore. See AUTHORS file for Copyright
* information; released under GNU GPL v2 license, redistribute/modify under version 2 of the License,
* or (at your option) any later version.
*/

#include "DepositGuildMaterialsAction.h"

#include "AiObjectContext.h"
#include "ItemUsageValue.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "QuestDef.h"

bool DepositGuildMaterialsAction::Execute(Event /*event*/)
{
if (!bot->IsAlive() || !bot->IsInWorld() || bot->IsBeingTeleported() || bot->IsInCombat() ||
!CanDepositToFirstTab())
return false;

GameObject* bank = GetNearbyGuildBank();
if (!bank)
return false;

CollectItemsVisitor visitor;
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);

bool deposited = false;
for (Item* item : visitor.items)
{
if (!IsDepositCandidate(item))
continue;

// Stop after the first failed transfer. This includes an unpurchased or full first tab,
// and avoids sending an inventory error for every remaining stack.
if (!MoveFromCharToBank(item, bank, false))
break;

deposited = true;
}

return deposited;
}

bool DepositGuildMaterialsAction::isPossible()
{
// This intentionally does not require a nearby guild bank. RandomPlayerbotMgr uses it as a
// location-independent preflight before selecting a city guild-bank visit.
return CanDepositToFirstTab() && HasDepositCandidate();
}

bool DepositGuildMaterialsAction::HasDepositCandidate()
{
CollectItemsVisitor visitor;
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);

for (Item* item : visitor.items)
if (IsDepositCandidate(item))
return true;

return false;
}

bool DepositGuildMaterialsAction::IsDepositCandidate(Item* item)
{
if (!item || item->IsSoulBound() || !item->CanBeTraded())
return false;

ItemTemplate const* proto = item->GetTemplate();
if (!proto || proto->Class != ITEM_CLASS_TRADE_GOODS || proto->Duration > 0 ||
proto->Bonding == BIND_WHEN_PICKED_UP || proto->Bonding == BIND_QUEST_ITEM ||
proto->Bonding == BIND_QUEST_ITEM1 || proto->HasFlag(ITEM_FLAG_HAS_QUEST_GLOW))
return false;

if (IsQuestItem(proto))
return false;

// ItemUsage already knows which reagents and reserve stacks the bot should retain for its
// own professions, as well as active guild-task items. Only donate items the existing usage
// rules consider disposable.
ItemUsage const usage = context->GetValue<ItemUsage>("item usage", item->GetEntry())->Get();
return usage == ITEM_USAGE_NONE || usage == ITEM_USAGE_AH || usage == ITEM_USAGE_VENDOR;
}

bool DepositGuildMaterialsAction::IsQuestItem(ItemTemplate const* proto) const
{
auto isRequiredForActiveQuest = [proto](Player* player)
{
if (!player)
return false;

for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(player->GetQuestSlotQuestId(slot));
if (!quest)
continue;

for (uint8 itemSlot = 0; itemSlot < 4; ++itemSlot)
if (quest->RequiredItemId[itemSlot] == proto->ItemId)
return true;
}

return false;
};

return isRequiredForActiveQuest(bot) || isRequiredForActiveQuest(GetMaster());
}
29 changes: 29 additions & 0 deletions src/Ai/Base/Actions/DepositGuildMaterialsAction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* This file is part of the mod-playerbots module for AzerothCore. See AUTHORS file for Copyright
* information; released under GNU GPL v2 license, redistribute/modify under version 2 of the License,
* or (at your option) any later version.
*/

#ifndef PLAYERBOTS_DEPOSITGUILDMATERIALSACTION_H
#define PLAYERBOTS_DEPOSITGUILDMATERIALSACTION_H

#include "GuildBankAction.h"

class Item;
struct ItemTemplate;

class DepositGuildMaterialsAction : public GuildBankAction
{
public:
DepositGuildMaterialsAction(PlayerbotAI* botAI) : GuildBankAction(botAI, "deposit guild materials") {}

bool Execute(Event event) override;
bool isPossible() override;

private:
bool HasDepositCandidate();
bool IsDepositCandidate(Item* item);
bool IsQuestItem(ItemTemplate const* proto) const;
};

#endif
71 changes: 52 additions & 19 deletions src/Ai/Base/Actions/GuildBankAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

#include "GuildBankAction.h"

#include "GuildMgr.h"
#include "PlayerbotAI.h"
#include "AiObjectContext.h"
#include "GameObject.h"
#include "Guild.h"
#include "PlayerbotAI.h"

bool GuildBankAction::Execute(Event event)
{
Expand All @@ -22,18 +23,33 @@ bool GuildBankAction::Execute(Event event)
return false;
}

GuidVector gos = *botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest game objects");
for (GuidVector::iterator i = gos.begin(); i != gos.end(); ++i)
if (GameObject* bank = GetNearbyGuildBank())
return Execute(text, bank);

botAI->TellMaster("Cannot find the guild bank nearby");
return false;
}

GameObject* GuildBankAction::GetNearbyGuildBank() const
{
GuidVector const gos = *botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest game objects");
for (ObjectGuid const& guid : gos)
{
GameObject* go = botAI->GetGameObject(*i);
if (!go || !bot->GetGameObjectIfCanInteractWith(go->GetGUID(), GAMEOBJECT_TYPE_GUILD_BANK))
GameObject* go = botAI->GetGameObject(guid);
if (!go)
continue;

return Execute(text, go);
if (GameObject* bank = bot->GetGameObjectIfCanInteractWith(go->GetGUID(), GAMEOBJECT_TYPE_GUILD_BANK))
return bank;
}

botAI->TellMaster("Cannot find the guild bank nearby");
return false;
return nullptr;
}

bool GuildBankAction::CanDepositToFirstTab() const
{
Guild* guild = bot->GetGuild();
return guild && guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM);
}

bool GuildBankAction::Execute(std::string const text, GameObject* bank)
Expand All @@ -54,27 +70,44 @@ bool GuildBankAction::Execute(std::string const text, GameObject* bank)
return result;
}

bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* /*bank*/)
bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank, bool report)
{
if (!item || !bank || !bot->GetGameObjectIfCanInteractWith(bank->GetGUID(), GAMEOBJECT_TYPE_GUILD_BANK))
return false;

uint32 playerSlot = item->GetSlot();
uint32 playerBag = item->GetBagSlot();
ObjectGuid const itemGuid = item->GetGUID();
std::string const itemText = chat->FormatItem(item->GetTemplate());

std::ostringstream out;

Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
Guild* guild = bot->GetGuild();
// guild->SwapItems(bot, 0, playerSlot, 0, INVENTORY_SLOT_BAG_0, 0);

// check source pos rights (item moved to bank)
if (!guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
out << "I can't put " << chat->FormatItem(item->GetTemplate())
<< " to guild bank. I have no rights to put items in the first guild bank tab";
else
if (!guild || !guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
{
out << chat->FormatItem(item->GetTemplate()) << " put to guild bank";
guild->SwapItemsWithInventory(bot, false, 0, 255, playerBag, playerSlot, 0);
out << "I can't put " << itemText
<< " to guild bank. I have no rights to put items in the first guild bank tab";
if (report)
botAI->TellMaster(out);
return false;
}

botAI->TellMaster(out);
guild->SwapItemsWithInventory(bot, false, 0, NULL_SLOT, playerBag, playerSlot, 0);

Item* sourceItem = bot->GetItemByPos(playerBag, playerSlot);
bool const moved = !sourceItem || sourceItem->GetGUID() != itemGuid;
if (report)
{
if (moved)
out << itemText << " put to guild bank";
else
out << "I can't put " << itemText << " to guild bank";

botAI->TellMaster(out);
}

return true;
return moved;
}
8 changes: 6 additions & 2 deletions src/Ai/Base/Actions/GuildBankAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ class PlayerbotAI;
class GuildBankAction : public InventoryAction
{
public:
GuildBankAction(PlayerbotAI* botAI) : InventoryAction(botAI, "guild bank") {}
GuildBankAction(PlayerbotAI* botAI, std::string const name = "guild bank") : InventoryAction(botAI, name) {}

bool Execute(Event event) override;

protected:
GameObject* GetNearbyGuildBank() const;
bool CanDepositToFirstTab() const;
bool MoveFromCharToBank(Item* item, GameObject* bank, bool report = true);

private:
bool Execute(std::string const text, GameObject* bank);
bool MoveFromCharToBank(Item* item, GameObject* bank);
};

#endif
Loading
Loading