mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-25 22:46:25 +00:00
[HOT FIX] MS build issues regarding folder / command lenght usage or rc.exe (#2038)
This commit is contained in:
490
src/Ai/Base/Actions/UseItemAction.cpp
Normal file
490
src/Ai/Base/Actions/UseItemAction.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "UseItemAction.h"
|
||||
|
||||
#include "ChatHelper.h"
|
||||
#include "Event.h"
|
||||
#include "ItemUsageValue.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ItemPackets.h"
|
||||
|
||||
bool UseItemAction::Execute(Event event)
|
||||
{
|
||||
std::string name = event.getParam();
|
||||
if (name.empty())
|
||||
name = getName();
|
||||
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", name);
|
||||
GuidVector gos = chat->parseGameobjects(name);
|
||||
|
||||
if (gos.empty())
|
||||
{
|
||||
if (!items.empty())
|
||||
{
|
||||
return UseItemAuto(*items.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (items.empty())
|
||||
return UseGameObject(*gos.begin());
|
||||
else
|
||||
return UseItemOnGameObject(*items.begin(), *gos.begin());
|
||||
}
|
||||
|
||||
botAI->TellError("No items (or game objects) available");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UseItemAction::UseGameObject(ObjectGuid guid)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(guid);
|
||||
if (!go || !go->isSpawned() /* || go->GetGoState() != GO_STATE_READY*/)
|
||||
return false;
|
||||
|
||||
go->Use(bot);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Using " << chat->FormatGameobject(go);
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UseItemAction::UseItemAuto(Item* item) { return UseItem(item, ObjectGuid::Empty, nullptr); }
|
||||
|
||||
bool UseItemAction::UseItemOnGameObject(Item* item, ObjectGuid go) { return UseItem(item, go, nullptr); }
|
||||
|
||||
bool UseItemAction::UseItemOnItem(Item* item, Item* itemTarget) { return UseItem(item, ObjectGuid::Empty, itemTarget); }
|
||||
|
||||
bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Unit* unitTarget)
|
||||
{
|
||||
if (bot->CanUseItem(item) != EQUIP_ERR_OK)
|
||||
return false;
|
||||
|
||||
if (bot->IsNonMeleeSpellCast(false))
|
||||
return false;
|
||||
|
||||
uint8 bagIndex = item->GetBagSlot();
|
||||
uint8 slot = item->GetSlot();
|
||||
uint8 spell_index = 0;
|
||||
uint8 cast_count = 1;
|
||||
ObjectGuid item_guid = item->GetGUID();
|
||||
uint32 glyphIndex = 0;
|
||||
uint8 castFlags = 0;
|
||||
uint32 targetFlag = TARGET_FLAG_NONE;
|
||||
uint32 spellId = 0;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
if (item->GetTemplate()->Spells[i].SpellId > 0)
|
||||
{
|
||||
spellId = item->GetTemplate()->Spells[i].SpellId;
|
||||
if (!botAI->CanCastSpell(spellId, bot, false, itemTarget, item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket packet(CMSG_USE_ITEM);
|
||||
packet << bagIndex << slot << cast_count << spellId << item_guid << glyphIndex << castFlags;
|
||||
|
||||
bool targetSelected = false;
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Using " << chat->FormatItem(item->GetTemplate());
|
||||
|
||||
if (item->GetTemplate()->Stackable > 1)
|
||||
{
|
||||
uint32 count = item->GetCount();
|
||||
if (count > 1)
|
||||
out << " (" << count << " available) ";
|
||||
else
|
||||
out << " (the last one!)";
|
||||
}
|
||||
|
||||
if (goGuid)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(goGuid);
|
||||
if (!go || !go->isSpawned())
|
||||
return false;
|
||||
|
||||
targetFlag = TARGET_FLAG_GAMEOBJECT;
|
||||
|
||||
packet << targetFlag;
|
||||
packet << goGuid.WriteAsPacked();
|
||||
out << " on " << chat->FormatGameobject(go);
|
||||
targetSelected = true;
|
||||
}
|
||||
|
||||
if (itemTarget)
|
||||
{
|
||||
if (item->GetTemplate()->Class == ITEM_CLASS_GEM)
|
||||
{
|
||||
bool fit = SocketItem(itemTarget, item) || SocketItem(itemTarget, item, true);
|
||||
if (!fit)
|
||||
botAI->TellMaster("Socket does not fit");
|
||||
|
||||
return fit;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetFlag = TARGET_FLAG_ITEM;
|
||||
packet << targetFlag;
|
||||
packet << itemTarget->GetGUID().WriteAsPacked();
|
||||
out << " on " << chat->FormatItem(itemTarget->GetTemplate());
|
||||
targetSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!targetSelected && item->GetTemplate()->Class != ITEM_CLASS_CONSUMABLE && master &&
|
||||
botAI->HasActivePlayerMaster() && !selfOnly)
|
||||
{
|
||||
if (ObjectGuid masterSelection = master->GetTarget())
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(masterSelection);
|
||||
if (unit)
|
||||
{
|
||||
targetFlag = TARGET_FLAG_UNIT;
|
||||
packet << targetFlag << masterSelection.WriteAsPacked();
|
||||
out << " on " << unit->GetName();
|
||||
targetSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetSelected && item->GetTemplate()->Class != ITEM_CLASS_CONSUMABLE && unitTarget)
|
||||
{
|
||||
targetFlag = TARGET_FLAG_UNIT;
|
||||
packet << targetFlag << unitTarget->GetGUID().WriteAsPacked();
|
||||
out << " on " << unitTarget->GetName();
|
||||
targetSelected = true;
|
||||
}
|
||||
|
||||
if (uint32 questid = item->GetTemplate()->StartQuest)
|
||||
{
|
||||
if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid))
|
||||
{
|
||||
WorldPacket packet(CMSG_QUESTGIVER_ACCEPT_QUEST, 8 + 4 + 4);
|
||||
packet << item_guid;
|
||||
packet << questid;
|
||||
packet << uint32(0);
|
||||
bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(packet);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Got quest " << chat->FormatQuest(qInfo);
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bot->ClearUnitState(UNIT_STATE_CHASE);
|
||||
bot->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
|
||||
if (bot->isMoving())
|
||||
{
|
||||
bot->StopMoving();
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; i++)
|
||||
{
|
||||
uint32 spellId = item->GetTemplate()->Spells[i].SpellId;
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
if (!botAI->CanCastSpell(spellId, bot, false))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (spellInfo->Targets & TARGET_FLAG_ITEM)
|
||||
{
|
||||
Item* itemForSpell = AI_VALUE2(Item*, "item for spell", spellId);
|
||||
if (!itemForSpell)
|
||||
continue;
|
||||
|
||||
if (itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
continue;
|
||||
|
||||
if (bot->GetTrader())
|
||||
{
|
||||
if (selfOnly)
|
||||
return false;
|
||||
|
||||
targetFlag = TARGET_FLAG_TRADE_ITEM;
|
||||
packet << targetFlag << (uint8)1 << ObjectGuid((uint64)TRADE_SLOT_NONTRADED).WriteAsPacked();
|
||||
targetSelected = true;
|
||||
out << " on traded item";
|
||||
}
|
||||
else
|
||||
{
|
||||
targetFlag = TARGET_FLAG_ITEM;
|
||||
packet << targetFlag;
|
||||
packet << itemForSpell->GetGUID().WriteAsPacked();
|
||||
targetSelected = true;
|
||||
out << " on " << chat->FormatItem(itemForSpell->GetTemplate());
|
||||
}
|
||||
uint32 castTime = spellInfo->CalcCastTime();
|
||||
botAI->SetNextCheckDelay(castTime + sPlayerbotAIConfig->reactDelay);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!targetSelected)
|
||||
{
|
||||
targetFlag = TARGET_FLAG_NONE;
|
||||
packet << targetFlag;
|
||||
|
||||
// Use the actual target if provided
|
||||
if (unitTarget)
|
||||
{
|
||||
packet << unitTarget->GetGUID();
|
||||
targetSelected = true;
|
||||
// If the target is bot or is an enemy, say "on self"
|
||||
if (unitTarget == bot || (unitTarget->IsHostileTo(bot)))
|
||||
out << " on self";
|
||||
else
|
||||
out << " on " << unitTarget->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet << bot->GetPackGUID();
|
||||
targetSelected = true;
|
||||
out << " on self";
|
||||
}
|
||||
}
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
bool isDrink = proto->Spells[0].SpellCategory == 59;
|
||||
bool isFood = proto->Spells[0].SpellCategory == 11;
|
||||
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
|
||||
(proto->SubClass == ITEM_SUBCLASS_FOOD || proto->SubClass == ITEM_SUBCLASS_CONSUMABLE) && (isFood || isDrink))
|
||||
{
|
||||
if (bot->IsInCombat())
|
||||
return false;
|
||||
|
||||
// bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
botAI->InterruptSpell();
|
||||
float hp = bot->GetHealthPct();
|
||||
float mp = bot->GetPower(POWER_MANA) * 100.0f / bot->GetMaxPower(POWER_MANA);
|
||||
float p = 0.f;
|
||||
if (isDrink && isFood)
|
||||
{
|
||||
p = std::min(hp, mp);
|
||||
TellConsumableUse(item, "Feasting", p);
|
||||
}
|
||||
else if (isDrink)
|
||||
{
|
||||
p = mp;
|
||||
TellConsumableUse(item, "Drinking", p);
|
||||
}
|
||||
else if (isFood)
|
||||
{
|
||||
p = std::min(hp, mp);
|
||||
TellConsumableUse(item, "Eating", p);
|
||||
}
|
||||
|
||||
if (!bot->IsInCombat() && !bot->InBattleground())
|
||||
botAI->SetNextCheckDelay(std::max(10000.0f, 27000.0f * (100 - p) / 100.0f));
|
||||
|
||||
if (!bot->IsInCombat() && bot->InBattleground())
|
||||
botAI->SetNextCheckDelay(std::max(10000.0f, 20000.0f * (100 - p) / 100.0f));
|
||||
|
||||
// botAI->SetNextCheckDelay(27000.0f * (100 - p) / 100.0f);
|
||||
// botAI->SetNextCheckDelay(20000);
|
||||
bot->GetSession()->HandleUseItemOpcode(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!spellId)
|
||||
return false;
|
||||
|
||||
// botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
bot->GetSession()->HandleUseItemOpcode(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
void UseItemAction::TellConsumableUse(Item* item, std::string const action, float percent)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << action << " " << chat->FormatItem(item->GetTemplate());
|
||||
|
||||
if (item->GetTemplate()->Stackable > 1)
|
||||
out << "/x" << item->GetCount();
|
||||
|
||||
out << " (" << round(percent) << "%)";
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
}
|
||||
|
||||
bool UseItemAction::SocketItem(Item* item, Item* gem, bool replace)
|
||||
{
|
||||
WorldPacket packet(CMSG_SOCKET_GEMS);
|
||||
packet << item->GetGUID();
|
||||
|
||||
bool fits = false;
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS;
|
||||
++enchant_slot)
|
||||
{
|
||||
uint8 SocketColor = item->GetTemplate()->Socket[enchant_slot - SOCK_ENCHANTMENT_SLOT].Color;
|
||||
GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GemProperties);
|
||||
if (gemProperty && (gemProperty->color & SocketColor))
|
||||
{
|
||||
if (fits)
|
||||
{
|
||||
packet << ObjectGuid::Empty;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if (!enchant_id)
|
||||
{
|
||||
packet << gem->GetGUID();
|
||||
fits = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
||||
if (!enchantEntry || !enchantEntry->GemID)
|
||||
{
|
||||
packet << gem->GetGUID();
|
||||
fits = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (replace && enchantEntry->GemID != gem->GetTemplate()->ItemId)
|
||||
{
|
||||
packet << gem->GetGUID();
|
||||
fits = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
packet << ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
if (fits)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Socketing " << chat->FormatItem(item->GetTemplate());
|
||||
out << " with " << chat->FormatItem(gem->GetTemplate());
|
||||
botAI->TellMaster(out);
|
||||
|
||||
WorldPackets::Item::SocketGems nicePacket(std::move(packet));
|
||||
nicePacket.Read();
|
||||
bot->GetSession()->HandleSocketOpcode(nicePacket);
|
||||
}
|
||||
|
||||
return fits;
|
||||
}
|
||||
|
||||
bool UseItemAction::isPossible() { return getName() == "use" || AI_VALUE2(uint32, "item count", getName()) > 0; }
|
||||
|
||||
bool UseSpellItemAction::isUseful() { return AI_VALUE2(bool, "spell cast useful", getName()); }
|
||||
|
||||
bool UseHealingPotion::isUseful() { return AI_VALUE2(bool, "combat", "self target"); }
|
||||
|
||||
bool UseManaPotion::isUseful() { return AI_VALUE2(bool, "combat", "self target"); }
|
||||
|
||||
bool UseHearthStone::Execute(Event event)
|
||||
{
|
||||
if (bot->isMoving())
|
||||
{
|
||||
MotionMaster& mm = *bot->GetMotionMaster();
|
||||
bot->StopMoving();
|
||||
mm.Clear();
|
||||
}
|
||||
|
||||
bool used = UseItemAction::Execute(event);
|
||||
if (used)
|
||||
{
|
||||
RESET_AI_VALUE(bool, "combat::self target");
|
||||
RESET_AI_VALUE(WorldPosition, "current position");
|
||||
botAI->SetNextCheckDelay(10 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
bool UseHearthStone::isUseful() { return !bot->InBattleground(); }
|
||||
|
||||
bool UseRandomRecipe::isUseful()
|
||||
{
|
||||
return !bot->IsInCombat() && !botAI->HasActivePlayerMaster() && !bot->InBattleground();
|
||||
}
|
||||
|
||||
bool UseRandomRecipe::isPossible() { return AI_VALUE2(uint32, "item count", "recipe") > 0; }
|
||||
|
||||
bool UseRandomRecipe::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> recipes = AI_VALUE2(std::vector<Item*>, "inventory items", "recipe");
|
||||
|
||||
std::string recipeName = "";
|
||||
|
||||
for (auto& recipe : recipes)
|
||||
{
|
||||
recipeName = recipe->GetTemplate()->Name1;
|
||||
}
|
||||
|
||||
if (recipeName.empty())
|
||||
return false;
|
||||
|
||||
bool used = UseItemAction::Execute(Event(name, recipeName));
|
||||
|
||||
if (used)
|
||||
botAI->SetNextCheckDelay(3.0 * IN_MILLISECONDS);
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
bool UseRandomQuestItem::isUseful()
|
||||
{
|
||||
return !botAI->HasActivePlayerMaster() && !bot->InBattleground() && !bot->HasUnitState(UNIT_STATE_IN_FLIGHT);
|
||||
}
|
||||
|
||||
bool UseRandomQuestItem::isPossible() { return AI_VALUE2(uint32, "item count", "quest") > 0; }
|
||||
|
||||
bool UseRandomQuestItem::Execute(Event event)
|
||||
{
|
||||
Unit* unitTarget = nullptr;
|
||||
ObjectGuid goTarget;
|
||||
|
||||
std::vector<Item*> questItems = AI_VALUE2(std::vector<Item*>, "inventory items", "quest");
|
||||
if (questItems.empty())
|
||||
return false;
|
||||
|
||||
Item* item = nullptr;
|
||||
for (uint8 i = 0; i < 5; i++)
|
||||
{
|
||||
auto itr = questItems.begin();
|
||||
std::advance(itr, urand(0, questItems.size() - 1));
|
||||
Item* questItem = *itr;
|
||||
|
||||
ItemTemplate const* proto = questItem->GetTemplate();
|
||||
if (proto->StartQuest)
|
||||
{
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(proto->StartQuest);
|
||||
if (bot->CanTakeQuest(qInfo, false))
|
||||
{
|
||||
item = questItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
bool used = UseItem(item, goTarget, nullptr, unitTarget);
|
||||
if (used)
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
|
||||
return used;
|
||||
}
|
||||
Reference in New Issue
Block a user