Skip to content

Commit

Permalink
Core/Players: Improve trade exchange calculations (#24435)
Browse files Browse the repository at this point in the history
* Add some comments to Player::CanStoreItems to help me wrap my head around how the method works.

* Experimental fix for incoming trade-stack problem.

* Only add to stacks that aren't already full.

* Use remaining_count instead of static 1.

* Remove debug logging from exploration.

* More uses of remaining_count for consistency.

* Correct space count check

* Correct overflow problem.

* Remove redundant check, handled in existing for statement.

* Store Item pointers in order to be able to merge in multiple incoming stacks.

* Build fix - was continually working locally, but failing in CI.

* Break build in order to keep PR focused on Player.cpp changes.

* Adjust phrasing of how arrays are initialized.

* Fix phrasing of comments to avoid sounding like a ToDo item

* In the spirit of b649273, rephrase an old comment to be a statement rather than a question.
  • Loading branch information
adeutscher committed Apr 16, 2020
1 parent 4bf5bec commit e11a13c
Showing 1 changed file with 98 additions and 40 deletions.
138 changes: 98 additions & 40 deletions src/server/game/Entities/Player/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10976,58 +10976,81 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
Item* item2;

// fill space table
uint32 inventoryCounts[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START];
uint32 bagCounts[INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE];
uint32 keyringCounts[KEYRING_SLOT_END - KEYRING_SLOT_START];
uint32 currencyCounts[CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START];
// fill space tables, creating a mock-up of the player's inventory

memset(inventoryCounts, 0, sizeof(uint32) * (INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START));
memset(bagCounts, 0, sizeof(uint32) * (INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START) * MAX_BAG_SIZE);
memset(keyringCounts, 0, sizeof(uint32) * (KEYRING_SLOT_END - KEYRING_SLOT_START));
memset(currencyCounts, 0, sizeof(uint32) * (CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START));
// counts
uint32 inventoryCounts[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START] = {};
uint32 bagCounts[INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE] = {};
uint32 keyringCounts[KEYRING_SLOT_END - KEYRING_SLOT_START] = {};
uint32 currencyCounts[CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START] = {};

// Item pointers
Item* inventoryPointers[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START] = {};
Item* bagPointers[INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE] = {};
Item* keyringPointers[KEYRING_SLOT_END - KEYRING_SLOT_START] = {};
Item* currencyPointers[CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START] = {};

// filling inventory
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
// build items in stock backpack
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (item2 && !item2->IsInTrade())
{
inventoryCounts[i - INVENTORY_SLOT_ITEM_START] = item2->GetCount();
inventoryPointers[i - INVENTORY_SLOT_ITEM_START] = item2;
}
}

for (uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
{
// build items in key ring 'bag'
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (item2 && !item2->IsInTrade())
{
keyringCounts[i - KEYRING_SLOT_START] = item2->GetCount();
keyringPointers[i - KEYRING_SLOT_START] = item2;
}
}

for (uint8 i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++)
{
// build items in currency 'bag'
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (item2 && !item2->IsInTrade())
{
currencyCounts[i - CURRENCYTOKEN_SLOT_START] = item2->GetCount();
currencyPointers[i - CURRENCYTOKEN_SLOT_START] = item2;
}
}

for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
if (Bag* pBag = GetBagByPos(i))
for (uint32 j = 0; j < pBag->GetBagSize(); j++)
{
// build item counts in equippable bags
item2 = GetItemByPos(i, j);
if (item2 && !item2->IsInTrade())
{
bagCounts[i - INVENTORY_SLOT_BAG_START][j] = item2->GetCount();
bagPointers[i - INVENTORY_SLOT_BAG_START][j] = item2;
}
}

// check free space for all items
// check free space for all items that we wish to add
for (int k = 0; k < count; ++k)
{
// Incoming item
Item* item = items[k];

// no item
if (!item)
continue;

uint32_t remaining_count = item->GetCount();

TC_LOG_DEBUG("entities.player.items", "Player::CanStoreItems: Player '%s' (%s), Index: %i ItemID: %u, Count: %u",
GetName().c_str(), GetGUID().ToString().c_str(), k + 1, item->GetEntry(), item->GetCount());
GetName().c_str(), GetGUID().ToString().c_str(), k + 1, item->GetEntry(), remaining_count);
ItemTemplate const* pProto = item->GetTemplate();

// strange item
Expand Down Expand Up @@ -11056,62 +11079,85 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit

for (uint8 t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; ++t)
{
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && keyringCounts[t-KEYRING_SLOT_START] + item->GetCount() <= pProto->GetMaxStackSize())
item2 = keyringPointers[t-KEYRING_SLOT_START];
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && keyringCounts[t-KEYRING_SLOT_START] < pProto->GetMaxStackSize())
{
keyringCounts[t-KEYRING_SLOT_START] += item->GetCount();
b_found = true;
break;
keyringCounts[t-KEYRING_SLOT_START] += remaining_count;
remaining_count = keyringCounts[t-KEYRING_SLOT_START] < pProto->GetMaxStackSize() ? 0 : keyringCounts[t-KEYRING_SLOT_START] - pProto->GetMaxStackSize();

b_found = remaining_count == 0;

// if no pieces of the stack remain, then stop checking keyring
if (b_found)
break;
}
}

if (b_found)
continue;

