internal static RunStatus StashUpdate(object ret) { if (FunkyGame.GameIsInvalid) { ActionsChecked = false; FunkyTownRunPlugin.DBLog.InfoFormat("[Funky] Town Run Behavior Failed! (Not In Game/Invalid Actor/misc)"); return(RunStatus.Failure); } if (!bUpdatedStashMap) { // Array for what blocks are or are not blocked for (int iRow = 0; iRow <= 49; iRow++) { for (int iColumn = 0; iColumn <= 6; iColumn++) { GilesStashSlotBlocked[iColumn, iRow] = false; } } // Block off the entire of any "protected stash pages" foreach (int iProtPage in CharacterSettings.Instance.ProtectedStashPages) { for (int iProtRow = 0; iProtRow <= 9; iProtRow++) { for (int iProtColumn = 0; iProtColumn <= 6; iProtColumn++) { GilesStashSlotBlocked[iProtColumn, iProtRow + (iProtPage * 10)] = true; } } } // Remove rows we don't have for (int iRow = (ZetaDia.Me.NumSharedStashSlots / 7); iRow <= 49; iRow++) { for (int iColumn = 0; iColumn <= 6; iColumn++) { GilesStashSlotBlocked[iColumn, iRow] = true; } } // Map out all the items already in the stash foreach (ACDItem tempitem in ZetaDia.Me.Inventory.StashItems) { if (tempitem.BaseAddress != IntPtr.Zero) { //StashedItems.Add(new CacheACDItem(tempitem)); int inventoryRow = tempitem.InventoryRow; int inventoryColumn = tempitem.InventoryColumn; // Mark this slot as not-free GilesStashSlotBlocked[inventoryColumn, inventoryRow] = true; // Try and reliably find out if this is a two slot item or not PluginItemTypes tempItemType = ItemFunc.DetermineItemType(tempitem.InternalName, tempitem.ItemType, tempitem.FollowerSpecialType, tempitem.ActorSNO); if (ItemFunc.DetermineIsTwoSlot(tempItemType) && inventoryRow != 19 && inventoryRow != 9 && inventoryRow != 29 && inventoryRow != 39 && inventoryRow != 49) { GilesStashSlotBlocked[inventoryColumn, inventoryRow + 1] = true; } else if (ItemFunc.DetermineIsTwoSlot(tempItemType) && (inventoryRow == 19 || inventoryRow == 9 || inventoryRow == 29 || inventoryRow == 39 || inventoryRow == 49)) { FunkyTownRunPlugin.DBLog.DebugFormat("GSError: DemonBuddy thinks this item is 2 slot even though it's at bottom row of a stash page: " + tempitem.Name + " [" + tempitem.InternalName + "] type=" + tempItemType.ToString() + " @ slot " + (inventoryRow + 1).ToString(CultureInfo.InvariantCulture) + "/" + (inventoryColumn + 1).ToString(CultureInfo.InvariantCulture)); } } } // Loop through all stash items bUpdatedStashMap = true; } // Need to update the stash map? return(RunStatus.Success); }
internal static void LogGoodItems(CacheACDItem thisgooditem, PluginBaseItemTypes thisPluginBaseItemTypes, PluginItemTypes thisPluginItemType) { try { //Update this item using (ZetaDia.Memory.AcquireFrame()) { thisgooditem = new CacheACDItem(thisgooditem.ACDItem); } } catch { DBLog.DebugFormat("Failure to update CacheACDItem during Logging"); } //double iThisItemValue = ItemFunc.ValueThisItem(thisgooditem, thisPluginItemType); FileStream LogStream = null; try { string outputPath = FolderPaths.LoggingFolderPath + @"\StashLog.log"; LogStream = File.Open(outputPath, FileMode.Append, FileAccess.Write, FileShare.Read); using (StreamWriter LogWriter = new StreamWriter(LogStream)) { if (!TownRunManager.bLoggedAnythingThisStash) { TownRunManager.bLoggedAnythingThisStash = true; LogWriter.WriteLine(DateTime.Now.ToString() + ":"); LogWriter.WriteLine("===================="); } string sLegendaryString = ""; if (thisgooditem.ThisQuality >= ItemQuality.Legendary) { if (!thisgooditem.IsUnidentified) { //Prowl.AddNotificationToQueue(thisgooditem.ThisRealName + " [" + thisPluginItemType.ToString() + "] (Score=" + iThisItemValue.ToString() + ". " + TownRunManager.sValueItemStatString + ")", ZetaDia.Service.Hero.Name + " new legendary!", Prowl.ProwlNotificationPriority.Emergency); sLegendaryString = " {legendary item}"; // Change made by bombastic DBLog.Info("+=+=+=+=+=+=+=+=+ LEGENDARY FOUND +=+=+=+=+=+=+=+=+"); DBLog.Info("+ Name: " + thisgooditem.ThisRealName + " (" + thisPluginItemType.ToString() + ")"); //DBLog.Info("+ Score: " + Math.Round(iThisItemValue).ToString()); DBLog.Info("+ Attributes: " + thisgooditem.ItemStatString); DBLog.Info("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+"); } else { DBLog.Info("+=+=+=+=+=+=+=+=+ LEGENDARY FOUND +=+=+=+=+=+=+=+=+"); DBLog.Info("+ Unid: " + thisPluginItemType.ToString()); DBLog.Info("+ Level: " + thisgooditem.ThisLevel.ToString()); DBLog.Info("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+"); } } else { // Check for non-legendary notifications bool bShouldNotify = false; switch (thisPluginBaseItemTypes) { case PluginBaseItemTypes.WeaponOneHand: case PluginBaseItemTypes.WeaponRange: case PluginBaseItemTypes.WeaponTwoHand: //if (ithisitemvalue >= settings.iNeedPointsToNotifyWeapon) // bShouldNotify = true; break; case PluginBaseItemTypes.Armor: case PluginBaseItemTypes.Offhand: //if (ithisitemvalue >= settings.iNeedPointsToNotifyArmor) //bShouldNotify = true; break; case PluginBaseItemTypes.Jewelry: //if (ithisitemvalue >= settings.iNeedPointsToNotifyJewelry) //bShouldNotify = true; break; } //if (bShouldNotify) //Prowl.AddNotificationToQueue(thisgooditem.ThisRealName + " [" + thisPluginItemType.ToString() + "] (Score=" + iThisItemValue.ToString() + ". " + TownRunManager.sValueItemStatString + ")", ZetaDia.Service.Hero.Name + " new item!", Prowl.ProwlNotificationPriority.Emergency); } if (!thisgooditem.IsUnidentified) { LogWriter.WriteLine(thisgooditem.ThisQuality.ToString() + " " + thisPluginItemType.ToString() + " '" + thisgooditem.ThisRealName + sLegendaryString); LogWriter.WriteLine(" " + thisgooditem.ItemStatString); LogWriter.WriteLine(""); } else { LogWriter.WriteLine(thisgooditem.ThisQuality.ToString() + " " + thisPluginItemType.ToString() + " '" + sLegendaryString); LogWriter.WriteLine("iLevel " + thisgooditem.ThisLevel.ToString()); LogWriter.WriteLine(""); } } } catch (IOException) { DBLog.Info("Fatal Error: File access error for stash log file."); } }
internal static void LogJunkItems(CacheACDItem thisgooditem, PluginBaseItemTypes thisPluginBaseItemTypes, PluginItemTypes thisPluginItemType) { FileStream LogStream = null; string outputPath = FolderPaths.LoggingFolderPath + @"\JunkLog.log"; try { LogStream = File.Open(outputPath, FileMode.Append, FileAccess.Write, FileShare.Read); using (StreamWriter LogWriter = new StreamWriter(LogStream)) { if (!TownRunManager.bLoggedJunkThisStash) { TownRunManager.bLoggedJunkThisStash = true; LogWriter.WriteLine(DateTime.Now.ToString() + ":"); LogWriter.WriteLine("===================="); } string sLegendaryString = ""; if (thisgooditem.ThisQuality >= ItemQuality.Legendary) sLegendaryString = " {legendary item}"; LogWriter.WriteLine(thisgooditem.ThisQuality.ToString() + " " + thisPluginItemType.ToString() + " '" + thisgooditem.ThisRealName + sLegendaryString); LogWriter.Write(thisgooditem.ItemStatProperties.ReturnPrimaryStatString()); LogWriter.WriteLine(""); } } catch (IOException) { DBLog.Info("Fatal Error: File access error for junk log file."); } }
} // Custom stashing routine 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 = 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 = (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); } // Custom stashing routine
private void UpdateStashSlots() { Logger.DBLog.DebugFormat("Updating Stash Slots!"); // Array for what blocks are or are not blocked for (int iRow = 0; iRow <= 49; iRow++) { for (int iColumn = 0; iColumn <= 6; iColumn++) { StashSlotBlocked[iColumn, iRow] = false; } } // Block off the entire of any "protected stash pages" foreach (int iProtPage in CharacterSettings.Instance.ProtectedStashPages) { for (int iProtRow = 0; iProtRow <= 9; iProtRow++) { for (int iProtColumn = 0; iProtColumn <= 6; iProtColumn++) { StashSlotBlocked[iProtColumn, iProtRow + (iProtPage * 10)] = true; } } } // Remove rows we don't have for (int iRow = (ZetaDia.Me.NumSharedStashSlots / 7); iRow <= 49; iRow++) { for (int iColumn = 0; iColumn <= 6; iColumn++) { StashSlotBlocked[iColumn, iRow] = true; } } // Map out all the items already in the stash foreach (ACDItem tempitem in ZetaDia.Me.Inventory.StashItems) { if (tempitem.BaseAddress != IntPtr.Zero) { //StashedItems.Add(new CacheACDItem(tempitem)); int inventoryRow = tempitem.InventoryRow; int inventoryColumn = tempitem.InventoryColumn; // Mark this slot as not-free StashSlotBlocked[inventoryColumn, inventoryRow] = true; // Try and reliably find out if this is a two slot item or not PluginItemTypes tempItemType = ItemFunc.DetermineItemType(tempitem.InternalName, tempitem.ItemType, tempitem.FollowerSpecialType, tempitem.ActorSNO); if (ItemFunc.DetermineIsTwoSlot(tempItemType) && inventoryRow != 19 && inventoryRow != 9 && inventoryRow != 29 && inventoryRow != 39 && inventoryRow != 49) { StashSlotBlocked[inventoryColumn, inventoryRow + 1] = true; } else if (ItemFunc.DetermineIsTwoSlot(tempItemType) && (inventoryRow == 19 || inventoryRow == 9 || inventoryRow == 29 || inventoryRow == 39 || inventoryRow == 49)) { Logger.DBLog.DebugFormat("GSError: DemonBuddy thinks this item is 2 slot even though it's at bottom row of a stash page: " + tempitem.Name + " [" + tempitem.InternalName + "] type=" + tempItemType.ToString() + " @ slot " + (inventoryRow + 1).ToString(CultureInfo.InvariantCulture) + "/" + (inventoryColumn + 1).ToString(CultureInfo.InvariantCulture)); } } } // Loop through all stash items bUpdatedStashMap = true; }