private bool BackpackStashAttempt(CacheACDItem item, out int[] XY)
{
XY = new[] { -1, -1 };
int iPlayerDynamicID = ZetaDia.Me.CommonData.DynamicId;
int iOriginalGameBalanceId = item.ThisBalanceID;
int iOriginalDynamicID = item.ThisDynamicID;
int iOriginalStackQuantity = (int)item.ThisItemStackQuantity;
string sOriginalItemName = item.ThisRealName;
string sOriginalInternalName = item.ThisInternalName;
PluginItemTypes OriginalPluginItemType = ItemFunc.DetermineItemType(item);
PluginBaseItemTypes thisGilesBaseType = ItemFunc.DetermineBaseType(OriginalPluginItemType);
bool bOriginalTwoSlot = item.IsTwoSlot;
bool bOriginalIsStackable = item.IsStackableItem;
int iAttempts;
if (_dictItemStashAttempted.TryGetValue(iOriginalDynamicID, out iAttempts))
{
Logger.DBLog.InfoFormat("GSError: Detected a duplicate stash attempt, DB item mis-read error, now forcing this item as a 2-slot item");
_dictItemStashAttempted[iOriginalDynamicID] = iAttempts + 1;
bOriginalTwoSlot = true;
bOriginalIsStackable = false;
if (iAttempts > 6)
{
Logger.DBLog.InfoFormat("GSError: Detected an item stash loop risk, now re-mapping stash treating everything as 2-slot and re-attempting");
// Array for what blocks are or are not blocked
for (int iRow = 0; iRow <= 5; iRow++)
for (int iColumn = 0; iColumn <= 9; iColumn++)
BackpackSlotBlocked[iColumn, iRow] = false;
// Block off the entire of any "protected stash pages"
foreach (InventorySquare iProtPage in CharacterSettings.Instance.ProtectedBagSlots)
BackpackSlotBlocked[iProtPage.Column, iProtPage.Row] = true;
// Map out all the items already in the stash
foreach (ACDItem tempitem in ZetaDia.Me.Inventory.Backpack)
{
if (tempitem.BaseAddress != IntPtr.Zero)
{
CacheACDItem tempCacheItem = new CacheACDItem(tempitem);
int inventoryRow = tempCacheItem.invRow;
int inventoryColumn = tempCacheItem.invCol;
// Mark this slot as not-free
BackpackSlotBlocked[inventoryColumn, inventoryRow] = true;
// Try and reliably find out if this is a two slot item or not
//BackpackSlotBlocked[inventoryColumn, inventoryRow + 1] = true;
if (inventoryRow != 5 && tempCacheItem.IsTwoSlot)
{
BackpackSlotBlocked[inventoryColumn, inventoryRow + 1] = true;
}
}
}
}
if (iAttempts > 15)
{
Logger.DBLog.InfoFormat("***************************");
Logger.DBLog.InfoFormat("GSError: Emergency Stop: No matter what we tried, we couldn't prevent an infinite stash loop. Sorry. Now stopping the bot.");
BotMain.Stop();
return false;
}
}
else
{
_dictItemStashAttempted.Add(iOriginalDynamicID, 1);
}
// Safety incase it's not actually in the backpack anymore
/*if (item.InventorySlot != InventorySlot.PlayerBackpack)
{
FunkyTownRunPlugin.DBLog.InfoFormat("GSError: Diablo 3 memory read error, or item became invalid [StashAttempt-4]", true);
return false;
}*/
int iLeftoverStackQuantity;
int iPointX = -1;
int iPointY = -1;
// First check if we can top-up any already-existing stacks in the stash
if (bOriginalIsStackable)
{
foreach (ACDItem tempitem in ZetaDia.Me.Inventory.Backpack)
{
if (tempitem.BaseAddress == IntPtr.Zero)
{
Logger.DBLog.InfoFormat("GSError: Diablo 3 memory read error, or stash item became invalid [StashAttempt-5]");
return false;
}
// Check if we combine the stacks, we won't overfill them
if ((tempitem.GameBalanceId == iOriginalGameBalanceId) && (tempitem.ItemStackQuantity < tempitem.MaxStackCount))
{
iLeftoverStackQuantity = (int)((tempitem.ItemStackQuantity + iOriginalStackQuantity) - tempitem.MaxStackCount);
iPointX = tempitem.InventoryColumn;
iPointY = tempitem.InventoryRow;
// Will we have leftovers?
if (iLeftoverStackQuantity <= 0)
goto FoundStashLocation;
goto HandleStackMovement;
}
}
HandleStackMovement:
if ((iPointX >= 0) && (iPointY >= 0))
{
ZetaDia.Me.Inventory.MoveItem(iOriginalDynamicID, iPlayerDynamicID, InventorySlot.BackpackItems, iPointX, iPointY);
}
}
iPointX = -1;
iPointY = -1;
// If it's a 2-square item, find a double-slot free
if (bOriginalTwoSlot)
{
for (int iRow = 0; iRow <= 5; iRow++)
{
bool bBottomPageRow = iRow == 5;
for (int iColumn = 0; iColumn <= 9; iColumn++)
{
// If nothing in the 1st row
if (!BackpackSlotBlocked[iColumn, iRow])
{
bool bNotEnoughSpace = false;
// Bottom row of a page = no room
if (bBottomPageRow)
bNotEnoughSpace = true;
// Already something in the stash in the 2nd row)
else if (BackpackSlotBlocked[iColumn, iRow + 1])
bNotEnoughSpace = true;
if (!bNotEnoughSpace)
{
iPointX = iColumn;
iPointY = iRow;
goto FoundStashLocation;
}
}
}
}
} // 2 slot item?
// Now deal with any leftover 1-slot items
else
{
// First we try and find somewhere "sensible"
for (int iRow = 0; iRow <= 5; iRow++)
{
bool bTopPageRow = iRow == 0;
bool bBottomPageRow = (iRow == 5);
for (int iColumn = 0; iColumn <= 9; iColumn++)
{
// Nothing in this slot
if (!BackpackSlotBlocked[iColumn, iRow])
{
bool bSensibleLocation = false;
if (!bTopPageRow && !bBottomPageRow)
{
// Something above and below this slot, or an odd-numbered row, so put something here
if ((BackpackSlotBlocked[iColumn, iRow + 1] && BackpackSlotBlocked[iColumn, iRow - 1]) ||
(iRow) % 2 != 0)
bSensibleLocation = true;
}
// Top page row with something directly underneath already blocking
else if (bTopPageRow)
{
if (BackpackSlotBlocked[iColumn, iRow + 1])
bSensibleLocation = true;
}
// Bottom page row with something directly over already blocking
else
{
bSensibleLocation = true;
}
// Sensible location? Yay, stash it here!
if (bSensibleLocation)
{
iPointX = iColumn;
iPointY = iRow;
// Keep looking for places if it's a stackable to try to stick it at the end
if (!bOriginalIsStackable)
goto FoundStashLocation;
}
}
}
}
// Didn't find a "sensible" place, let's try and force it in absolutely anywhere
if ((iPointX < 0) || (iPointY < 0))
{
for (int iRow = 0; iRow <= 5; iRow++)
{
for (int iColumn = 0; iColumn <= 9; iColumn++)
{
// Nothing in this spot, we're good!
if (!BackpackSlotBlocked[iColumn, iRow])
{
iPointX = iColumn;
iPointY = iRow;
// Keep looking for places if it's a stackable to try to stick it at the end
if (!bOriginalIsStackable)
goto FoundStashLocation;
}
}
}
}
}
FoundStashLocation:
if ((iPointX < 0) || (iPointY < 0))
{
Logger.DBLog.DebugFormat("Fatal Error: No valid stash location found for '" + sOriginalItemName + "' [" + sOriginalInternalName + " - " + OriginalPluginItemType.ToString() + "]");
Logger.DBLog.InfoFormat("***************************");
Logger.DBLog.InfoFormat("GSError: Emergency Stop: You need to stash an item but no valid space could be found. Stash is full? Stopping the bot to prevent infinite town-run loop.");
BotMain.Stop(true, "No Room To Stash!");
//ZetaDia.Service.Party.LeaveGame();
return false;
}
// We have two valid points that are empty, move the object here!
BackpackSlotBlocked[iPointX, iPointY] = true;
if (bOriginalTwoSlot)
BackpackSlotBlocked[iPointX, iPointY + 1] = true;
XY = new[] { iPointX, iPointY };
return true;
}