for (int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t)
{
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && currencyCounts[t-CURRENCYTOKEN_SLOT_START] + item->GetCount() <= pProto->GetMaxStackSize())
item2 = currencyPointers[t-CURRENCYTOKEN_SLOT_START];
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && currencyCounts[t-CURRENCYTOKEN_SLOT_START] < pProto->GetMaxStackSize())
{
currencyCounts[t-CURRENCYTOKEN_SLOT_START] += item->GetCount();
b_found = true;
break;
currencyCounts[t-CURRENCYTOKEN_SLOT_START] += remaining_count;
remaining_count = currencyCounts[t-CURRENCYTOKEN_SLOT_START] < pProto->GetMaxStackSize() ? 0 : currencyCounts[t-CURRENCYTOKEN_SLOT_START] - pProto->GetMaxStackSize();

b_found = remaining_count == 0;
// if no pieces of the stack remain, then stop checking currency 'bag'
if (b_found)
break;
}
}

if (b_found)
continue;

for (int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; ++t)
{
item2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inventoryCounts[t-INVENTORY_SLOT_ITEM_START] + item->GetCount() <= pProto->GetMaxStackSize())
item2 = inventoryPointers[t-INVENTORY_SLOT_ITEM_START];
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inventoryCounts[t-INVENTORY_SLOT_ITEM_START] < pProto->GetMaxStackSize())
{
inventoryCounts[t-INVENTORY_SLOT_ITEM_START] += item->GetCount();
b_found = true;
break;
inventoryCounts[t-INVENTORY_SLOT_ITEM_START] += remaining_count;
remaining_count = inventoryCounts[t-INVENTORY_SLOT_ITEM_START] < pProto->GetMaxStackSize() ? 0 : inventoryCounts[t-INVENTORY_SLOT_ITEM_START] - pProto->GetMaxStackSize();

b_found = remaining_count == 0;
// if no pieces of the stack remain, then stop checking stock bag
if (b_found)
break;
}
}

if (b_found)
continue;

for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
{
if (Bag* bag = GetBagByPos(t))
{
if (ItemCanGoIntoBag(item->GetTemplate(), bag->GetTemplate()))
if (!ItemCanGoIntoBag(item->GetTemplate(), bag->GetTemplate()))
continue;

for (uint32 j = 0; j < bag->GetBagSize(); j++)
{
for (uint32 j = 0; j < bag->GetBagSize(); j++)
item2 = bagPointers[t-INVENTORY_SLOT_BAG_START][j];
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && bagCounts[t-INVENTORY_SLOT_BAG_START][j] < pProto->GetMaxStackSize())
{
item2 = GetItemByPos(t, j);
if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && bagCounts[t-INVENTORY_SLOT_BAG_START][j] + item->GetCount() <= pProto->GetMaxStackSize())
{
bagCounts[t-INVENTORY_SLOT_BAG_START][j] += item->GetCount();
b_found = true;
// add count to stack so that later items in the list do not double-book
bagCounts[t-INVENTORY_SLOT_BAG_START][j] += remaining_count;
remaining_count = bagCounts[t-INVENTORY_SLOT_BAG_START][j] < pProto->GetMaxStackSize() ? 0 : bagCounts[t-INVENTORY_SLOT_BAG_START][j] - pProto->GetMaxStackSize();

b_found = remaining_count == 0;

// if no pieces of the stack remain, then stop checking equippable bags
if (b_found)
break;
}
}
}
}
}

if (b_found)
continue;
}
Expand All @@ -11127,7 +11173,9 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
if (keyringCounts[t-KEYRING_SLOT_START] == 0)
{
keyringCounts[t-KEYRING_SLOT_START] = 1;
keyringCounts[t-KEYRING_SLOT_START] = remaining_count;
keyringPointers[t-KEYRING_SLOT_START] = item;

b_found = true;
break;
}
Expand All @@ -11143,7 +11191,9 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
if (currencyCounts[t-CURRENCYTOKEN_SLOT_START] == 0)
{
currencyCounts[t-CURRENCYTOKEN_SLOT_START] = 1;
currencyCounts[t-CURRENCYTOKEN_SLOT_START] = remaining_count;
currencyPointers [t-CURRENCYTOKEN_SLOT_START] = item;

b_found = true;
break;
}
Expand All @@ -11167,14 +11217,17 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
if (bagCounts[t-INVENTORY_SLOT_BAG_START][j] == 0)
{
bagCounts[t-INVENTORY_SLOT_BAG_START][j] = 1;
bagCounts[t-INVENTORY_SLOT_BAG_START][j] = remaining_count;
bagPointers[t-INVENTORY_SLOT_BAG_START][j] = item;

b_found = true;
break;
}
}
}
}
}

if (b_found)
continue;
}
Expand All @@ -11185,11 +11238,14 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
if (inventoryCounts[t-INVENTORY_SLOT_ITEM_START] == 0)
{
inventoryCounts[t-INVENTORY_SLOT_ITEM_START] = 1;
inventoryCounts[t-INVENTORY_SLOT_ITEM_START] = remaining_count;
inventoryPointers[t-INVENTORY_SLOT_ITEM_START] = item;

b_found = true;
break;
}
}

if (b_found)
continue;

Expand All @@ -11208,15 +11264,17 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
{
if (bagCounts[t-INVENTORY_SLOT_BAG_START][j] == 0)
{
bagCounts[t-INVENTORY_SLOT_BAG_START][j] = 1;
bagCounts[t-INVENTORY_SLOT_BAG_START][j] = remaining_count;
bagPointers[t-INVENTORY_SLOT_BAG_START][j] = item;

b_found = true;
break;
}
}
}
}

// no free slot found?
// if no free slot found for all pieces of the item, then return an error
if (!b_found)
return EQUIP_ERR_BAG_FULL;
}
Expand Down

1 comment on commit e11a13c

@msoky
Copy link
Contributor

@msoky msoky commented on e11a13c Apr 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

close? #24434

Please sign in to comment.