private static void LogSalvagedItem(CacheACDItem item) { // Item log for cool stuff stashed PluginItemTypes OriginalGilesItemType = ItemFunc.DetermineItemType(item); PluginBaseItemTypes thisGilesBaseType = ItemFunc.DetermineBaseType(OriginalGilesItemType); if (thisGilesBaseType == PluginBaseItemTypes.WeaponTwoHand || thisGilesBaseType == PluginBaseItemTypes.WeaponOneHand || thisGilesBaseType == PluginBaseItemTypes.WeaponRange || thisGilesBaseType == PluginBaseItemTypes.Armor || thisGilesBaseType == PluginBaseItemTypes.Jewelry || thisGilesBaseType == PluginBaseItemTypes.Offhand || thisGilesBaseType == PluginBaseItemTypes.FollowerItem) { FunkyTownRunPlugin.LogJunkItems(item, thisGilesBaseType, OriginalGilesItemType); } if (FunkyGame.CurrentStats != null) { FunkyGame.CurrentStats.CurrentProfile.LootTracker.SalvagedItemLog(item); } }
internal static RunStatus SellInteraction(object ret) { if (FunkyGame.GameIsInvalid) { ActionsChecked = false; FunkyTownRunPlugin.DBLog.InfoFormat("[Funky] Town Run Behavior Failed! (Not In Game/Invalid Actor/misc)"); return(RunStatus.Failure); } BotMain.StatusText = "Town run: Vendor Routine Interaction"; if (!UIElements.VendorWindow.IsVisible) { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Town Run Vednor Behavior Failed! (Vendor Window not visible)"); return(RunStatus.Failure); } #region SellItem if (townRunItemCache.SellItems.Count > 0) { BotMain.StatusText = "Town run: Vendor Routine Interaction Selling Items"; if (!Delay.Test()) { return(RunStatus.Running); } CacheACDItem thisitem = townRunItemCache.SellItems.FirstOrDefault(); // Item log for cool stuff sold if (thisitem != null) { PluginItemTypes OriginalPluginItemType = ItemFunc.DetermineItemType(thisitem); PluginBaseItemTypes thisGilesBaseType = ItemFunc.DetermineBaseType(OriginalPluginItemType); if (thisGilesBaseType == PluginBaseItemTypes.WeaponTwoHand || thisGilesBaseType == PluginBaseItemTypes.WeaponOneHand || thisGilesBaseType == PluginBaseItemTypes.WeaponRange || thisGilesBaseType == PluginBaseItemTypes.Armor || thisGilesBaseType == PluginBaseItemTypes.Jewelry || thisGilesBaseType == PluginBaseItemTypes.Offhand || thisGilesBaseType == PluginBaseItemTypes.FollowerItem) { FunkyTownRunPlugin.LogJunkItems(thisitem, thisGilesBaseType, OriginalPluginItemType); } //FunkyTownRunPlugin.TownRunStats.VendoredItemLog(thisitem); if (FunkyGame.CurrentStats != null) { FunkyGame.CurrentStats.CurrentProfile.LootTracker.VendoredItemLog(thisitem); } ZetaDia.Me.Inventory.SellItem(thisitem.ACDItem); } if (thisitem != null) { townRunItemCache.SellItems.Remove(thisitem); } if (townRunItemCache.SellItems.Count > 0) { return(RunStatus.Running); } } #endregion #region BuyPotion //Check if settings for potion buy is enabled, with less than 99 potions existing! if (bBuyingPotions) { BotMain.StatusText = "Town run: Sell Routine Interaction Buying Potions"; if (PotionCount >= FunkyTownRunPlugin.PluginSettings.PotionsCount) { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Potion Buying Finished (Potion Count Greater Than Setting) Count {0} Setting {1}", PotionCount, FunkyTownRunPlugin.PluginSettings.PotionsCount); bBuyingPotions = false; return(RunStatus.Running); } //Obey the timer, so we don't buy 100 potions in 3 seconds. if (!Delay.Test(1.5)) { return(RunStatus.Running); } //Update Dynamic ID if (PotionDynamicID == 0) { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Potion updating Dynamic ID!"); foreach (ACDItem item in ZetaDia.Me.Inventory.MerchantItems) { if (item.IsPotion) { PotionMerchantACDItem = item; PotionDynamicID = item.DynamicId; break; } } //Check we found a potion.. if (PotionDynamicID == 0) { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Potion Buying Finished (Failed to find Potion Dynamic ID)"); bBuyingPotions = false; } else { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Buying Potion Dynamic ID {0}", PotionDynamicID); } return(RunStatus.Running); } //Check we have enough gold! if (PotionMerchantACDItem.Gold > ZetaDia.CPlayer.Coinage) { FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Potion Buying Finished (Not Enough Gold to buy Potions)"); bBuyingPotions = false; return(RunStatus.Running); } FunkyTownRunPlugin.DBLog.DebugFormat("[Funky] Vendor Buying Potion!"); ZetaDia.Actors.Me.Inventory.BuyItem(PotionDynamicID); //Update counter PotionCount++; return(RunStatus.Running); } #endregion if (bNeedsEquipmentRepairs) { BotMain.StatusText = "Town run: Vendor Routine Interaction Repairing"; if (!Delay.Test()) { return(RunStatus.Running); } //int playerCoinage = ZetaDia.Me.Inventory.Coinage; //int repairCost = ZetaDia.Me.Inventory.GetRepairCost(false); //if (playerCoinage > 0 && playerCoinage < repairCost) //{ // FunkyTownRunPlugin.DBLog.InfoFormat("Emergency Stop: You need repairs but don't have enough money. Current Coinage {0} -- Repair Cost {1}", playerCoinage, repairCost); // BotMain.Stop(false, "Not enough gold to repair item(s)!"); //} ZetaDia.Me.Inventory.RepairEquippedItems(); bNeedsEquipmentRepairs = false; } return(RunStatus.Success); }
private static bool GilesStashAttempt(CacheACDItem item, out int[] XY, out int StashPage) { XY = new[] { -1, -1 }; StashPage = -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 = ItemFunc.DetermineIsTwoSlot(OriginalPluginItemType); bool bOriginalIsStackable = ItemFunc.DetermineIsStackable(OriginalPluginItemType); int iAttempts; if (_dictItemStashAttempted.TryGetValue(iOriginalDynamicID, out iAttempts)) { FunkyTownRunPlugin.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) { FunkyTownRunPlugin.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 <= 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) { 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 GilesStashSlotBlocked[inventoryColumn, inventoryRow + 1] = true; if (inventoryRow != 19 && inventoryRow != 9 && inventoryRow != 29 && inventoryRow != 39 && inventoryRow != 49) { GilesStashSlotBlocked[inventoryColumn, inventoryRow + 1] = true; } } } } if (iAttempts > 15) { FunkyTownRunPlugin.DBLog.InfoFormat("***************************"); FunkyTownRunPlugin.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; // Item log for cool stuff stashed if (thisGilesBaseType == PluginBaseItemTypes.WeaponTwoHand || thisGilesBaseType == PluginBaseItemTypes.WeaponOneHand || thisGilesBaseType == PluginBaseItemTypes.WeaponRange || thisGilesBaseType == PluginBaseItemTypes.Armor || thisGilesBaseType == PluginBaseItemTypes.Jewelry || thisGilesBaseType == PluginBaseItemTypes.Offhand || thisGilesBaseType == PluginBaseItemTypes.FollowerItem) { FunkyTownRunPlugin.LogGoodItems(item, thisGilesBaseType, OriginalPluginItemType); } 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.StashItems) { if (tempitem.BaseAddress == IntPtr.Zero) { FunkyTownRunPlugin.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.SharedStash, 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 <= 49; iRow++) { bool bBottomPageRow = (iRow == 9 || iRow == 19 || iRow == 29 || iRow == 39 || iRow == 49); for (int iColumn = 0; iColumn <= 6; iColumn++) { // If nothing in the 1st row if (!GilesStashSlotBlocked[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 (GilesStashSlotBlocked[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 <= 49; iRow++) { bool bTopPageRow = (iRow == 0 || iRow == 10 || iRow == 20 || iRow == 30 || iRow == 40); bool bBottomPageRow = (iRow == 9 || iRow == 19 || iRow == 29 || iRow == 39 || iRow == 49); for (int iColumn = 0; iColumn <= 6; iColumn++) { // Nothing in this slot if (!GilesStashSlotBlocked[iColumn, iRow]) { bool bSensibleLocation = false; if (!bTopPageRow && !bBottomPageRow) { // Something above and below this slot, or an odd-numbered row, so put something here if ((GilesStashSlotBlocked[iColumn, iRow + 1] && GilesStashSlotBlocked[iColumn, iRow - 1]) || (iRow) % 2 != 0) { bSensibleLocation = true; } } // Top page row with something directly underneath already blocking else if (bTopPageRow) { if (GilesStashSlotBlocked[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 <= 49; iRow++) { for (int iColumn = 0; iColumn <= 6; iColumn++) { // Nothing in this spot, we're good! if (!GilesStashSlotBlocked[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)) { FunkyTownRunPlugin.DBLog.DebugFormat("Fatal Error: No valid stash location found for '" + sOriginalItemName + "' [" + sOriginalInternalName + " - " + OriginalPluginItemType.ToString() + "]"); FunkyTownRunPlugin.DBLog.InfoFormat("***************************"); FunkyTownRunPlugin.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! GilesStashSlotBlocked[iPointX, iPointY] = true; if (bOriginalTwoSlot) { GilesStashSlotBlocked[iPointX, iPointY + 1] = true; } XY = new[] { iPointX, iPointY }; if (iPointY < 10) { StashPage = 0; } else if (iPointY < 20) { StashPage = 1; } else if (iPointY < 30) { StashPage = 2; } else if (iPointY < 40) { StashPage = 3; } else { StashPage = 4; } return(true); } // Custom stashing routine