mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 16:41:29 +00:00
Fixed a few glitches related to bot trading and other affected code
This commit is contained in:
parent
09bbfbcc31
commit
999650d368
@ -1,5 +1,12 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 03/09/2017 ==
|
||||||
|
Uleat: Fixed a few glitches related to bot trading and other affected code
|
||||||
|
- Added a temporary fail clause for partial stack transfers to prevent client item overwrites
|
||||||
|
- Return messages no longer repeat the top cursor item when multiple items are pushed there
|
||||||
|
- Test slot for client returns is now handled appropriately for parent and bag searches
|
||||||
|
- FindFreeSlotForTradeItem() now begins at the correct bag index on subsequent parent iterations
|
||||||
|
|
||||||
== 03/08/2017 ==
|
== 03/08/2017 ==
|
||||||
Uleat: Complete rework of the bot trading system
|
Uleat: Complete rework of the bot trading system
|
||||||
- Equipment slot priority can now be tailored..though, a recompile will be required
|
- Equipment slot priority can now be tailored..though, a recompile will be required
|
||||||
|
|||||||
@ -635,7 +635,7 @@ int16 EQEmu::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function...
|
// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function...
|
||||||
int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start, int16 bag_start) {
|
int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start, uint8 bag_start) {
|
||||||
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
|
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
|
||||||
// If you have a need, use it..but, understand it is not a suitable replacement for InventoryProfile::FindFreeSlot().
|
// If you have a need, use it..but, understand it is not a suitable replacement for InventoryProfile::FindFreeSlot().
|
||||||
//
|
//
|
||||||
@ -643,7 +643,7 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
|||||||
|
|
||||||
if ((general_start < legacy::GENERAL_BEGIN) || (general_start > legacy::GENERAL_END))
|
if ((general_start < legacy::GENERAL_BEGIN) || (general_start > legacy::GENERAL_END))
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
if ((bag_start < inventory::containerBegin) || (bag_start >= inventory::ContainerCount))
|
if (bag_start >= inventory::ContainerCount)
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
|
|
||||||
if (!inst || !inst->GetID())
|
if (!inst || !inst->GetID())
|
||||||
@ -678,7 +678,8 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (main_inst->IsClassBag()) { // if item-specific containers already have bad items, we won't fix it here...
|
if (main_inst->IsClassBag()) { // if item-specific containers already have bad items, we won't fix it here...
|
||||||
for (uint8 free_bag_slot = bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
|
||||||
|
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
||||||
const ItemInstance* sub_inst = main_inst->GetItem(free_bag_slot);
|
const ItemInstance* sub_inst = main_inst->GetItem(free_bag_slot);
|
||||||
|
|
||||||
if (!sub_inst)
|
if (!sub_inst)
|
||||||
@ -699,7 +700,8 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
|||||||
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeQuiver) || !main_inst->IsClassBag())
|
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeQuiver) || !main_inst->IsClassBag())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 free_bag_slot = bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
|
||||||
|
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
||||||
if (!main_inst->GetItem(free_bag_slot))
|
if (!main_inst->GetItem(free_bag_slot))
|
||||||
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
||||||
}
|
}
|
||||||
@ -714,7 +716,8 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
|||||||
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeBandolier) || !main_inst->IsClassBag())
|
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeBandolier) || !main_inst->IsClassBag())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 free_bag_slot = bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
|
||||||
|
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
||||||
if (!main_inst->GetItem(free_bag_slot))
|
if (!main_inst->GetItem(free_bag_slot))
|
||||||
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
||||||
}
|
}
|
||||||
@ -736,7 +739,8 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
|||||||
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == item::BagTypeBandolier) || (main_inst->GetItem()->BagType == item::BagTypeQuiver))
|
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == item::BagTypeBandolier) || (main_inst->GetItem()->BagType == item::BagTypeQuiver))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 free_bag_slot = bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
|
||||||
|
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
|
||||||
if (!main_inst->GetItem(free_bag_slot))
|
if (!main_inst->GetItem(free_bag_slot))
|
||||||
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -155,7 +155,7 @@ namespace EQEmu
|
|||||||
|
|
||||||
// Locate an available inventory slot
|
// Locate an available inventory slot
|
||||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
||||||
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = legacy::GENERAL_BEGIN, int16 bag_start = inventory::containerBegin);
|
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = legacy::GENERAL_BEGIN, uint8 bag_start = inventory::containerBegin);
|
||||||
|
|
||||||
// Calculate slot_id for an item within a bag
|
// Calculate slot_id for an item within a bag
|
||||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
||||||
|
|||||||
63
zone/bot.cpp
63
zone/bot.cpp
@ -3359,8 +3359,9 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
int16 fromClientSlot;
|
int16 fromClientSlot;
|
||||||
int16 toBotSlot;
|
int16 toBotSlot;
|
||||||
int adjustStackSize;
|
int adjustStackSize;
|
||||||
|
std::string acceptedItemName;
|
||||||
|
|
||||||
ClientTrade(const ItemInstance* item, int16 from) : tradeItemInstance(item), fromClientSlot(from), toBotSlot(legacy::SLOT_INVALID), adjustStackSize(0) { }
|
ClientTrade(const ItemInstance* item, int16 from, const char* name = "") : tradeItemInstance(item), fromClientSlot(from), toBotSlot(legacy::SLOT_INVALID), adjustStackSize(0), acceptedItemName(name) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClientReturn {
|
struct ClientReturn {
|
||||||
@ -3368,8 +3369,9 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
int16 fromBotSlot;
|
int16 fromBotSlot;
|
||||||
int16 toClientSlot;
|
int16 toClientSlot;
|
||||||
int adjustStackSize;
|
int adjustStackSize;
|
||||||
|
std::string failedItemName;
|
||||||
|
|
||||||
ClientReturn(const ItemInstance* item, int16 from) : returnItemInstance(item), fromBotSlot(from), toClientSlot(legacy::SLOT_INVALID), adjustStackSize(0) { }
|
ClientReturn(const ItemInstance* item, int16 from, const char* name = "") : returnItemInstance(item), fromBotSlot(from), toClientSlot(legacy::SLOT_INVALID), adjustStackSize(0), failedItemName(name) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int16 proxyPowerSource = 22;
|
static const int16 proxyPowerSource = 22;
|
||||||
@ -3442,6 +3444,11 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (trade_instance->IsStackable() && (trade_instance->GetCharges() < trade_instance->GetItem()->StackSize)) { // temp until partial stacks are implemented
|
||||||
|
client->Message(CC_Yellow, "'%s' is only a partially stacked item - Trade Canceled!", trade_instance->GetItem()->Name);
|
||||||
|
client->ResetTrade();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (CheckLoreConflict(trade_instance->GetItem())) {
|
if (CheckLoreConflict(trade_instance->GetItem())) {
|
||||||
client->Message(CC_Yellow, "This bot already has lore equipment matching the item '%s' - Trade Canceled!", trade_instance->GetItem()->Name);
|
client->Message(CC_Yellow, "This bot already has lore equipment matching the item '%s' - Trade Canceled!", trade_instance->GetItem()->Name);
|
||||||
client->ResetTrade();
|
client->ResetTrade();
|
||||||
@ -3449,15 +3456,15 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!trade_instance->IsType(item::ItemClassCommon)) {
|
if (!trade_instance->IsType(item::ItemClassCommon)) {
|
||||||
client_return.push_back(ClientReturn(trade_instance, trade_index));
|
client_return.push_back(ClientReturn(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!trade_instance->IsEquipable(GetBaseRace(), GetClass()) || (GetLevel() < trade_instance->GetItem()->ReqLevel)) {
|
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));
|
client_return.push_back(ClientReturn(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_trade.push_back(ClientTrade(trade_instance, trade_index));
|
client_trade.push_back(ClientTrade(trade_instance, trade_index, trade_instance->GetItem()->Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for incoming lore hacks
|
// check for incoming lore hacks
|
||||||
@ -3576,7 +3583,7 @@ 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 == legacy::SLOT_INVALID) {
|
if (trade_iterator->toBotSlot == legacy::SLOT_INVALID) {
|
||||||
client_return.push_back(ClientReturn(trade_iterator->tradeItemInstance, trade_iterator->fromClientSlot));
|
client_return.push_back(ClientReturn(trade_iterator->tradeItemInstance, trade_iterator->fromClientSlot, trade_iterator->tradeItemInstance->GetItem()->Name));
|
||||||
trade_iterator = client_trade.erase(trade_iterator);
|
trade_iterator = client_trade.erase(trade_iterator);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -3606,7 +3613,7 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int16 client_search_general = legacy::GENERAL_BEGIN;
|
int16 client_search_general = legacy::GENERAL_BEGIN;
|
||||||
int16 client_search_bag = inventory::containerBegin;
|
uint8 client_search_bag = inventory::containerBegin;
|
||||||
|
|
||||||
bool run_search = true;
|
bool run_search = true;
|
||||||
while (run_search) {
|
while (run_search) {
|
||||||
@ -3627,16 +3634,23 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (slot_taken) {
|
if (slot_taken) {
|
||||||
client_search_general = InventoryProfile::CalcSlotId(client_test_slot);
|
if ((client_test_slot >= legacy::GENERAL_BEGIN) && (client_test_slot <= legacy::GENERAL_END)) {
|
||||||
client_search_bag = InventoryProfile::CalcBagIdx(client_test_slot);
|
|
||||||
|
|
||||||
++client_search_bag;
|
|
||||||
if (client_search_bag >= inventory::ContainerCount) {
|
|
||||||
client_search_bag = inventory::containerBegin;
|
|
||||||
// incrementing this past legacy::GENERAL_END triggers the (client_test_slot == legacy::SLOT_INVALID) at the beginning of the search loop
|
|
||||||
// ideally, this will never occur because we always start fresh with each loop iteration and should receive SLOT_CURSOR as a return value
|
|
||||||
++client_search_general;
|
++client_search_general;
|
||||||
|
client_search_bag = inventory::containerBegin;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
client_search_general = InventoryProfile::CalcSlotId(client_test_slot);
|
||||||
|
client_search_bag = InventoryProfile::CalcBagIdx(client_test_slot);
|
||||||
|
|
||||||
|
++client_search_bag;
|
||||||
|
if (client_search_bag >= inventory::ContainerCount) {
|
||||||
|
// incrementing this past legacy::GENERAL_END triggers the (client_test_slot == legacy::SLOT_INVALID) at the beginning of the search loop
|
||||||
|
// ideally, this will never occur because we always start fresh with each loop iteration and should receive SLOT_CURSOR as a return value
|
||||||
|
++client_search_general;
|
||||||
|
client_search_bag = inventory::containerBegin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3694,17 +3708,14 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
|||||||
trade_iterator.tradeItemInstance = nullptr;
|
trade_iterator.tradeItemInstance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trade announcements
|
// trade messages
|
||||||
for (const auto& return_iterator : client_return) { // item pointers should be nulled by this point
|
for (const auto& return_iterator : client_return) {
|
||||||
if (((return_iterator.fromBotSlot < legacy::TRADE_BEGIN) || (return_iterator.fromBotSlot > legacy::TRADE_END)) && (return_iterator.fromBotSlot != inventory::slotCursor))
|
if (return_iterator.failedItemName.size())
|
||||||
continue;
|
client->Message(MT_Tell, "%s tells you, \"%s, I can't use this '%s.'\"", GetCleanName(), client->GetName(), return_iterator.failedItemName.c_str());
|
||||||
|
|
||||||
if (client->GetInv()[return_iterator.toClientSlot])
|
|
||||||
client->Message(MT_Tell, "%s tells you, \"%s, I can't use this '%s.'\"", GetCleanName(), client->GetName(), client->GetInv()[return_iterator.toClientSlot]->GetItem()->Name);
|
|
||||||
}
|
}
|
||||||
for (const auto& trade_iterator : client_trade) { // item pointers should be nulled by this point
|
for (const auto& trade_iterator : client_trade) {
|
||||||
if (m_inv[trade_iterator.toBotSlot])
|
if (trade_iterator.acceptedItemName.size())
|
||||||
client->Message(MT_Tell, "%s tells you, \"Thank you for the '%s,' %s!\"", GetCleanName(), m_inv[trade_iterator.toBotSlot]->GetItem()->Name, client->GetName());
|
client->Message(MT_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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user