/// <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); }
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); }