mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Rogue bots can unlock items in their bags and in the trade window (#1055)
This commit is contained in:
@@ -178,6 +178,7 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_RESURRECT_REQUEST, "resurrect request");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_INVENTORY_CHANGE_FAILURE, "cannot equip");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS, "trade status");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS_EXTENDED, "trade status extended");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_RESPONSE, "loot response");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_ITEM_PUSH_RESULT, "item push result");
|
||||
botOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command");
|
||||
@@ -3173,7 +3174,8 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
|
||||
|
||||
SpellCastTargets targets;
|
||||
if (spellInfo->Targets & TARGET_FLAG_ITEM)
|
||||
if (spellInfo->Effects[0].Effect != SPELL_EFFECT_OPEN_LOCK &&
|
||||
(spellInfo->Targets & TARGET_FLAG_ITEM || spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM))
|
||||
{
|
||||
Item* item = itemTarget ? itemTarget : aiObjectContext->GetValue<Item*>("item for spell", spellId)->Get();
|
||||
targets.SetItemTarget(item);
|
||||
@@ -3216,6 +3218,20 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
targets.SetGOTarget(go);
|
||||
faceTo = go;
|
||||
}
|
||||
else if (itemTarget)
|
||||
{
|
||||
Player* trader = bot->GetTrader();
|
||||
if (trader)
|
||||
{
|
||||
targets.SetTradeItemTarget(bot);
|
||||
targets.SetUnitTarget(bot);
|
||||
faceTo = trader;
|
||||
}
|
||||
else
|
||||
{
|
||||
targets.SetItemTarget(itemTarget);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Unit* creature = GetUnit(loot.guid))
|
||||
@@ -3252,6 +3268,58 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
// LOG_DEBUG("playerbots", "Spell cast failed. - target name: {}, spellid: {}, bot name: {}, result: {}",
|
||||
// target->GetName(), spellId, bot->GetName(), result);
|
||||
// }
|
||||
if (HasStrategy("debug spell", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Spell cast failed - ";
|
||||
out << "Spell ID: " << spellId << " (" << ChatHelper::FormatSpell(spellInfo) << "), ";
|
||||
out << "Error Code: " << static_cast<int>(result) << " (0x" << std::hex << static_cast<int>(result) << std::dec << "), ";
|
||||
out << "Bot: " << bot->GetName() << ", ";
|
||||
|
||||
// Check spell target type
|
||||
if (targets.GetUnitTarget())
|
||||
{
|
||||
out << "Target: Unit (" << targets.GetUnitTarget()->GetName()
|
||||
<< ", Low GUID: " << targets.GetUnitTarget()->GetGUID().GetCounter()
|
||||
<< ", High GUID: " << static_cast<uint32>(targets.GetUnitTarget()->GetGUID().GetHigh()) << "), ";
|
||||
}
|
||||
|
||||
if (targets.GetGOTarget())
|
||||
{
|
||||
out << "Target: GameObject (Low GUID: " << targets.GetGOTarget()->GetGUID().GetCounter()
|
||||
<< ", High GUID: " << static_cast<uint32>(targets.GetGOTarget()->GetGUID().GetHigh()) << "), ";
|
||||
}
|
||||
|
||||
if (targets.GetItemTarget())
|
||||
{
|
||||
out << "Target: Item (Low GUID: " << targets.GetItemTarget()->GetGUID().GetCounter()
|
||||
<< ", High GUID: " << static_cast<uint32>(targets.GetItemTarget()->GetGUID().GetHigh()) << "), ";
|
||||
}
|
||||
|
||||
// Check if bot is in trade mode
|
||||
if (bot->GetTradeData())
|
||||
{
|
||||
out << "Trade Mode: Active, ";
|
||||
Item* tradeItem = bot->GetTradeData()->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
|
||||
if (tradeItem)
|
||||
{
|
||||
out << "Trade Item: " << tradeItem->GetEntry()
|
||||
<< " (Low GUID: " << tradeItem->GetGUID().GetCounter()
|
||||
<< ", High GUID: " << static_cast<uint32>(tradeItem->GetGUID().GetHigh()) << "), ";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Trade Item: None, ";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Trade Mode: Inactive, ";
|
||||
}
|
||||
|
||||
TellMasterNoFacing(out);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// if (spellInfo->Effects[0].Effect == SPELL_EFFECT_OPEN_LOCK || spellInfo->Effects[0].Effect ==
|
||||
@@ -3348,7 +3416,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite
|
||||
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
|
||||
|
||||
SpellCastTargets targets;
|
||||
if (spellInfo->Targets & TARGET_FLAG_ITEM)
|
||||
if (spellInfo->Targets & TARGET_FLAG_ITEM || spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM)
|
||||
{
|
||||
Item* item = itemTarget ? itemTarget : aiObjectContext->GetValue<Item*>("item for spell", spellId)->Get();
|
||||
targets.SetItemTarget(item);
|
||||
@@ -4904,6 +4972,52 @@ Item* PlayerbotAI::FindBandage() const
|
||||
{ return pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == ITEM_SUBCLASS_BANDAGE; });
|
||||
}
|
||||
|
||||
Item* PlayerbotAI::FindOpenableItem() const
|
||||
{
|
||||
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
||||
{
|
||||
return (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT) &&
|
||||
(itemTemplate->LockID == 0 || !this->bot->GetItemByEntry(itemTemplate->ItemId)->IsLocked());
|
||||
});
|
||||
}
|
||||
|
||||
Item* PlayerbotAI::FindLockedItem() const
|
||||
{
|
||||
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
||||
{
|
||||
if (!this->bot->HasSkill(SKILL_LOCKPICKING)) // Ensure bot has Lockpicking skill
|
||||
return false;
|
||||
|
||||
if (itemTemplate->LockID == 0) // Ensure the item is actually locked
|
||||
return false;
|
||||
|
||||
Item* item = this->bot->GetItemByEntry(itemTemplate->ItemId);
|
||||
if (!item || !item->IsLocked()) // Ensure item instance is locked
|
||||
return false;
|
||||
|
||||
// Check if bot has enough Lockpicking skill
|
||||
LockEntry const* lockInfo = sLockStore.LookupEntry(itemTemplate->LockID);
|
||||
if (!lockInfo)
|
||||
return false;
|
||||
|
||||
for (uint8 j = 0; j < 8; ++j)
|
||||
{
|
||||
if (lockInfo->Type[j] == LOCK_KEY_SKILL)
|
||||
{
|
||||
uint32 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
|
||||
if (skillId == SKILL_LOCKPICKING)
|
||||
{
|
||||
uint32 requiredSkill = lockInfo->Skill[j];
|
||||
uint32 botSkill = this->bot->GetSkillValue(SKILL_LOCKPICKING);
|
||||
return botSkill >= requiredSkill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
||||
ELEMENTAL_SHARPENING_DISPLAYID, DENSE_SHARPENING_DISPLAYID,
|
||||
SOLID_SHARPENING_DISPLAYID, HEAVY_SHARPENING_DISPLAYID,
|
||||
|
||||
@@ -467,6 +467,8 @@ public:
|
||||
Item* FindPoison() const;
|
||||
Item* FindAmmo() const;
|
||||
Item* FindBandage() const;
|
||||
Item* FindOpenableItem() const;
|
||||
Item* FindLockedItem() const;
|
||||
Item* FindConsumable(uint32 displayId) const;
|
||||
Item* FindStoneFor(Item* weapon) const;
|
||||
Item* FindOilFor(Item* weapon) const;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
#include "WhoAction.h"
|
||||
#include "WtsAction.h"
|
||||
#include "OpenItemAction.h"
|
||||
#include "UnlockItemAction.h"
|
||||
#include "UnlockTradedItemAction.h"
|
||||
|
||||
class ChatActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
@@ -82,6 +84,8 @@ public:
|
||||
ChatActionContext()
|
||||
{
|
||||
creators["open items"] = &ChatActionContext::open_items;
|
||||
creators["unlock items"] = &ChatActionContext::unlock_items;
|
||||
creators["unlock traded item"] = &ChatActionContext::unlock_traded_item;
|
||||
creators["range"] = &ChatActionContext::range;
|
||||
creators["stats"] = &ChatActionContext::stats;
|
||||
creators["quests"] = &ChatActionContext::quests;
|
||||
@@ -184,6 +188,8 @@ public:
|
||||
|
||||
private:
|
||||
static Action* open_items(PlayerbotAI* botAI) { return new OpenItemAction(botAI); }
|
||||
static Action* unlock_items(PlayerbotAI* botAI) { return new UnlockItemAction(botAI); }
|
||||
static Action* unlock_traded_item(PlayerbotAI* botAI) { return new UnlockTradedItemAction(botAI); }
|
||||
static Action* range(PlayerbotAI* botAI) { return new RangeAction(botAI); }
|
||||
static Action* flag(PlayerbotAI* botAI) { return new FlagAction(botAI); }
|
||||
static Action* craft(PlayerbotAI* botAI) { return new SetCraftAction(botAI); }
|
||||
|
||||
@@ -4,64 +4,23 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
bool OpenItemAction::Execute(Event event)
|
||||
{
|
||||
bool foundOpenable = false;
|
||||
|
||||
// Check main inventory slots
|
||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
|
||||
Item* item = botAI->FindOpenableItem();
|
||||
if (item)
|
||||
{
|
||||
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
|
||||
uint8 bag = item->GetBagSlot(); // Retrieves the bag slot (0 for main inventory)
|
||||
uint8 slot = item->GetSlot(); // Retrieves the actual slot inside the bag
|
||||
|
||||
if (item && CanOpenItem(item))
|
||||
{
|
||||
OpenItem(item, INVENTORY_SLOT_BAG_0, slot);
|
||||
foundOpenable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check items in the bags
|
||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||
{
|
||||
Bag* bagItem = bot->GetBagByPos(bag);
|
||||
if (!bagItem)
|
||||
continue;
|
||||
|
||||
for (uint32 slot = 0; slot < bagItem->GetBagSize(); ++slot)
|
||||
{
|
||||
Item* item = bot->GetItemByPos(bag, slot);
|
||||
|
||||
if (item && CanOpenItem(item))
|
||||
{
|
||||
OpenItem(item, bag, slot);
|
||||
foundOpenable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no openable items found
|
||||
if (!foundOpenable)
|
||||
{
|
||||
botAI->TellError("No openable items in inventory.");
|
||||
OpenItem(item, bag, slot);
|
||||
foundOpenable = true;
|
||||
}
|
||||
|
||||
return foundOpenable;
|
||||
}
|
||||
|
||||
bool OpenItemAction::CanOpenItem(Item* item)
|
||||
{
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
ItemTemplate const* itemTemplate = item->GetTemplate();
|
||||
if (!itemTemplate)
|
||||
return false;
|
||||
|
||||
// Check if the item has the openable flag
|
||||
return itemTemplate->Flags & ITEM_FLAG_HAS_LOOT;
|
||||
}
|
||||
|
||||
void OpenItemAction::OpenItem(Item* item, uint8 bag, uint8 slot)
|
||||
{
|
||||
WorldPacket packet(CMSG_OPEN_ITEM);
|
||||
|
||||
@@ -21,9 +21,6 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
// Checks if the given item can be opened (i.e., has the openable flag)
|
||||
bool CanOpenItem(Item* item);
|
||||
|
||||
// Performs the action of opening the item
|
||||
void OpenItem(Item* item, uint8 bag, uint8 slot);
|
||||
};
|
||||
|
||||
@@ -24,12 +24,17 @@ bool TradeStatusAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
PlayerbotAI* traderBotAI = GET_PLAYERBOT_AI(trader);
|
||||
if (trader != master && !traderBotAI)
|
||||
|
||||
// Allow the master and group members to trade
|
||||
if (trader != master && !traderBotAI && (!bot->GetGroup() || !bot->GetGroup()->IsMember(trader->GetGUID())))
|
||||
{
|
||||
bot->Whisper("I'm kind of busy now", LANG_UNIVERSAL, trader);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((trader != master || !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, true, master)) &&
|
||||
// Allow trades from group members or bots
|
||||
if ((!bot->GetGroup() || !bot->GetGroup()->IsMember(trader->GetGUID())) &&
|
||||
(trader != master || !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, true, master)) &&
|
||||
!traderBotAI)
|
||||
{
|
||||
WorldPacket p;
|
||||
@@ -109,9 +114,9 @@ bool TradeStatusAction::Execute(Event event)
|
||||
bot->SetFacingToObject(trader);
|
||||
|
||||
BeginTrade();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
84
src/strategy/actions/TradeStatusExtendedAction.cpp
Normal file
84
src/strategy/actions/TradeStatusExtendedAction.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "TradeStatusExtendedAction.h"
|
||||
#include "Event.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "TradeData.h"
|
||||
|
||||
bool TradeStatusExtendedAction::Execute(Event event)
|
||||
{
|
||||
Player* trader = bot->GetTrader();
|
||||
if (!trader)
|
||||
return false;
|
||||
|
||||
TradeData* tradeData = trader->GetTradeData();
|
||||
if (!tradeData)
|
||||
return false;
|
||||
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
|
||||
uint8 isTraderData;
|
||||
uint32 unknown1, slotCount1, slotCount2, tradeGold, spellCast;
|
||||
p >> isTraderData;
|
||||
p >> unknown1;
|
||||
p >> slotCount1;
|
||||
p >> slotCount2;
|
||||
p >> tradeGold;
|
||||
p >> spellCast;
|
||||
|
||||
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
|
||||
{
|
||||
uint8 tradeSlot;
|
||||
p >> tradeSlot;
|
||||
|
||||
if (tradeSlot >= TRADE_SLOT_COUNT)
|
||||
break; // End of packet
|
||||
|
||||
uint32 itemId, displayId, count, wrapped, lockId;
|
||||
uint64 giftCreator, creator;
|
||||
uint32 permEnchant, gem1, gem2, gem3;
|
||||
uint32 spellCharges, suffixFactor, randomProp, maxDurability, durability;
|
||||
|
||||
p >> itemId;
|
||||
p >> displayId;
|
||||
p >> count;
|
||||
p >> wrapped;
|
||||
p >> giftCreator;
|
||||
p >> permEnchant;
|
||||
p >> gem1;
|
||||
p >> gem2;
|
||||
p >> gem3;
|
||||
p >> creator;
|
||||
p >> spellCharges;
|
||||
p >> suffixFactor;
|
||||
p >> randomProp;
|
||||
p >> lockId;
|
||||
p >> maxDurability;
|
||||
p >> durability;
|
||||
|
||||
// Check for locked items in "Do Not Trade" slot
|
||||
if (tradeSlot == TRADE_SLOT_NONTRADED && lockId > 0)
|
||||
{
|
||||
// Get the actual item reference from TradeData
|
||||
Item* lockbox = tradeData->GetItem(TRADE_SLOT_NONTRADED);
|
||||
if (!lockbox)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(1804) && lockbox->IsLocked()) // Pick Lock spell
|
||||
{
|
||||
// botAI->CastSpell(1804, bot, lockbox); // Attempt to cast Pick Lock on the lockbox
|
||||
botAI->DoSpecificAction("unlock traded item");
|
||||
botAI->SetNextCheckDelay(4000); // Delay before accepting trade
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellMaster("I can't unlock this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
17
src/strategy/actions/TradeStatusExtendedAction.h
Normal file
17
src/strategy/actions/TradeStatusExtendedAction.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _PLAYERBOT_TRADESTATUSEXTENDEDACTION_H
|
||||
#define _PLAYERBOT_TRADESTATUSEXTENDEDACTION_H
|
||||
|
||||
#include "QueryItemUsageAction.h"
|
||||
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
|
||||
class TradeStatusExtendedAction : public QueryItemUsageAction
|
||||
{
|
||||
public:
|
||||
TradeStatusExtendedAction(PlayerbotAI* botAI) : QueryItemUsageAction(botAI, "trade status extended") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
38
src/strategy/actions/UnlockItemAction.cpp
Normal file
38
src/strategy/actions/UnlockItemAction.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "UnlockItemAction.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
|
||||
#define PICK_LOCK_SPELL_ID 1804
|
||||
|
||||
bool UnlockItemAction::Execute(Event event)
|
||||
{
|
||||
bool foundLockedItem = false;
|
||||
|
||||
Item* item = botAI->FindLockedItem();
|
||||
if (item)
|
||||
{
|
||||
UnlockItem(item);
|
||||
foundLockedItem = true;
|
||||
}
|
||||
|
||||
return foundLockedItem;
|
||||
}
|
||||
|
||||
void UnlockItemAction::UnlockItem(Item* item)
|
||||
{
|
||||
// Use CastSpell to unlock the item
|
||||
if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot, item))
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Used Pick Lock on: " << item->GetTemplate()->Name1;
|
||||
botAI->TellMaster(out.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellError("Failed to cast Pick Lock.");
|
||||
}
|
||||
}
|
||||
19
src/strategy/actions/UnlockItemAction.h
Normal file
19
src/strategy/actions/UnlockItemAction.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _PLAYERBOT_UNLOCKITEMACTION_H
|
||||
#define _PLAYERBOT_UNLOCKITEMACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class UnlockItemAction : public Action
|
||||
{
|
||||
public:
|
||||
UnlockItemAction(PlayerbotAI* botAI) : Action(botAI, "unlock item") { }
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
void UnlockItem(Item* item);
|
||||
};
|
||||
|
||||
#endif
|
||||
98
src/strategy/actions/UnlockTradedItemAction.cpp
Normal file
98
src/strategy/actions/UnlockTradedItemAction.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "UnlockTradedItemAction.h"
|
||||
#include "Playerbots.h"
|
||||
#include "TradeData.h"
|
||||
#include "SpellInfo.h"
|
||||
|
||||
#define PICK_LOCK_SPELL_ID 1804
|
||||
|
||||
bool UnlockTradedItemAction::Execute(Event event)
|
||||
{
|
||||
Player* trader = bot->GetTrader();
|
||||
if (!trader)
|
||||
return false; // No active trade session
|
||||
|
||||
TradeData* tradeData = trader->GetTradeData();
|
||||
if (!tradeData)
|
||||
return false; // No trade data available
|
||||
|
||||
Item* lockbox = tradeData->GetItem(TRADE_SLOT_NONTRADED);
|
||||
if (!lockbox)
|
||||
{
|
||||
botAI->TellError("No item in the Do Not Trade slot.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CanUnlockItem(lockbox))
|
||||
{
|
||||
botAI->TellError("Cannot unlock this item.");
|
||||
return false;
|
||||
}
|
||||
|
||||
UnlockItem(lockbox);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnlockTradedItemAction::CanUnlockItem(Item* item)
|
||||
{
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
ItemTemplate const* itemTemplate = item->GetTemplate();
|
||||
if (!itemTemplate)
|
||||
return false;
|
||||
|
||||
// Ensure the bot is a rogue and has Lockpicking skill
|
||||
if (bot->getClass() != CLASS_ROGUE || !botAI->HasSkill(SKILL_LOCKPICKING))
|
||||
return false;
|
||||
|
||||
// Ensure the item is actually locked
|
||||
if (itemTemplate->LockID == 0 || !item->IsLocked())
|
||||
return false;
|
||||
|
||||
// Check if the bot's Lockpicking skill is high enough
|
||||
uint32 lockId = itemTemplate->LockID;
|
||||
LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
|
||||
if (!lockInfo)
|
||||
return false;
|
||||
|
||||
uint32 botSkill = bot->GetSkillValue(SKILL_LOCKPICKING);
|
||||
for (uint8 j = 0; j < 8; ++j)
|
||||
{
|
||||
if (lockInfo->Type[j] == LOCK_KEY_SKILL && SkillByLockType(LockType(lockInfo->Index[j])) == SKILL_LOCKPICKING)
|
||||
{
|
||||
uint32 requiredSkill = lockInfo->Skill[j];
|
||||
if (botSkill >= requiredSkill)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Lockpicking skill too low (" << botSkill << "/" << requiredSkill << ") to unlock: "
|
||||
<< item->GetTemplate()->Name1;
|
||||
botAI->TellMaster(out.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnlockTradedItemAction::UnlockItem(Item* item)
|
||||
{
|
||||
if (!bot->HasSpell(PICK_LOCK_SPELL_ID))
|
||||
{
|
||||
botAI->TellError("Cannot unlock, Pick Lock spell is missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use CastSpell to unlock the item
|
||||
if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot->GetTrader(), item)) // Unit target is trader
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Picking Lock on traded item: " << item->GetTemplate()->Name1;
|
||||
botAI->TellMaster(out.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellError("Failed to cast Pick Lock.");
|
||||
}
|
||||
}
|
||||
20
src/strategy/actions/UnlockTradedItemAction.h
Normal file
20
src/strategy/actions/UnlockTradedItemAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _PLAYERBOT_UNLOCKTRADEDITEMACTION_H
|
||||
#define _PLAYERBOT_UNLOCKTRADEDITEMACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class UnlockTradedItemAction : public Action
|
||||
{
|
||||
public:
|
||||
UnlockTradedItemAction(PlayerbotAI* botAI) : Action(botAI, "unlock traded item") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool CanUnlockItem(Item* item);
|
||||
void UnlockItem(Item* item);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "TellCastFailedAction.h"
|
||||
#include "TellMasterAction.h"
|
||||
#include "TradeStatusAction.h"
|
||||
#include "TradeStatusExtendedAction.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
creators["check mount state"] = &WorldPacketActionContext::check_mount_state;
|
||||
creators["remember taxi"] = &WorldPacketActionContext::remember_taxi;
|
||||
creators["accept trade"] = &WorldPacketActionContext::accept_trade;
|
||||
creators["trade status extended"] = &WorldPacketActionContext::trade_status_extended;
|
||||
creators["store loot"] = &WorldPacketActionContext::store_loot;
|
||||
|
||||
// quest
|
||||
@@ -118,6 +120,7 @@ private:
|
||||
static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); }
|
||||
static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); }
|
||||
static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); }
|
||||
static Action* trade_status_extended(PlayerbotAI* botAI) { return new TradeStatusExtendedAction(botAI); }
|
||||
static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); }
|
||||
static Action* check_mount_state(PlayerbotAI* botAI) { return new CheckMountStateAction(botAI); }
|
||||
static Action* area_trigger(PlayerbotAI* botAI) { return new AreaTriggerAction(botAI); }
|
||||
|
||||
@@ -96,6 +96,10 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
new TriggerNode("open items", NextAction::array(0, new NextAction("open items", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("qi", NextAction::array(0, new NextAction("query item usage", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("unlock items", NextAction::array(0, new NextAction("unlock items", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("unlock traded item", NextAction::array(0, new NextAction("unlock traded item", relevance), nullptr)));
|
||||
}
|
||||
|
||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
@@ -172,4 +176,6 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("calc");
|
||||
supported.push_back("open items");
|
||||
supported.push_back("qi");
|
||||
supported.push_back("unlock items");
|
||||
supported.push_back("unlock traded item");
|
||||
}
|
||||
|
||||
@@ -35,12 +35,15 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
new NextAction("taxi", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("taxi done", NextAction::array(0, new NextAction("taxi", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("trade status", NextAction::array(0, new NextAction("accept trade", relevance), new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("trade status extended", NextAction::array(0, new NextAction("trade status extended", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("area trigger", NextAction::array(0, new NextAction("reach area trigger", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("within area trigger", NextAction::array(0, new NextAction("area trigger", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance), new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("unlock items", relevance),
|
||||
new NextAction("open items", relevance),
|
||||
new NextAction("query item usage", relevance),
|
||||
new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("quest item push result", relevance), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("ready check finished", NextAction::array(0, new NextAction("finish ready check", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new NextAction("check mail", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr)));
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
ChatTriggerContext()
|
||||
{
|
||||
creators["open items"] = &ChatTriggerContext::open_items;
|
||||
creators["unlock items"] = &ChatTriggerContext::unlock_items;
|
||||
creators["unlock traded item"] = &ChatTriggerContext::unlock_traded_item;
|
||||
creators["quests"] = &ChatTriggerContext::quests;
|
||||
creators["stats"] = &ChatTriggerContext::stats;
|
||||
creators["leave"] = &ChatTriggerContext::leave;
|
||||
@@ -133,6 +135,8 @@ public:
|
||||
|
||||
private:
|
||||
static Trigger* open_items(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "open items"); }
|
||||
static Trigger* unlock_items(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "unlock items"); }
|
||||
static Trigger* unlock_traded_item(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "unlock traded item"); }
|
||||
static Trigger* ra(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "ra"); }
|
||||
static Trigger* range(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "range"); }
|
||||
static Trigger* flag(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "flag"); }
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state;
|
||||
creators["activate taxi"] = &WorldPacketTriggerContext::taxi;
|
||||
creators["trade status"] = &WorldPacketTriggerContext::trade_status;
|
||||
creators["trade status extended"] = &WorldPacketTriggerContext::trade_status_extended;
|
||||
creators["loot response"] = &WorldPacketTriggerContext::loot_response;
|
||||
creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range;
|
||||
|
||||
@@ -108,6 +109,7 @@ private:
|
||||
static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); }
|
||||
static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); }
|
||||
static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); }
|
||||
static Trigger* trade_status_extended(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status extended"); }
|
||||
static Trigger* cannot_equip(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cannot equip"); }
|
||||
static Trigger* check_mount_state(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "check mount state"); }
|
||||
static Trigger* area_trigger(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "area trigger"); }
|
||||
|
||||
@@ -71,6 +71,9 @@ Item* ItemForSpellValue::Calculate()
|
||||
if (!strcmpi(spellInfo->SpellName[0], "disenchant"))
|
||||
return nullptr;
|
||||
|
||||
if (!strcmpi(spellInfo->SpellName[0], "pick lock"))
|
||||
return nullptr;
|
||||
|
||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
|
||||
{
|
||||
itemForSpell = GetItemFitsToSpellRequirements(slot, spellInfo);
|
||||
|
||||
Reference in New Issue
Block a user