mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-10 20:22:41 +00:00
[Bots] Bot::PerformTradeWithClient Cleanup. (#2084)
* [Bots] Bot::PerformTradeWithClient Cleanup. - Cleanups message and logic. - Initial cleanup to eventually allow easy use with Perl/Lua quest API. * Duplicated comment.
This commit is contained in:
parent
8f0b80097e
commit
759f9bd007
353
zone/bot.cpp
353
zone/bot.cpp
@ -4206,28 +4206,24 @@ void Bot::FinishTrade(Client* client, BotTradeType tradeType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perfoms the actual trade action with a client bot owner
|
// Perfoms the actual trade action with a client bot owner
|
||||||
void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client)
|
void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client* client)
|
||||||
{
|
{
|
||||||
using namespace EQ;
|
using namespace EQ;
|
||||||
|
|
||||||
struct ClientTrade {
|
struct ClientTrade {
|
||||||
const ItemInstance* tradeItemInstance;
|
const ItemInstance* trade_item_instance;
|
||||||
int16 fromClientSlot;
|
int16 from_client_slot;
|
||||||
int16 toBotSlot;
|
int16 to_bot_slot;
|
||||||
int adjustStackSize;
|
|
||||||
std::string acceptedItemName;
|
|
||||||
|
|
||||||
ClientTrade(const ItemInstance* item, int16 from, const char* name = "") : tradeItemInstance(item), fromClientSlot(from), toBotSlot(invslot::SLOT_INVALID), adjustStackSize(0), acceptedItemName(name) { }
|
ClientTrade(const ItemInstance* item, int16 from) : trade_item_instance(item), from_client_slot(from), to_bot_slot(invslot::SLOT_INVALID) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClientReturn {
|
struct ClientReturn {
|
||||||
const ItemInstance* returnItemInstance;
|
const ItemInstance* return_item_instance;
|
||||||
int16 fromBotSlot;
|
int16 from_bot_slot;
|
||||||
int16 toClientSlot;
|
int16 to_client_slot;
|
||||||
int adjustStackSize;
|
|
||||||
std::string failedItemName;
|
|
||||||
|
|
||||||
ClientReturn(const ItemInstance* item, int16 from, const char* name = "") : returnItemInstance(item), fromBotSlot(from), toClientSlot(invslot::SLOT_INVALID), adjustStackSize(0), failedItemName(name) { }
|
ClientReturn(const ItemInstance* item, int16 from) : return_item_instance(item), from_bot_slot(from), to_client_slot(invslot::SLOT_INVALID) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int16 bot_equip_order[invslot::EQUIPMENT_COUNT] = {
|
static const int16 bot_equip_order[invslot::EQUIPMENT_COUNT] = {
|
||||||
@ -4247,32 +4243,37 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (client != GetOwner()) {
|
if (client != GetOwner()) {
|
||||||
client->Message(Chat::Red, "You are not the owner of this bot - Trade Canceled.");
|
client->Message(Chat::Red, "You are not the owner of this bot, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((beginSlotID != invslot::TRADE_BEGIN) && (beginSlotID != invslot::slotCursor)) {
|
|
||||||
client->Message(Chat::Red, "Trade request processing from illegal 'begin' slot - Trade Canceled.");
|
if (begin_slot_id != invslot::TRADE_BEGIN && begin_slot_id != invslot::slotCursor) {
|
||||||
|
client->Message(Chat::Red, "Trade request processing from illegal 'begin' slot, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((endSlotID != invslot::TRADE_END) && (endSlotID != invslot::slotCursor)) {
|
|
||||||
client->Message(Chat::Red, "Trade request processing from illegal 'end' slot - Trade Canceled.");
|
if (end_slot_id != invslot::TRADE_END && end_slot_id != invslot::slotCursor) {
|
||||||
|
client->Message(Chat::Red, "Trade request processing from illegal 'end' slot, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (((beginSlotID == invslot::slotCursor) && (endSlotID != invslot::slotCursor)) || ((beginSlotID != invslot::slotCursor) && (endSlotID == invslot::slotCursor))) {
|
|
||||||
client->Message(Chat::Red, "Trade request processing illegal slot range - Trade Canceled.");
|
if ((begin_slot_id == invslot::slotCursor && end_slot_id != invslot::slotCursor) || (begin_slot_id != invslot::slotCursor && end_slot_id == invslot::slotCursor)) {
|
||||||
|
client->Message(Chat::Red, "Trade request processing illegal slot range, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (endSlotID < beginSlotID) {
|
|
||||||
client->Message(Chat::Red, "Trade request processing in reverse slot order - Trade Canceled.");
|
if (end_slot_id < begin_slot_id) {
|
||||||
|
client->Message(Chat::Red, "Trade request processing in reverse slot order, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->IsEngaged() || IsEngaged()) {
|
if (client->IsEngaged() || IsEngaged()) {
|
||||||
client->Message(Chat::Yellow, "You may not perform a trade while engaged - Trade Canceled!");
|
client->Message(Chat::Yellow, "You may not perform a trade while engaged, the trade has been cancelled!");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4281,66 +4282,100 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
std::list<ClientReturn> client_return;
|
std::list<ClientReturn> client_return;
|
||||||
|
|
||||||
// pre-checks for incoming illegal transfers
|
// pre-checks for incoming illegal transfers
|
||||||
for (int16 trade_index = beginSlotID; trade_index <= endSlotID; ++trade_index) {
|
for (int16 trade_index = begin_slot_id; trade_index <= end_slot_id; ++trade_index) {
|
||||||
auto trade_instance = client->GetInv()[trade_index];
|
auto trade_instance = client->GetInv()[trade_index];
|
||||||
if (!trade_instance)
|
if (!trade_instance) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!trade_instance->GetItem()) {
|
if (!trade_instance->GetItem()) {
|
||||||
// TODO: add logging
|
LogError("Bot::PerformTradeWithClient could not find item from instance in trade for {} with {} in slot {}.", client->GetCleanName(), GetCleanName(), trade_index);
|
||||||
client->Message(Chat::Red, "A server error was encountered while processing client slot %i - Trade Canceled.", trade_index);
|
client->Message(
|
||||||
|
Chat::Red,
|
||||||
|
fmt::format(
|
||||||
|
"A server error was encountered while processing client slot {}, the trade has been cancelled.",
|
||||||
|
trade_index
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((trade_index != invslot::slotCursor) && !trade_instance->IsDroppable()) {
|
|
||||||
// TODO: add logging
|
EQ::SayLinkEngine linker;
|
||||||
client->Message(Chat::Red, "Trade hack detected - Trade Canceled.");
|
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||||
|
linker.SetItemInst(trade_instance);
|
||||||
|
|
||||||
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
|
if (trade_index != invslot::slotCursor && !trade_instance->IsDroppable()) {
|
||||||
|
LogError("Bot::PerformTradeWithClient trade hack detected by {} with {}.", client->GetCleanName(), GetCleanName());
|
||||||
|
client->Message(Chat::Red, "Trade hack detected, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trade_instance->IsStackable() && (trade_instance->GetCharges() < trade_instance->GetItem()->StackSize)) { // temp until partial stacks are implemented
|
if (trade_instance->IsStackable() && (trade_instance->GetCharges() < trade_instance->GetItem()->StackSize)) { // temp until partial stacks are implemented
|
||||||
client->Message(Chat::Yellow, "'%s' is only a partially stacked item - Trade Canceled!", trade_instance->GetItem()->Name);
|
client->Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"{} is only a partially stacked item, the trade has been cancelled!",
|
||||||
|
item_link
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckLoreConflict(trade_instance->GetItem())) {
|
if (CheckLoreConflict(trade_instance->GetItem())) {
|
||||||
client->Message(Chat::Yellow, "This bot already has lore equipment matching the item '%s' - Trade Canceled!", trade_instance->GetItem()->Name);
|
client->Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"This bot already has {}, the trade has been cancelled!",
|
||||||
|
item_link
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trade_instance->IsType(item::ItemClassCommon)) {
|
if (!trade_instance->IsType(item::ItemClassCommon)) {
|
||||||
client_return.push_back(ClientReturn(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
client_return.push_back(ClientReturn(trade_instance, trade_index));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!trade_instance->IsEquipable(GetBaseRace(), GetClass()) || (GetLevel() < trade_instance->GetItem()->ReqLevel)) { // deity checks will be handled within IsEquipable()
|
|
||||||
client_return.push_back(ClientReturn(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_trade.push_back(ClientTrade(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
if (!trade_instance->IsEquipable(GetBaseRace(), GetClass()) || (GetLevel() < trade_instance->GetItem()->ReqLevel)) { // deity checks will be handled within IsEquipable()
|
||||||
|
client_return.push_back(ClientReturn(trade_instance, trade_index));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_trade.push_back(ClientTrade(trade_instance, trade_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for incoming lore hacks
|
// check for incoming lore hacks
|
||||||
for (auto& trade_iterator : client_trade) {
|
for (auto& trade_iterator : client_trade) {
|
||||||
if (!trade_iterator.tradeItemInstance->GetItem()->LoreFlag)
|
if (!trade_iterator.trade_item_instance->GetItem()->LoreFlag) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& check_iterator : client_trade) {
|
for (const auto& check_iterator : client_trade) {
|
||||||
if (check_iterator.fromClientSlot == trade_iterator.fromClientSlot)
|
if (check_iterator.from_client_slot == trade_iterator.from_client_slot) {
|
||||||
continue;
|
|
||||||
if (!check_iterator.tradeItemInstance->GetItem()->LoreFlag)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ((trade_iterator.tradeItemInstance->GetItem()->LoreGroup == -1) && (check_iterator.tradeItemInstance->GetItem()->ID == trade_iterator.tradeItemInstance->GetItem()->ID)) {
|
if (!check_iterator.trade_item_instance->GetItem()->LoreFlag) {
|
||||||
// TODO: add logging
|
continue;
|
||||||
client->Message(Chat::Red, "Trade hack detected - Trade Canceled.");
|
}
|
||||||
|
|
||||||
|
if (trade_iterator.trade_item_instance->GetItem()->LoreGroup == -1 && check_iterator.trade_item_instance->GetItem()->ID == trade_iterator.trade_item_instance->GetItem()->ID) {
|
||||||
|
LogError("Bot::PerformTradeWithClient trade hack detected by {} with {}.", client->GetCleanName(), GetCleanName());
|
||||||
|
client->Message(Chat::Red, "Trade hack detected, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((trade_iterator.tradeItemInstance->GetItem()->LoreGroup > 0) && (check_iterator.tradeItemInstance->GetItem()->LoreGroup == trade_iterator.tradeItemInstance->GetItem()->LoreGroup)) {
|
|
||||||
// TODO: add logging
|
if ((trade_iterator.trade_item_instance->GetItem()->LoreGroup > 0) && (check_iterator.trade_item_instance->GetItem()->LoreGroup == trade_iterator.trade_item_instance->GetItem()->LoreGroup)) {
|
||||||
client->Message(Chat::Red, "Trade hack detected - Trade Canceled.");
|
LogError("Bot::PerformTradeWithClient trade hack detected by {} with {}.", client->GetCleanName(), GetCleanName());
|
||||||
|
client->Message(Chat::Red, "Trade hack detected, the trade has been cancelled.");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4355,16 +4390,18 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
//for (unsigned stage_loop = stageStackable; stage_loop <= stageReplaceable; ++stage_loop) { // awaiting implementation
|
//for (unsigned stage_loop = stageStackable; stage_loop <= stageReplaceable; ++stage_loop) { // awaiting implementation
|
||||||
for (unsigned stage_loop = stageEmpty; stage_loop <= stageReplaceable; ++stage_loop) {
|
for (unsigned stage_loop = stageEmpty; stage_loop <= stageReplaceable; ++stage_loop) {
|
||||||
for (auto& trade_iterator : client_trade) {
|
for (auto& trade_iterator : client_trade) {
|
||||||
if (trade_iterator.toBotSlot != invslot::SLOT_INVALID)
|
if (trade_iterator.to_bot_slot != invslot::SLOT_INVALID) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
auto trade_instance = trade_iterator.tradeItemInstance;
|
auto trade_instance = trade_iterator.trade_item_instance;
|
||||||
//if ((stage_loop == stageStackable) && !trade_instance->IsStackable())
|
//if ((stage_loop == stageStackable) && !trade_instance->IsStackable())
|
||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
for (auto index : bot_equip_order) {
|
for (auto index : bot_equip_order) {
|
||||||
if (!(trade_instance->GetItem()->Slots & (1 << index)))
|
if (!(trade_instance->GetItem()->Slots & (1 << index))) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//if (stage_loop == stageStackable) {
|
//if (stage_loop == stageStackable) {
|
||||||
// // TODO: implement
|
// // TODO: implement
|
||||||
@ -4372,59 +4409,64 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
if (stage_loop != stageReplaceable) {
|
if (stage_loop != stageReplaceable) {
|
||||||
if (m_inv[index])
|
if (m_inv[index]) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool slot_taken = false;
|
bool slot_taken = false;
|
||||||
for (const auto& check_iterator : client_trade) {
|
for (const auto& check_iterator : client_trade) {
|
||||||
if (check_iterator.fromClientSlot == trade_iterator.fromClientSlot)
|
if (check_iterator.from_client_slot == trade_iterator.from_client_slot) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (check_iterator.toBotSlot == index) {
|
if (check_iterator.to_bot_slot == index) {
|
||||||
slot_taken = true;
|
slot_taken = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (slot_taken)
|
|
||||||
|
if (slot_taken) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (index == invslot::slotPrimary) {
|
if (index == invslot::slotPrimary) {
|
||||||
if (trade_instance->GetItem()->IsType2HWeapon()) {
|
if (trade_instance->GetItem()->IsType2HWeapon()) {
|
||||||
if (!melee_secondary) {
|
if (!melee_secondary) {
|
||||||
melee_2h_weapon = true;
|
melee_2h_weapon = true;
|
||||||
|
|
||||||
auto equipped_secondary_weapon = m_inv[invslot::slotSecondary];
|
auto equipped_secondary_weapon = m_inv[invslot::slotSecondary];
|
||||||
if (equipped_secondary_weapon)
|
if (equipped_secondary_weapon) {
|
||||||
client_return.push_back(ClientReturn(equipped_secondary_weapon, invslot::slotSecondary));
|
client_return.push_back(ClientReturn(equipped_secondary_weapon, invslot::slotSecondary));
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (index == invslot::slotSecondary) {
|
||||||
if (index == invslot::slotSecondary) {
|
|
||||||
if (!melee_2h_weapon) {
|
if (!melee_2h_weapon) {
|
||||||
if ((can_dual_wield && trade_instance->GetItem()->IsType1HWeapon()) || trade_instance->GetItem()->IsTypeShield() || !trade_instance->IsWeapon()) {
|
if (
|
||||||
|
(can_dual_wield && trade_instance->GetItem()->IsType1HWeapon()) ||
|
||||||
|
trade_instance->GetItem()->IsTypeShield() ||
|
||||||
|
!trade_instance->IsWeapon()
|
||||||
|
) {
|
||||||
melee_secondary = true;
|
melee_secondary = true;
|
||||||
|
|
||||||
auto equipped_primary_weapon = m_inv[invslot::slotPrimary];
|
auto equipped_primary_weapon = m_inv[invslot::slotPrimary];
|
||||||
if (equipped_primary_weapon && equipped_primary_weapon->GetItem()->IsType2HWeapon())
|
if (equipped_primary_weapon && equipped_primary_weapon->GetItem()->IsType2HWeapon()) {
|
||||||
client_return.push_back(ClientReturn(equipped_primary_weapon, invslot::slotPrimary));
|
client_return.push_back(ClientReturn(equipped_primary_weapon, invslot::slotPrimary));
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trade_iterator.toBotSlot = index;
|
trade_iterator.to_bot_slot = index;
|
||||||
|
|
||||||
if (m_inv[index])
|
if (m_inv[index]) {
|
||||||
client_return.push_back(ClientReturn(m_inv[index], index));
|
client_return.push_back(ClientReturn(m_inv[index], index));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4433,8 +4475,8 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
|
|
||||||
// move unassignable items from trade list to return list
|
// move unassignable items from trade list to return list
|
||||||
for (std::list<ClientTrade>::iterator trade_iterator = client_trade.begin(); trade_iterator != client_trade.end();) {
|
for (std::list<ClientTrade>::iterator trade_iterator = client_trade.begin(); trade_iterator != client_trade.end();) {
|
||||||
if (trade_iterator->toBotSlot == invslot::SLOT_INVALID) {
|
if (trade_iterator->to_bot_slot == invslot::SLOT_INVALID) {
|
||||||
client_return.push_back(ClientReturn(trade_iterator->tradeItemInstance, trade_iterator->fromClientSlot, trade_iterator->tradeItemInstance->GetItem()->Name));
|
client_return.push_back(ClientReturn(trade_iterator->trade_item_instance, trade_iterator->from_client_slot));
|
||||||
trade_iterator = client_trade.erase(trade_iterator);
|
trade_iterator = client_trade.erase(trade_iterator);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -4443,31 +4485,49 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
|
|
||||||
// out-going return checks for client
|
// out-going return checks for client
|
||||||
for (auto& return_iterator : client_return) {
|
for (auto& return_iterator : client_return) {
|
||||||
auto return_instance = return_iterator.returnItemInstance;
|
auto return_instance = return_iterator.return_item_instance;
|
||||||
if (!return_instance)
|
if (!return_instance) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!return_instance->GetItem()) {
|
if (!return_instance->GetItem()) {
|
||||||
// TODO: add logging
|
LogError("Bot::PerformTradeWithClient error processing bot slot {} for {} in trade with {}.", return_iterator.from_bot_slot, GetCleanName(), client->GetCleanName());
|
||||||
client->Message(Chat::Red, "A server error was encountered while processing bot slot %i - Trade Canceled.", return_iterator.fromBotSlot);
|
client->Message(
|
||||||
|
Chat::Red,
|
||||||
|
fmt::format(
|
||||||
|
"A server error was encountered while processing bot slot {}, the trade has been cancelled.",
|
||||||
|
return_iterator.from_bot_slot
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EQ::SayLinkEngine linker;
|
||||||
|
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||||
|
linker.SetItemInst(return_instance);
|
||||||
|
|
||||||
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
// non-failing checks above are causing this to trigger (i.e., !ItemClassCommon and !IsEquipable{race, class, min_level})
|
// non-failing checks above are causing this to trigger (i.e., !ItemClassCommon and !IsEquipable{race, class, min_level})
|
||||||
// this process is hindered by not having bots use the inventory trade method (TODO: implement bot inventory use)
|
// this process is hindered by not having bots use the inventory trade method (TODO: implement bot inventory use)
|
||||||
if (client->CheckLoreConflict(return_instance->GetItem())) {
|
if (client->CheckLoreConflict(return_instance->GetItem())) {
|
||||||
client->Message(Chat::Yellow, "You already have lore equipment matching the item '%s' - Trade Canceled!", return_instance->GetItem()->Name);
|
client->Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"You already have {}, the trade has been cancelled!",
|
||||||
|
item_link
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_iterator.fromBotSlot == invslot::slotCursor) {
|
if (return_iterator.from_bot_slot == invslot::slotCursor) {
|
||||||
return_iterator.toClientSlot = invslot::slotCursor;
|
return_iterator.to_client_slot = invslot::slotCursor;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int16 client_search_general = invslot::GENERAL_BEGIN;
|
int16 client_search_general = invslot::GENERAL_BEGIN;
|
||||||
uint8 client_search_bag = invbag::SLOT_BEGIN;
|
uint8 client_search_bag = invbag::SLOT_BEGIN;
|
||||||
|
|
||||||
bool run_search = true;
|
bool run_search = true;
|
||||||
while (run_search) {
|
while (run_search) {
|
||||||
int16 client_test_slot = client->GetInv().FindFreeSlotForTradeItem(return_instance, client_search_general, client_search_bag);
|
int16 client_test_slot = client->GetInv().FindFreeSlotForTradeItem(return_instance, client_search_general, client_search_bag);
|
||||||
@ -4478,23 +4538,23 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
|
|
||||||
bool slot_taken = false;
|
bool slot_taken = false;
|
||||||
for (const auto& check_iterator : client_return) {
|
for (const auto& check_iterator : client_return) {
|
||||||
if (check_iterator.fromBotSlot == return_iterator.fromBotSlot)
|
if (check_iterator.from_bot_slot == return_iterator.from_bot_slot) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ((check_iterator.toClientSlot == client_test_slot) && (client_test_slot != invslot::slotCursor)) {
|
if (check_iterator.to_client_slot == client_test_slot && client_test_slot != invslot::slotCursor) {
|
||||||
slot_taken = true;
|
slot_taken = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot_taken) {
|
if (slot_taken) {
|
||||||
if ((client_test_slot >= invslot::GENERAL_BEGIN) && (client_test_slot <= invslot::GENERAL_END)) {
|
if (client_test_slot >= invslot::GENERAL_BEGIN && client_test_slot <= invslot::GENERAL_END) {
|
||||||
++client_search_general;
|
++client_search_general;
|
||||||
client_search_bag = invbag::SLOT_BEGIN;
|
client_search_bag = invbag::SLOT_BEGIN;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
client_search_general = InventoryProfile::CalcSlotId(client_test_slot);
|
client_search_general = InventoryProfile::CalcSlotId(client_test_slot);
|
||||||
client_search_bag = InventoryProfile::CalcBagIdx(client_test_slot);
|
client_search_bag = InventoryProfile::CalcBagIdx(client_test_slot);
|
||||||
|
|
||||||
++client_search_bag;
|
++client_search_bag;
|
||||||
if (client_search_bag >= invbag::SLOT_COUNT) {
|
if (client_search_bag >= invbag::SLOT_COUNT) {
|
||||||
// incrementing this past legacy::GENERAL_END triggers the (client_test_slot == legacy::SLOT_INVALID) at the beginning of the search loop
|
// incrementing this past legacy::GENERAL_END triggers the (client_test_slot == legacy::SLOT_INVALID) at the beginning of the search loop
|
||||||
@ -4507,13 +4567,13 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return_iterator.toClientSlot = client_test_slot;
|
return_iterator.to_client_slot = client_test_slot;
|
||||||
run_search = false;
|
run_search = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_iterator.toClientSlot == invslot::SLOT_INVALID) {
|
if (return_iterator.to_client_slot == invslot::SLOT_INVALID) {
|
||||||
client->Message(Chat::Yellow, "You do not have room to complete this trade - Trade Canceled!");
|
client->Message(Chat::Yellow, "You do not have room to complete this trade, the trade has been cancelled!");
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4524,70 +4584,105 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
for (auto& return_iterator : client_return) {
|
for (auto& return_iterator : client_return) {
|
||||||
// TODO: code for stackables
|
// TODO: code for stackables
|
||||||
|
|
||||||
if (return_iterator.fromBotSlot == invslot::slotCursor) { // failed trade return
|
if (return_iterator.from_bot_slot == invslot::slotCursor) { // failed trade return
|
||||||
// no movement action required
|
// no movement action required
|
||||||
}
|
} else if ((return_iterator.from_bot_slot >= invslot::TRADE_BEGIN) && (return_iterator.from_bot_slot <= invslot::TRADE_END)) { // failed trade returns
|
||||||
else if ((return_iterator.fromBotSlot >= invslot::TRADE_BEGIN) && (return_iterator.fromBotSlot <= invslot::TRADE_END)) { // failed trade returns
|
client->PutItemInInventory(return_iterator.to_client_slot, *return_iterator.return_item_instance);
|
||||||
client->PutItemInInventory(return_iterator.toClientSlot, *return_iterator.returnItemInstance);
|
client->SendItemPacket(return_iterator.to_client_slot, return_iterator.return_item_instance, ItemPacketTrade);
|
||||||
client->SendItemPacket(return_iterator.toClientSlot, return_iterator.returnItemInstance, ItemPacketTrade);
|
client->DeleteItemInInventory(return_iterator.from_bot_slot);
|
||||||
client->DeleteItemInInventory(return_iterator.fromBotSlot);
|
} else { // successful trade returns
|
||||||
}
|
auto return_instance = m_inv.PopItem(return_iterator.from_bot_slot);
|
||||||
else { // successful trade returns
|
//if (*return_instance != *return_iterator.return_item_instance) {
|
||||||
auto return_instance = m_inv.PopItem(return_iterator.fromBotSlot);
|
|
||||||
//if (*return_instance != *return_iterator.returnItemInstance) {
|
|
||||||
// // TODO: add logging
|
// // TODO: add logging
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (!database.botdb.DeleteItemBySlot(GetBotID(), return_iterator.fromBotSlot))
|
if (!database.botdb.DeleteItemBySlot(GetBotID(), return_iterator.from_bot_slot)) {
|
||||||
client->Message(Chat::Red, "%s (slot: %i, name: '%s')", BotDatabase::fail::DeleteItemBySlot(), return_iterator.fromBotSlot, (return_instance ? return_instance->GetItem()->Name : "nullptr"));
|
client->Message(
|
||||||
|
Chat::Red,
|
||||||
|
fmt::format(
|
||||||
|
"Failed to delete item by slot from slot {} for {}.",
|
||||||
|
return_iterator.from_bot_slot,
|
||||||
|
GetCleanName()
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BotRemoveEquipItem(return_iterator.from_bot_slot);
|
||||||
|
|
||||||
|
if (return_instance) {
|
||||||
|
EQ::SayLinkEngine linker;
|
||||||
|
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||||
|
linker.SetItemInst(return_instance);
|
||||||
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
|
client->Message(
|
||||||
|
Chat::Tell,
|
||||||
|
fmt::format(
|
||||||
|
"{} tells you, 'I have returned {}.'",
|
||||||
|
GetCleanName(),
|
||||||
|
item_link
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
client->PutItemInInventory(return_iterator.to_client_slot, *return_instance, true);
|
||||||
|
}
|
||||||
|
|
||||||
BotRemoveEquipItem(return_iterator.fromBotSlot);
|
|
||||||
if (return_instance)
|
|
||||||
client->PutItemInInventory(return_iterator.toClientSlot, *return_instance, true);
|
|
||||||
InventoryProfile::MarkDirty(return_instance);
|
InventoryProfile::MarkDirty(return_instance);
|
||||||
}
|
}
|
||||||
return_iterator.returnItemInstance = nullptr;
|
return_iterator.return_item_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trades can now go in as empty slot inserts
|
// trades can now go in as empty slot inserts
|
||||||
for (auto& trade_iterator : client_trade) {
|
for (auto& trade_iterator : client_trade) {
|
||||||
// TODO: code for stackables
|
// TODO: code for stackables
|
||||||
|
|
||||||
if (!database.botdb.SaveItemBySlot(this, trade_iterator.toBotSlot, trade_iterator.tradeItemInstance))
|
if (!database.botdb.SaveItemBySlot(this, trade_iterator.to_bot_slot, trade_iterator.trade_item_instance)) {
|
||||||
client->Message(Chat::Red, "%s (slot: %i, name: '%s')", BotDatabase::fail::SaveItemBySlot(), trade_iterator.toBotSlot, (trade_iterator.tradeItemInstance ? trade_iterator.tradeItemInstance->GetItem()->Name : "nullptr"));
|
client->Message(
|
||||||
|
Chat::Red,
|
||||||
|
fmt::format(
|
||||||
|
"Failed to save item by slot to slot {} for {}.",
|
||||||
|
trade_iterator.to_bot_slot,
|
||||||
|
GetCleanName()
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
m_inv.PutItem(trade_iterator.toBotSlot, *trade_iterator.tradeItemInstance);
|
EQ::SayLinkEngine linker;
|
||||||
BotAddEquipItem(trade_iterator.toBotSlot, (trade_iterator.tradeItemInstance ? trade_iterator.tradeItemInstance->GetID() : 0));
|
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||||
trade_iterator.tradeItemInstance = nullptr; // actual deletion occurs in client delete below
|
linker.SetItemInst(trade_iterator.trade_item_instance);
|
||||||
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
client->DeleteItemInInventory(trade_iterator.fromClientSlot, 0, (trade_iterator.fromClientSlot == EQ::invslot::slotCursor));
|
client->Message(
|
||||||
|
Chat::Tell,
|
||||||
|
fmt::format(
|
||||||
|
"{} tells you, 'I have accepted {}.'",
|
||||||
|
GetCleanName(),
|
||||||
|
item_link
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
m_inv.PutItem(trade_iterator.to_bot_slot, *trade_iterator.trade_item_instance);
|
||||||
|
BotAddEquipItem(trade_iterator.to_bot_slot, (trade_iterator.trade_item_instance ? trade_iterator.trade_item_instance->GetID() : 0));
|
||||||
|
trade_iterator.trade_item_instance = nullptr; // actual deletion occurs in client delete below
|
||||||
|
|
||||||
|
client->DeleteItemInInventory(trade_iterator.from_client_slot, 0, (trade_iterator.from_client_slot == EQ::invslot::slotCursor));
|
||||||
|
|
||||||
// database currently has unattuned item saved in inventory..it will be attuned on next bot load
|
// database currently has unattuned item saved in inventory..it will be attuned on next bot load
|
||||||
// this prevents unattuned item returns in the mean time (TODO: re-work process)
|
// this prevents unattuned item returns in the mean time (TODO: re-work process)
|
||||||
if (trade_iterator.toBotSlot >= invslot::EQUIPMENT_BEGIN && trade_iterator.toBotSlot <= invslot::EQUIPMENT_END) {
|
if (trade_iterator.to_bot_slot >= invslot::EQUIPMENT_BEGIN && trade_iterator.to_bot_slot <= invslot::EQUIPMENT_END) {
|
||||||
auto attune_item = m_inv.GetItem(trade_iterator.toBotSlot);
|
auto attune_item = m_inv.GetItem(trade_iterator.to_bot_slot);
|
||||||
if (attune_item && attune_item->GetItem()->Attuneable)
|
if (attune_item && attune_item->GetItem()->Attuneable) {
|
||||||
attune_item->SetAttuned(true);
|
attune_item->SetAttuned(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trade messages
|
|
||||||
for (const auto& return_iterator : client_return) {
|
|
||||||
if (return_iterator.failedItemName.size())
|
|
||||||
client->Message(Chat::Tell, "%s tells you, \"%s, I can't use this '%s.'\"", GetCleanName(), client->GetName(), return_iterator.failedItemName.c_str());
|
|
||||||
}
|
|
||||||
for (const auto& trade_iterator : client_trade) {
|
|
||||||
if (trade_iterator.acceptedItemName.size())
|
|
||||||
client->Message(Chat::Tell, "%s tells you, \"Thank you for the '%s,' %s!\"", GetCleanName(), trade_iterator.acceptedItemName.c_str(), client->GetName());
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t accepted_count = client_trade.size();
|
size_t accepted_count = client_trade.size();
|
||||||
size_t returned_count = client_return.size();
|
size_t returned_count = client_return.size();
|
||||||
|
|
||||||
client->Message(Chat::Lime, "Trade with '%s' resulted in %i accepted item%s, %i returned item%s.", GetCleanName(), accepted_count, ((accepted_count == 1) ? "" : "s"), returned_count, ((returned_count == 1) ? "" : "s"));
|
if (accepted_count) {
|
||||||
|
|
||||||
if (accepted_count)
|
|
||||||
CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
|
CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) {
|
bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) {
|
||||||
|
|||||||
@ -602,7 +602,7 @@ protected:
|
|||||||
virtual int32 GetBotFocusEffect(focusType bottype, uint16 spell_id, bool from_buff_tic = false);
|
virtual int32 GetBotFocusEffect(focusType bottype, uint16 spell_id, bool from_buff_tic = false);
|
||||||
virtual int32 CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false);
|
virtual int32 CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false);
|
||||||
virtual int32 CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id);
|
virtual int32 CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id);
|
||||||
virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client);
|
virtual void PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client* client);
|
||||||
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||||
|
|
||||||
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
|
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user