public static async Task <bool> PickItemToCursor(this InventoryControlWrapper inventory, bool rightClick = false) { var item = inventory.CustomTabItem; if (item == null) { GlobalLog.Error("[PickItemToCursor] Custom inventory control is empty."); return(false); } GlobalLog.Debug($"[PickItemToCursor] Now going to pick \"{item.Name}\" to cursor."); if (rightClick) { var err = inventory.UseItem(); if (err != UseItemResult.None) { GlobalLog.Error($"[PickItemToCursor] Fail to pick item to cursor. Error: \"{err}\"."); return(false); } } else { var err = inventory.Pickup(); if (err != PickupResult.None) { GlobalLog.Error($"[PickItemToCursor] Fail to pick item to cursor. Error: \"{err}\"."); return(false); } } return(await Wait.For(() => Cursor.Item != null, "item appear under cursor")); }
public static async Task <bool> PickItemToCursor(this InventoryControlWrapper inventory, Vector2i itemPos, bool rightClick = false) { var item = inventory.Inventory.FindItemByPos(itemPos); if (item == null) { GlobalLog.Error($"[PickItemToCursor] Cannot find item at {itemPos}"); return(false); } GlobalLog.Debug($"[PickItemToCursor] Now going to pick \"{item.Name}\" at {itemPos} to cursor."); int id = item.LocalId; if (rightClick) { var err = inventory.UseItem(id); if (err != UseItemResult.None) { GlobalLog.Error($"[PickItemToCursor] Fail to pick item to cursor. Error: \"{err}\"."); return(false); } } else { var err = inventory.Pickup(id); if (err != PickupResult.None) { GlobalLog.Error($"[PickItemToCursor] Fail to pick item to cursor. Error: \"{err}\"."); return(false); } } return(await Wait.For(() => Cursor.Item != null, "item appear under cursor")); }
public CachedItemObject(InventoryControlWrapper wrp, Item item, string tabName = "") { //Wrapper = wrp; TabName = tabName; League = string.Copy(LokiPoe.Me.League); if (wrp.HasCurrencyTabOverride) { MaxCurrencyTabStackCount = item.MaxCurrencyTabStackCount; } Update(item); }
private static bool ControlCanFit(InventoryControlWrapper control, string metadata) { var item = control.CustomTabItem; if (item == null) { return(true); } if (metadata == "Metadata/Items/Currency/CurrencyItemisedProphecy") { return(false); } return(item.Metadata == metadata && item.StackCount < 5000); }
private static bool CanFit(this InventoryControlWrapper control, string itemName, int amount) { var item = control.CustomTabItem; if (item == null) { return(true); } if (itemName == CurrencyNames.Prophecy) { return(false); } return(item.Name == itemName && item.StackCount + amount <= 5000); }
public static async Task <bool> FastMoveFromPremiumStashTab(InventoryControlWrapper control) { if (control == null) { GlobalLog.Error("[FastMoveFromPremiumStashTab] Inventory control is null."); return(false); } var item = control.CustomTabItem; if (item == null) { GlobalLog.Error("[FastMoveFromPremiumStashTab] Inventory control has no item."); return(false); } var itemName = item.Name; var stackCount = item.StackCount; var tabName = StashUi.TabControl.CurrentTabName; GlobalLog.Debug($"[FastMoveFromPremiumStashTab] Fast moving \"{itemName}\" from \"{tabName}\" tab."); var moved = control.FastMove(); if (moved != FastMoveResult.None) { GlobalLog.Error($"[FastMoveFromPremiumStashTab] Fast move error: \"{moved}\"."); return(false); } if (await Wait.For(() => { var i = control.CustomTabItem; return(i == null || i.StackCount < stackCount); }, "fast move")) { GlobalLog.Debug($"[FastMoveFromPremiumStashTab] \"{itemName}\" has been successfully fast moved from \"{tabName}\" tab."); if (Settings.Instance.ArtificialDelays) { await Wait.ArtificialDelay(); } return(true); } GlobalLog.Error($"[FastMoveFromPremiumStashTab] Fast move timeout for \"{itemName}\" in \"{tabName}\" tab."); return(false); }
/// <summary> /// This coroutine waits for an item to be fully altered and available /// </summary> /// <param name="wrapper">Wrapper to retrieve item from</param> /// <param name="itemId">Initial id of the item to check</param> /// <param name="timeout"></param> /// <returns>True if item is null before timeout, else false</returns> public static async Task <bool> WaitForItemToChange(InventoryControlWrapper wrapper, int itemId, int timeout = 2000) { var sw = Stopwatch.StartNew(); var item = wrapper.Inventory.GetItemById(itemId); while (item != null) { await Coroutine.Yield(); item = wrapper.Inventory.GetItemById(itemId); if (sw.ElapsedMilliseconds > timeout) { return(false); } } return(true); }
/// <summary> /// Split an item from a source wrapper into main inventory /// </summary> /// <param name="wrapper">Source wrapper, where the item belongs</param> /// <param name="item">Item that is meant to be splitten up</param> /// <param name="pickupAmount">Amount to be placed in main, if this is superior to the stack count, it gets fastmoved instead</param> /// <returns> true if everything went well</returns> public static async Task <bool> SplitAndPlaceItemInMainInventory(InventoryControlWrapper wrapper, Item item, int pickupAmount) { // If Any of these args are null, throw an application-level exception if (wrapper == null) { throw new ArgumentNullException(nameof(wrapper)); } if (item == null) { throw new ArgumentNullException(nameof(item)); } CommunityLib.Log.DebugFormat("[SplitAndPlaceItemInMainInventory] Spliting up stacks. Getting {0} {1}. Count in stack: {2}", pickupAmount, item.FullName, item.StackCount); if (pickupAmount >= item.StackCount) { return(await FastMove(wrapper, item.LocalId)); } var error = wrapper.SplitStack(item.LocalId, pickupAmount); //We assume it's currency stash tab, do not use LocalId with it if (error == SplitStackResult.Unsupported) { error = wrapper.SplitStack(pickupAmount); } if (error != SplitStackResult.None) { CommunityLib.Log.ErrorFormat("[SplitAndPlaceItemInMainInventory] Failed to split failed. Split Error: {0}", error); return(false); } await Inputs.WaitForCursorToHaveItem(); await Coroutines.ReactionWait(); await Inputs.ClearCursorTask(); return(true); }
public async Task <ApplyCursorResult> UseOnItem(InventoryControlWrapper destinationWrapper, Item destinationItem, Inventory.StopUsingDelegate delegateToStop = null) { var item = await GetItem(); var wrapper = await GetWrapper(); if (wrapper == null || item == null) { CommunityLib.Log.ErrorFormat("[{0}] Failed to get item or wrapper, item == null: {1}, wrapper == null == {2}", Name, item == null, wrapper == null); RemoveFromCache(); return(ApplyCursorResult.ItemNotFound); } var res = await Inventory.UseItemOnItem(Wrapper, item, destinationWrapper, destinationItem, delegateToStop); //Updating the StackCount now and removing the item if needed await Update(); return(res); }
/// <summary> /// This functions is meant to use an item on another one, for identification, chancing, anything you can think about /// It also supports the +X% quality using stones/scraps /// </summary> /// <param name="sourceWrapper">The source (inventory) that's holding the item meant to be used</param> /// <param name="sourceItem">The item meant to be used</param> /// <param name="destinationWrapper">The source (inventory) holding the item meant to be altered</param> /// <param name="destinationItem">The item menant to be altered</param> /// <param name="d">Delegate/Condition to stop using item</param> /// <returns>ApplyCursorResult enum entry</returns> public static async Task <ApplyCursorResult> UseItemOnItem(InventoryControlWrapper sourceWrapper, Item sourceItem, InventoryControlWrapper destinationWrapper, Item destinationItem, StopUsingDelegate d = null) { // If Any of these args are null, throw an application-level exception if (sourceWrapper == null) { throw new ArgumentNullException(nameof(sourceWrapper)); } if (sourceItem == null) { throw new ArgumentNullException(nameof(sourceItem)); } if (destinationWrapper == null) { throw new ArgumentNullException(nameof(destinationWrapper)); } if (destinationItem == null) { throw new ArgumentNullException(nameof(destinationItem)); } // If the item is not modifiable, prevent the logic to be executed if (destinationItem.IsCorrupted || destinationItem.IsMirrored) { CommunityLib.Log.DebugFormat("[CommunityLib] We can\'t alter the item (Corrupted/Mirrored). UnsupportedItem"); return(ApplyCursorResult.UnsupportedItem); } if (destinationItem.HasSkillGemsEquipped && sourceItem.FullName == "Jeweller's Orb") { CommunityLib.Log.DebugFormat("[CommunityLib] We can't change sockets on the item (Has skill gems in it). UnsupportedItem"); return(ApplyCursorResult.UnsupportedItem); } var onCursor = sourceWrapper.UseItem(sourceItem.LocalId); // We assume it's currency stash tab, do not use LocalId with it if (onCursor == UseItemResult.Unsupported) { CommunityLib.Log.DebugFormat("[CommunityLib] Failed to use item on item. Unsupported"); onCursor = sourceWrapper.UseItem(); } await Coroutines.LatencyWait(); // If something else than None is returned, the item can't be put on cursor properly if (onCursor != UseItemResult.None) { if (!await Inputs.WaitForCursorToHaveItem()) { CommunityLib.Log.ErrorFormat($"[CommunityLib] Failed to use item on item. OnCursor: {onCursor}. Returning item not found"); return(ApplyCursorResult.ItemNotFound); } } await Coroutines.LatencyWait(); // First, we put the item on cursor to start applying var err = InventoryControlWrapper.BeginApplyCursor(true); if (err != ApplyCursorResult.None) { CommunityLib.Log.Error($"[CommunityLib] Error returned for BeginApplyCursor : {err}"); return(ApplyCursorResult.ProcessHookManagerNotEnabled); } // We store the destination item's location to make sure it has been applied or the delegate (lower in the code) is valid var itemLocation = destinationItem.LocationTopLeft; int useCount = 0; while (true) { var initialId = destinationItem.LocalId; // Apply item on cursor to the destination item err = destinationWrapper.ApplyCursorTo(destinationItem.LocalId); //Destination is in utility currency slot? if (err == ApplyCursorResult.Unsupported) { err = destinationWrapper.ApplyCursorTo(); } // If the error is different of None, break the execution and return the error if (err != ApplyCursorResult.None) { break; } // Check if the item has been modified on memory-side if (!await WaitForItemToChange(destinationWrapper, initialId)) { break; } await Coroutines.LatencyWait(); //await Coroutines.ReactionWait(); // If the delegate is null, that means our processing is done, break the loop to return None if (d == null) { break; } // We increment usecount to make it usable in delegate useCount++; // Refresh item to test the delegate (or condition) destinationItem = destinationWrapper.Inventory.GetItemAtLocation(itemLocation.X, itemLocation.Y); if (d.Invoke(destinationItem, useCount)) { break; } } // End up the item application var err2 = InventoryControlWrapper.EndApplyCursor(); await Coroutine.Yield(); await Inputs.WaitForCursorToBeEmpty(); // IF an error is returned, let caller know if (err2 != ApplyCursorResult.None) { CommunityLib.Log.Error($"[CommunityLib] Error returned for EndApplyCursor : {err2}"); return(ApplyCursorResult.ProcessHookManagerNotEnabled); } if (err != ApplyCursorResult.None) { CommunityLib.Log.ErrorFormat($"[CommunityLib] Failed to use item on item. Error: {err}"); } return(err); }
/// <summary> /// Generic FastMove using new Inv Wrapper /// The inventory you refer is theinventory that will be used for moving the item from /// </summary> /// <param name="inv">This is the location where the item is picked up (can be stash or whatever you want)</param> /// <param name="id">This is the item localid</param> /// <param name="retries">Number of max fastmove attempts</param> /// <param name="breakFunc">If specified condition return true, FastMove will canceled and false will be returned</param> /// <returns>FastMoveResult enum entry</returns> public static async Task <bool> FastMove(InventoryControlWrapper inv, int id, int retries = 3, Func <bool> breakFunc = null) { // If the inventory is null for reasons, throw ana application-level error if (inv == null) { throw new ArgumentNullException(nameof(inv)); } // Here the idea is to make a first fastmove attempt to get an error // If the error is different of None, return the error var err = inv.FastMove(id); //We assume it's currency stash tab, do not use LocalId with it if (err == FastMoveResult.Unsupported) { err = inv.FastMove(); } if (err != FastMoveResult.None) { CommunityLib.Log.ErrorFormat("[CommunityLib][FastMove] FastMove has returned an error : {0}", err); return(false); } await Coroutines.LatencyWait(); await Coroutines.ReactionWait(); // The idea is to have a maximum of tries, but we don't want to spam them. // A Timer is started to "cool-off" the tries and a random lapse is calculated between each checks var nextfastmovetimer = Stopwatch.StartNew(); var nextFastMove = LokiPoe.Random.Next(2500, 4000); int nextFastMoveTries = 0; while (nextFastMoveTries < retries) { if (breakFunc != null) { if (breakFunc()) { return(false); } } // Verifying if the item exists in the source inventory // If not, the item has been moved return true var itemExists = inv.Inventory.GetItemById(id); if (itemExists == null) { await Coroutines.ReactionWait(); return(true); } // If it exists, and the timer has reached the random lapse we calculated above, // Attempt to make a new move if (nextfastmovetimer.ElapsedMilliseconds > nextFastMove) { CommunityLib.Log.DebugFormat("[CommunityLib][FastMove] Attempt to fastmove ({0}/{1})", nextFastMoveTries, retries); var error = inv.FastMove(id); if (error == FastMoveResult.Unsupported) { inv.FastMove(); } await Coroutines.LatencyWait(); await Coroutines.ReactionWait(); nextFastMove = LokiPoe.Random.Next(2500, 4000); nextfastmovetimer.Restart(); nextFastMoveTries++; } await Coroutine.Sleep(20); } // It failed after the number of tries referenced, just return false. CommunityLib.Log.ErrorFormat("[CommunityLib][FastMove] Operation failed after {0} tries", retries); return(false); }
private static int CardSetsInControl(InventoryControlWrapper control) { var item = control.CustomTabItem; return(item == null ? 0 : item.StackCount / item.MaxStackCount); }
public static async Task <bool> PlaceItemFromCursor(this InventoryControlWrapper inventory, Vector2i pos) { var cursorItem = Cursor.Item; if (cursorItem == null) { GlobalLog.Error("[PlaceItemFromCursor] Cursor item is null."); return(false); } GlobalLog.Debug($"[PlaceItemFromCursor] Now going to place \"{cursorItem.Name}\" from cursor to {pos}."); //apply item on another item, if we are in VirtualUse mode if (Cursor.Mode == LokiPoe.InGameState.CursorItemModes.VirtualUse) { var destItem = inventory.Inventory.FindItemByPos(pos); if (destItem == null) { GlobalLog.Error("[PlaceItemFromCursor] Destination item is null."); return(false); } int destItemId = destItem.LocalId; var applied = inventory.ApplyCursorTo(destItem.LocalId); if (applied != ApplyCursorResult.None) { GlobalLog.Error($"[PlaceItemFromCursor] Fail to place item from cursor. Error: \"{applied}\"."); return(false); } //wait for destination item change, it cannot become null, ID should change return(await Wait.For(() => { var item = inventory.Inventory.FindItemByPos(pos); return item != null && item.LocalId != destItemId; }, "destination item change")); } //in other cases, place item to empty inventory slot or swap it with another item int cursorItemId = cursorItem.LocalId; var placed = inventory.PlaceCursorInto(pos.X, pos.Y, true); if (placed != PlaceCursorIntoResult.None) { GlobalLog.Error($"[PlaceItemFromCursor] Fail to place item from cursor. Error: \"{placed}\"."); return(false); } //wait for cursor item change, if we placed - it should become null, if we swapped - ID should change if (!await Wait.For(() => { var item = Cursor.Item; return(item == null || item.LocalId != cursorItemId); }, "cursor item change")) { return(false); } if (Settings.Instance.ArtificialDelays) { await Wait.ArtificialDelay(); } return(true); }