Release v1.0.4
Add Shift+Right Click Trade window support with auto-fill max quantity.
This commit is contained in:
+75
-7
@@ -1148,7 +1148,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
// Then we can recognize the correct InputNumeric without relying on prompt text.
|
// Then we can recognize the correct InputNumeric without relying on prompt text.
|
||||||
private uint pendingSplitExpectedMax;
|
private uint pendingSplitExpectedMax;
|
||||||
private long pendingSplitExpectedUntilMs;
|
private long pendingSplitExpectedUntilMs;
|
||||||
private enum PendingNumericKind { None, Store, Remove, Move, Split }
|
private enum PendingNumericKind { None, Store, Remove, Move, Split, Trade }
|
||||||
private PendingNumericKind pendingNumericKind;
|
private PendingNumericKind pendingNumericKind;
|
||||||
|
|
||||||
private long lastShiftSeenMs;
|
private long lastShiftSeenMs;
|
||||||
@@ -1287,6 +1287,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
RemoveFromCompanyChest,
|
RemoveFromCompanyChest,
|
||||||
Split,
|
Split,
|
||||||
Sort,
|
Sort,
|
||||||
|
Trade,
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] ArmouryAddonNames =
|
private static readonly string[] ArmouryAddonNames =
|
||||||
@@ -1899,6 +1900,23 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
lastActionTickMs = now;
|
lastActionTickMs = now;
|
||||||
if (Configuration.DebugMode)
|
if (Configuration.DebugMode)
|
||||||
Log.Information($"[QuickTransfer] ({mode} + RClick) Selected context action '{chosenText}' (idx={chosenIndex}) via OpenForItemSlot.");
|
Log.Information($"[QuickTransfer] ({mode} + RClick) Selected context action '{chosenText}' (idx={chosenIndex}) via OpenForItemSlot.");
|
||||||
|
|
||||||
|
// Set up Trade quantity auto-confirm if Trade was selected
|
||||||
|
if (mode == ModifierMode.Shift &&
|
||||||
|
chosenText.Length > 0 &&
|
||||||
|
ContextLabelMatches(AutoContextAction.Trade, chosenText) &&
|
||||||
|
IsTradeOpen())
|
||||||
|
{
|
||||||
|
pendingCompanyChestNumericConfirmUntilMs = now + 1500;
|
||||||
|
pendingCompanyChestNumericConfirmAttempts = 0;
|
||||||
|
pendingCompanyChestNumericArmed = true;
|
||||||
|
pendingNumericKind = PendingNumericKind.Trade;
|
||||||
|
pendingCompanyChestNumericValueSet = false;
|
||||||
|
pendingCompanyChestNumericValueSetAtMs = 0;
|
||||||
|
pendingCompanyChestNumericDesired = 0;
|
||||||
|
pendingCompanyChestNumericHalf = false;
|
||||||
|
ArmSuppressInputNumeric(now, 1500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Configuration.DebugMode && mode == ModifierMode.Ctrl)
|
else if (Configuration.DebugMode && mode == ModifierMode.Ctrl)
|
||||||
{
|
{
|
||||||
@@ -2014,7 +2032,12 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
lastAltSeenMs = now;
|
lastAltSeenMs = now;
|
||||||
|
|
||||||
// Quantity prompt auto-confirm (best effort).
|
// Quantity prompt auto-confirm (best effort).
|
||||||
if (Configuration.AutoConfirmCompanyChestQuantity &&
|
// Trade and Split always auto-confirm; Company Chest respects the config setting.
|
||||||
|
var shouldAutoConfirm = pendingNumericKind == PendingNumericKind.Trade ||
|
||||||
|
pendingNumericKind == PendingNumericKind.Split ||
|
||||||
|
(Configuration.AutoConfirmCompanyChestQuantity && pendingNumericKind != PendingNumericKind.None);
|
||||||
|
|
||||||
|
if (shouldAutoConfirm &&
|
||||||
pendingNumericKind != PendingNumericKind.None &&
|
pendingNumericKind != PendingNumericKind.None &&
|
||||||
pendingCompanyChestNumericConfirmUntilMs > 0 &&
|
pendingCompanyChestNumericConfirmUntilMs > 0 &&
|
||||||
now <= pendingCompanyChestNumericConfirmUntilMs)
|
now <= pendingCompanyChestNumericConfirmUntilMs)
|
||||||
@@ -2422,6 +2445,21 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
? 3000
|
? 3000
|
||||||
: 1500;
|
: 1500;
|
||||||
ArmSuppressContextMenu(now, suppressMs);
|
ArmSuppressContextMenu(now, suppressMs);
|
||||||
|
if (pending.Value.Mode == ModifierMode.Shift &&
|
||||||
|
chosenText.Length > 0 &&
|
||||||
|
ContextLabelMatches(AutoContextAction.Trade, chosenText))
|
||||||
|
{
|
||||||
|
// Trade: auto-confirm max quantity when InputNumeric appears
|
||||||
|
pendingCompanyChestNumericConfirmUntilMs = now + 1500;
|
||||||
|
pendingCompanyChestNumericConfirmAttempts = 0;
|
||||||
|
pendingCompanyChestNumericArmed = true;
|
||||||
|
pendingNumericKind = PendingNumericKind.Trade;
|
||||||
|
pendingCompanyChestNumericValueSet = false;
|
||||||
|
pendingCompanyChestNumericValueSetAtMs = 0;
|
||||||
|
pendingCompanyChestNumericDesired = 0;
|
||||||
|
pendingCompanyChestNumericHalf = false;
|
||||||
|
ArmSuppressInputNumeric(now, 1500);
|
||||||
|
}
|
||||||
if (Configuration.EnableCompanyChest &&
|
if (Configuration.EnableCompanyChest &&
|
||||||
pending.Value.Mode == ModifierMode.Shift &&
|
pending.Value.Mode == ModifierMode.Shift &&
|
||||||
chosenText.Length > 0 &&
|
chosenText.Length > 0 &&
|
||||||
@@ -2969,8 +3007,8 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
// Single-pass: decode each label once, record first match per action.
|
// Single-pass: decode each label once, record first match per action.
|
||||||
var foundAny = false;
|
var foundAny = false;
|
||||||
|
|
||||||
int removeIdx = -1, addIdx = -1, placeIdx = -1, returnIdx = -1, entrustIdx = -1, retrieveIdx = -1, companyRemoveIdx = -1, splitIdx = -1;
|
int removeIdx = -1, addIdx = -1, placeIdx = -1, returnIdx = -1, entrustIdx = -1, retrieveIdx = -1, companyRemoveIdx = -1, splitIdx = -1, tradeIdx = -1;
|
||||||
string? removeTxt = null, addTxt = null, placeTxt = null, returnTxt = null, entrustTxt = null, retrieveTxt = null, companyRemoveTxt = null, splitTxt = null;
|
string? removeTxt = null, addTxt = null, placeTxt = null, returnTxt = null, entrustTxt = null, retrieveTxt = null, companyRemoveTxt = null, splitTxt = null, tradeTxt = null;
|
||||||
|
|
||||||
var max = Math.Min(agent->ContextItemCount, 64);
|
var max = Math.Min(agent->ContextItemCount, 64);
|
||||||
for (var i = 0; i < max; i++)
|
for (var i = 0; i < max; i++)
|
||||||
@@ -3039,6 +3077,13 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
splitIdx = i;
|
splitIdx = i;
|
||||||
splitTxt = text;
|
splitTxt = text;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tradeIdx < 0 && ContextLabelMatches(AutoContextAction.Trade, text))
|
||||||
|
{
|
||||||
|
tradeIdx = i;
|
||||||
|
tradeTxt = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3048,6 +3093,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
var saddlebagOpen = IsSaddlebagOpen();
|
var saddlebagOpen = IsSaddlebagOpen();
|
||||||
var retainerOpen = IsRetainerOpen();
|
var retainerOpen = IsRetainerOpen();
|
||||||
var companyChestOpen = IsCompanyChestOpen();
|
var companyChestOpen = IsCompanyChestOpen();
|
||||||
|
var tradeOpen = IsTradeOpen();
|
||||||
|
|
||||||
// Choose the best action that exists in the menu.
|
// Choose the best action that exists in the menu.
|
||||||
//
|
//
|
||||||
@@ -3071,6 +3117,11 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
chosen = splitIdx >= 0 ? (splitIdx, splitTxt) : (-1, (string?)null);
|
chosen = splitIdx >= 0 ? (splitIdx, splitTxt) : (-1, (string?)null);
|
||||||
}
|
}
|
||||||
|
else if (mode == ModifierMode.Shift && tradeOpen)
|
||||||
|
{
|
||||||
|
// Trade window: prioritize Trade action when Trade window is open
|
||||||
|
chosen = tradeIdx >= 0 ? (tradeIdx, tradeTxt) : (-1, (string?)null);
|
||||||
|
}
|
||||||
else if (mode == ModifierMode.Shift && companyChestOpen && Configuration.EnableCompanyChest)
|
else if (mode == ModifierMode.Shift && companyChestOpen && Configuration.EnableCompanyChest)
|
||||||
{
|
{
|
||||||
chosen = companyRemoveIdx >= 0 ? (companyRemoveIdx, companyRemoveTxt) : (-1, (string?)null);
|
chosen = companyRemoveIdx >= 0 ? (companyRemoveIdx, companyRemoveTxt) : (-1, (string?)null);
|
||||||
@@ -3122,11 +3173,11 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
GenerateCallback(contextMenuAddon, 0, chosen.idx, 0U, 0, 0);
|
GenerateCallback(contextMenuAddon, 0, chosen.idx, 0U, 0, 0);
|
||||||
|
|
||||||
// Some actions (notably Split) can be cancelled if we close the menu immediately.
|
// Some actions (notably Split and Trade) can be cancelled if we close the menu immediately.
|
||||||
// Delay the close slightly to allow the follow-up UI (InputNumeric) to spawn.
|
// Delay the close slightly to allow the follow-up UI (InputNumeric) to spawn.
|
||||||
if (chosen.txt != null && ContextLabelMatches(AutoContextAction.Split, chosen.txt))
|
if (chosen.txt != null && (ContextLabelMatches(AutoContextAction.Split, chosen.txt) || ContextLabelMatches(AutoContextAction.Trade, chosen.txt)))
|
||||||
{
|
{
|
||||||
// Don't close immediately: on some setups this cancels Split before InputNumeric opens.
|
// Don't close immediately: on some setups this cancels the action before InputNumeric opens.
|
||||||
// We'll keep the menu invisible (via suppression) and close it later as a cleanup.
|
// We'll keep the menu invisible (via suppression) and close it later as a cleanup.
|
||||||
pendingCloseContextMenuAtMs = Environment.TickCount64 + 3000;
|
pendingCloseContextMenuAtMs = Environment.TickCount64 + 3000;
|
||||||
}
|
}
|
||||||
@@ -4457,6 +4508,15 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
return false;
|
return false;
|
||||||
if (kind == PendingNumericKind.Remove && !prompt.Contains("remove", StringComparison.OrdinalIgnoreCase))
|
if (kind == PendingNumericKind.Remove && !prompt.Contains("remove", StringComparison.OrdinalIgnoreCase))
|
||||||
return false;
|
return false;
|
||||||
|
// Trade dialogs may be localized; if we're in Trade mode and Trade window is open, accept it
|
||||||
|
// (similar to how Split works - we trust the context rather than requiring exact prompt text)
|
||||||
|
if (kind == PendingNumericKind.Trade && !prompt.Contains("trade", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Fallback: if Trade window is open and we're expecting Trade, accept it anyway
|
||||||
|
// (prompt might be localized or say "How many would you like to trade?" etc.)
|
||||||
|
if (!IsTradeOpen())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (minValue->Type != AtkValueType.UInt || maxValue->Type != AtkValueType.UInt || defaultValue->Type != AtkValueType.UInt)
|
if (minValue->Type != AtkValueType.UInt || maxValue->Type != AtkValueType.UInt || defaultValue->Type != AtkValueType.UInt)
|
||||||
return false;
|
return false;
|
||||||
@@ -5111,6 +5171,9 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
private static bool IsCompanyChestOpen()
|
private static bool IsCompanyChestOpen()
|
||||||
=> IsAddonVisibleAnyIndex(FreeCompanyChestAddonName);
|
=> IsAddonVisibleAnyIndex(FreeCompanyChestAddonName);
|
||||||
|
|
||||||
|
private static bool IsTradeOpen()
|
||||||
|
=> IsAddonVisibleAnyIndex("Trade") || IsAddonVisibleAnyIndex("TradeWindow");
|
||||||
|
|
||||||
private static bool IsCompanyChestType(FFXIVClientStructs.FFXIV.Client.Game.InventoryType inventoryType)
|
private static bool IsCompanyChestType(FFXIVClientStructs.FFXIV.Client.Game.InventoryType inventoryType)
|
||||||
{
|
{
|
||||||
var name = Enum.GetName(typeof(FFXIVClientStructs.FFXIV.Client.Game.InventoryType), inventoryType);
|
var name = Enum.GetName(typeof(FFXIVClientStructs.FFXIV.Client.Game.InventoryType), inventoryType);
|
||||||
@@ -5224,6 +5287,11 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
t.Equals("Sort", StringComparison.OrdinalIgnoreCase) ||
|
t.Equals("Sort", StringComparison.OrdinalIgnoreCase) ||
|
||||||
t.StartsWith("Sort", StringComparison.OrdinalIgnoreCase),
|
t.StartsWith("Sort", StringComparison.OrdinalIgnoreCase),
|
||||||
|
|
||||||
|
AutoContextAction.Trade =>
|
||||||
|
t.Equals("Trade", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
t.StartsWith("Trade", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
(Has(t, "Trade") && Has(t, "Item")),
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
<RootNamespace>QuickTransfer</RootNamespace>
|
<RootNamespace>QuickTransfer</RootNamespace>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<Version>1.0.3</Version>
|
<Version>1.0.4</Version>
|
||||||
<AssemblyVersion>1.0.3.0</AssemblyVersion>
|
<AssemblyVersion>1.0.4.0</AssemblyVersion>
|
||||||
<FileVersion>1.0.3.0</FileVersion>
|
<FileVersion>1.0.4.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Local builds: some setups have DALAMUD_HOME pointing at the XIVLauncher root,
|
<!-- Local builds: some setups have DALAMUD_HOME pointing at the XIVLauncher root,
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
"Author": "flick",
|
"Author": "flick",
|
||||||
"Name": "QuickTransfer",
|
"Name": "QuickTransfer",
|
||||||
"InternalName": "QuickTransfer",
|
"InternalName": "QuickTransfer",
|
||||||
"AssemblyVersion": "1.0.3.0",
|
"AssemblyVersion": "1.0.4.0",
|
||||||
"Description": "Automate inventory transfers with Shift/Ctrl/Alt + Right-Click.",
|
"Description": "Automate inventory transfers with Shift/Ctrl/Alt + Right-Click. Includes Trade window support.",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"RepoUrl": "https://github.com/Knack117/QuickTransfer",
|
"RepoUrl": "https://github.com/Knack117/QuickTransfer",
|
||||||
"Tags": [
|
"Tags": [
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@
|
|||||||
"Author": "flick",
|
"Author": "flick",
|
||||||
"Name": "QuickTransfer",
|
"Name": "QuickTransfer",
|
||||||
"InternalName": "QuickTransfer",
|
"InternalName": "QuickTransfer",
|
||||||
"AssemblyVersion": "1.0.3.0",
|
"AssemblyVersion": "1.0.4.0",
|
||||||
"Description": "Automate inventory transfers with Shift/Ctrl/Alt + Right-Click.",
|
"Description": "Automate inventory transfers with Shift/Ctrl/Alt + Right-Click. Includes Trade window support.",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"RepoUrl": "https://github.com/Knack117/QuickTransfer",
|
"RepoUrl": "https://github.com/Knack117/QuickTransfer",
|
||||||
"DalamudApiLevel": 14,
|
"DalamudApiLevel": 14,
|
||||||
|
|||||||
Reference in New Issue
Block a user