Merge branch 'main' into CykaFix
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UIFixes;
|
namespace UIFixes;
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ public static class ExtraItemProperties
|
|||||||
|
|
||||||
private class Properties
|
private class Properties
|
||||||
{
|
{
|
||||||
public bool Reordered;
|
public bool Reordered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool GetReordered(this Item item) => properties.GetOrCreateValue(item).Reordered;
|
public static bool GetReordered(this Item item) => properties.GetOrCreateValue(item).Reordered;
|
||||||
@@ -23,7 +24,7 @@ public static class ExtraTemplatedGridsViewProperties
|
|||||||
|
|
||||||
private class Properties
|
private class Properties
|
||||||
{
|
{
|
||||||
public bool Reordered;
|
public bool Reordered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool GetReordered(this TemplatedGridsView gridsView) => properties.GetOrCreateValue(gridsView).Reordered;
|
public static bool GetReordered(this TemplatedGridsView gridsView) => properties.GetOrCreateValue(gridsView).Reordered;
|
||||||
@@ -42,3 +43,47 @@ public static class ExtraTradingGridProperties
|
|||||||
public static bool GetShowOutOfStock(this TradingGridView gridView) => properties.GetOrCreateValue(gridView).ShowOutOfStock;
|
public static bool GetShowOutOfStock(this TradingGridView gridView) => properties.GetOrCreateValue(gridView).ShowOutOfStock;
|
||||||
public static void SetShowOutOfStock(this TradingGridView gridView, bool value) => properties.GetOrCreateValue(gridView).ShowOutOfStock = value;
|
public static void SetShowOutOfStock(this TradingGridView gridView, bool value) => properties.GetOrCreateValue(gridView).ShowOutOfStock = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ExtraRagfairOfferItemViewProperties
|
||||||
|
{
|
||||||
|
private static readonly ConditionalWeakTable<RagfairOfferItemView, Properties> properties = new();
|
||||||
|
|
||||||
|
private class Properties
|
||||||
|
{
|
||||||
|
public Vector2? SizeOverride = null;
|
||||||
|
public bool ShowCaption = false;
|
||||||
|
public string Inscription = null;
|
||||||
|
public string Count = null;
|
||||||
|
public string Tooltip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2? GetSizeOverride(this RagfairOfferItemView itemView) => properties.GetOrCreateValue(itemView).SizeOverride;
|
||||||
|
public static void SetSizeOverride(this RagfairOfferItemView itemView, Vector2 value) => properties.GetOrCreateValue(itemView).SizeOverride = value;
|
||||||
|
|
||||||
|
public static bool GetShowCaption(this RagfairOfferItemView itemView) => properties.GetOrCreateValue(itemView).ShowCaption;
|
||||||
|
public static void SetShowCaption(this RagfairOfferItemView itemView, bool value) => properties.GetOrCreateValue(itemView).ShowCaption = value;
|
||||||
|
|
||||||
|
public static string GetInscription(this RagfairOfferItemView itemView) => properties.GetOrCreateValue(itemView).Inscription;
|
||||||
|
public static void SetInscription(this RagfairOfferItemView itemView, string value) => properties.GetOrCreateValue(itemView).Inscription = value;
|
||||||
|
|
||||||
|
public static string GetCount(this RagfairOfferItemView itemView) => properties.GetOrCreateValue(itemView).Count;
|
||||||
|
public static void SetCount(this RagfairOfferItemView itemView, string value) => properties.GetOrCreateValue(itemView).Count = value;
|
||||||
|
|
||||||
|
public static string GetTooltip(this RagfairOfferItemView itemView) => properties.GetOrCreateValue(itemView).Tooltip;
|
||||||
|
public static void SetTooltip(this RagfairOfferItemView itemView, string value) => properties.GetOrCreateValue(itemView).Tooltip = value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExtraItemViewStatsProperties
|
||||||
|
{
|
||||||
|
private static readonly ConditionalWeakTable<ItemViewStats, Properties> properties = new();
|
||||||
|
|
||||||
|
private class Properties
|
||||||
|
{
|
||||||
|
public bool HideMods = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetHideMods(this ItemViewStats itemViewStats) => properties.GetOrCreateValue(itemViewStats).HideMods;
|
||||||
|
public static void SetHideMods(this ItemViewStats itemViewStats, bool value) => properties.GetOrCreateValue(itemViewStats).HideMods = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ global using DiscardResult = GClass2799;
|
|||||||
global using ItemSorter = GClass2772;
|
global using ItemSorter = GClass2772;
|
||||||
global using ItemWithLocation = GClass2521;
|
global using ItemWithLocation = GClass2521;
|
||||||
global using SearchableGrid = GClass2516;
|
global using SearchableGrid = GClass2516;
|
||||||
|
global using CursorManager = GClass3034;
|
||||||
|
|
||||||
// State machine states
|
// State machine states
|
||||||
global using FirearmReadyState = EFT.Player.FirearmController.GClass1619;
|
global using FirearmReadyState = EFT.Player.FirearmController.GClass1619;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Comfort.Common;
|
using BepInEx.Configuration;
|
||||||
|
using Comfort.Common;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
using System;
|
using System;
|
||||||
@@ -24,6 +25,8 @@ public class DrawMultiSelect : MonoBehaviour
|
|||||||
private bool drawing;
|
private bool drawing;
|
||||||
private bool secondary;
|
private bool secondary;
|
||||||
|
|
||||||
|
private static Vector2 Deadzone = new(5f, 5f);
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
selectTexture = new Texture2D(1, 1);
|
selectTexture = new Texture2D(1, 1);
|
||||||
@@ -56,37 +59,34 @@ public class DrawMultiSelect : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// checking ItemUiContext is a quick and easy way to know the mouse is over an item
|
if (Settings.SelectionBoxKey.Value.IsDownIgnoreOthers())
|
||||||
if (Input.GetKeyDown(Settings.SelectionBoxKey.Value.MainKey) && ItemUiContext.Instance.R().ItemContext == null)
|
|
||||||
{
|
{
|
||||||
PointerEventData eventData = new(EventSystem.current)
|
bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
|
||||||
{
|
|
||||||
position = Input.mousePosition
|
|
||||||
};
|
|
||||||
|
|
||||||
List<RaycastResult> results = [];
|
// Only need to check we aren't over draggables/clickables if the multiselect key is left mouse
|
||||||
localRaycaster.Raycast(eventData, results);
|
if (Settings.SelectionBoxKey.Value.MainKey == KeyCode.Mouse0 && !shiftDown && !MouseIsOverClickable())
|
||||||
preloaderRaycaster.Raycast(eventData, results);
|
|
||||||
|
|
||||||
foreach (GameObject gameObject in results.Select(r => r.gameObject))
|
|
||||||
{
|
|
||||||
var draggables = gameObject.GetComponents<MonoBehaviour>()
|
|
||||||
.Where(c => c is IDragHandler || c is IBeginDragHandler || c is TextMeshProUGUI) // tmp_inputfield is draggable, but textmesh isn't so explicitly include
|
|
||||||
.Where(c => c is not ScrollRectNoDrag) // this disables scrolling, it doesn't add it
|
|
||||||
.Where(c => c.name != "Inner"); // there's a random DragTrigger sitting in ItemInfoWindows
|
|
||||||
|
|
||||||
var clickables = gameObject.GetComponents<MonoBehaviour>()
|
|
||||||
.Where(c => c is IPointerClickHandler || c is IPointerDownHandler || c is IPointerUpHandler);
|
|
||||||
|
|
||||||
if (draggables.Any() || clickables.Any())
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
selectOrigin = Input.mousePosition;
|
selectOrigin = Input.mousePosition;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
secondary = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
|
secondary = shiftDown;
|
||||||
|
|
||||||
|
if (!secondary)
|
||||||
|
{
|
||||||
|
MultiSelect.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawing && !Settings.SelectionBoxKey.Value.IsPressedIgnoreOthers())
|
||||||
|
{
|
||||||
|
drawing = false;
|
||||||
|
if (secondary)
|
||||||
|
{
|
||||||
|
MultiSelect.CombineSecondary();
|
||||||
|
secondary = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawing)
|
if (drawing)
|
||||||
@@ -94,6 +94,10 @@ public class DrawMultiSelect : MonoBehaviour
|
|||||||
selectEnd = Input.mousePosition;
|
selectEnd = Input.mousePosition;
|
||||||
|
|
||||||
Rect selectRect = new(selectOrigin, selectEnd - selectOrigin);
|
Rect selectRect = new(selectOrigin, selectEnd - selectOrigin);
|
||||||
|
if (Mathf.Abs(selectRect.size.x) < Deadzone.x && Mathf.Abs(selectRect.size.y) < Deadzone.y)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If not secondary, then we can kick out any non-rendered items, plus they won't be covered by the foreach below
|
// If not secondary, then we can kick out any non-rendered items, plus they won't be covered by the foreach below
|
||||||
if (!secondary)
|
if (!secondary)
|
||||||
@@ -136,16 +140,6 @@ public class DrawMultiSelect : MonoBehaviour
|
|||||||
MultiSelect.Deselect(gridItemView, secondary);
|
MultiSelect.Deselect(gridItemView, secondary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawing && !Input.GetKey(Settings.SelectionBoxKey.Value.MainKey))
|
|
||||||
{
|
|
||||||
drawing = false;
|
|
||||||
if (secondary)
|
|
||||||
{
|
|
||||||
MultiSelect.CombineSecondary();
|
|
||||||
secondary = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGUI()
|
public void OnGUI()
|
||||||
@@ -171,6 +165,42 @@ public class DrawMultiSelect : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool MouseIsOverClickable()
|
||||||
|
{
|
||||||
|
// checking ItemUiContext is a quick and easy way to know the mouse is over an item
|
||||||
|
if (ItemUiContext.Instance.R().ItemContext != null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerEventData eventData = new(EventSystem.current)
|
||||||
|
{
|
||||||
|
position = Input.mousePosition
|
||||||
|
};
|
||||||
|
|
||||||
|
List<RaycastResult> results = [];
|
||||||
|
localRaycaster.Raycast(eventData, results);
|
||||||
|
preloaderRaycaster.Raycast(eventData, results);
|
||||||
|
|
||||||
|
foreach (GameObject gameObject in results.Select(r => r.gameObject))
|
||||||
|
{
|
||||||
|
var draggables = gameObject.GetComponents<MonoBehaviour>()
|
||||||
|
.Where(c => c is IDragHandler || c is IBeginDragHandler || c is TextMeshProUGUI) // tmp_inputfield is draggable, but textmesh isn't so explicitly include
|
||||||
|
.Where(c => c is not ScrollRectNoDrag) // this disables scrolling, it doesn't add it
|
||||||
|
.Where(c => c.name != "Inner"); // there's a random DragTrigger sitting in ItemInfoWindows
|
||||||
|
|
||||||
|
var clickables = gameObject.GetComponents<MonoBehaviour>()
|
||||||
|
.Where(c => c is IPointerClickHandler || c is IPointerDownHandler || c is IPointerUpHandler);
|
||||||
|
|
||||||
|
if (draggables.Any() || clickables.Any())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsOnTop(Rect itemRect, Transform itemTransform, GraphicRaycaster raycaster)
|
private bool IsOnTop(Rect itemRect, Transform itemTransform, GraphicRaycaster raycaster)
|
||||||
{
|
{
|
||||||
// Otherwise, ensure it's not overlapped by window UI
|
// Otherwise, ensure it's not overlapped by window UI
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ public class MultiSelect
|
|||||||
|
|
||||||
public static void OnKillItemView(GridItemView itemView)
|
public static void OnKillItemView(GridItemView itemView)
|
||||||
{
|
{
|
||||||
|
CombineSecondary();
|
||||||
|
|
||||||
MultiSelectItemContext itemContext = SelectedItems.FirstOrDefault(x => x.Value == itemView).Key;
|
MultiSelectItemContext itemContext = SelectedItems.FirstOrDefault(x => x.Value == itemView).Key;
|
||||||
if (itemContext != null)
|
if (itemContext != null)
|
||||||
{
|
{
|
||||||
@@ -140,6 +142,8 @@ public class MultiSelect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CombineSecondary();
|
||||||
|
|
||||||
MultiSelectItemContext itemContext = SelectedItems.FirstOrDefault(x => x.Key.Item == itemView.Item).Key;
|
MultiSelectItemContext itemContext = SelectedItems.FirstOrDefault(x => x.Key.Item == itemView.Item).Key;
|
||||||
if (itemContext != null)
|
if (itemContext != null)
|
||||||
{
|
{
|
||||||
@@ -158,6 +162,8 @@ public class MultiSelect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CombineSecondary();
|
||||||
|
|
||||||
MultiSelectItemContext oldItemContext = SelectedItems.FirstOrDefault(x => x.Key.Item == eventArgs.Item).Key;
|
MultiSelectItemContext oldItemContext = SelectedItems.FirstOrDefault(x => x.Key.Item == eventArgs.Item).Key;
|
||||||
if (oldItemContext != null)
|
if (oldItemContext != null)
|
||||||
{
|
{
|
||||||
@@ -221,7 +227,7 @@ public class MultiSelect
|
|||||||
|
|
||||||
public static bool Active
|
public static bool Active
|
||||||
{
|
{
|
||||||
get { return SelectedItems.Count > 0; }
|
get { return SelectedItems.Count > 0 || SecondaryItems.Count > 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one
|
// Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one
|
||||||
|
|||||||
@@ -69,6 +69,6 @@ public class MultiSelectDebug : MonoBehaviour
|
|||||||
LocationInGrid location = address is GridItemAddress gridAddress ? gridAddress.LocationInGrid : null;
|
LocationInGrid location = address is GridItemAddress gridAddress ? gridAddress.LocationInGrid : null;
|
||||||
string locationString = location != null ? $"({location.x}, {location.y})" : "(slot)";
|
string locationString = location != null ? $"({location.x}, {location.y})" : "(slot)";
|
||||||
|
|
||||||
return $"x{itemContext.Item.StackObjectsCount} {address.Container.ID} {locationString} {itemContext.Item.Name.Localized()}";
|
return $"x{itemContext.Item.StackObjectsCount} {(address != null ? address.Container.ID : "")} {locationString} {itemContext.Item.Name.Localized()}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
334
Patches/BarterOfferPatches.cs
Normal file
334
Patches/BarterOfferPatches.cs
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
using EFT;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI;
|
||||||
|
using EFT.UI.DragAndDrop;
|
||||||
|
using EFT.UI.Ragfair;
|
||||||
|
using HarmonyLib;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace UIFixes;
|
||||||
|
|
||||||
|
public static class BarterOfferPatches
|
||||||
|
{
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
new IconsPatch().Enable();
|
||||||
|
new ItemViewScalePatch().Enable();
|
||||||
|
new ItemUpdateInfoPatch().Enable();
|
||||||
|
new HideItemViewStatsPatch().Enable();
|
||||||
|
new OverrideGridItemViewTooltipPatch().Enable();
|
||||||
|
|
||||||
|
new NoPointerEnterPatch().Enable();
|
||||||
|
new NoPointerExitPatch().Enable();
|
||||||
|
new NoPointerClickPatch().Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IconsPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.DeclaredMethod(typeof(OfferItemPriceBarter), nameof(OfferItemPriceBarter.Show));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(
|
||||||
|
OfferItemPriceBarter __instance,
|
||||||
|
IExchangeRequirement requirement,
|
||||||
|
ItemTooltip tooltip,
|
||||||
|
Offer offer,
|
||||||
|
InventoryControllerClass inventoryController,
|
||||||
|
ItemUiContext itemUiContext,
|
||||||
|
InsuranceCompanyClass insuranceCompany,
|
||||||
|
int index,
|
||||||
|
bool expanded,
|
||||||
|
GameObject ____barterIcon,
|
||||||
|
TextMeshProUGUI ____requirementName,
|
||||||
|
GameObject ____separator)
|
||||||
|
{
|
||||||
|
if (!Settings.ShowBarterIcons.Value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requirement is not HandoverRequirement handoverRequirement)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDogtag = requirement.Item.GetItemComponent<DogtagComponent>() != null;
|
||||||
|
|
||||||
|
HorizontalOrVerticalLayoutGroup layoutGroup = __instance.transform.parent.GetComponent<HorizontalOrVerticalLayoutGroup>();
|
||||||
|
if (layoutGroup != null)
|
||||||
|
{
|
||||||
|
layoutGroup.spacing = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 smallSizeDelta = ____barterIcon.RectTransform().sizeDelta;
|
||||||
|
|
||||||
|
RagfairOfferItemView itemView = ItemViewFactory.CreateFromPool<RagfairOfferItemView>("ragfair_offer_layout");
|
||||||
|
itemView.transform.SetParent(__instance.transform, false);
|
||||||
|
if (!expanded)
|
||||||
|
{
|
||||||
|
itemView.SetSizeOverride(smallSizeDelta);
|
||||||
|
|
||||||
|
ItemViewStats itemViewStats = itemView.GetComponent<ItemViewStats>();
|
||||||
|
itemViewStats.SetHideMods(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isDogtag)
|
||||||
|
{
|
||||||
|
if (handoverRequirement.Side != EDogtagExchangeSide.Any)
|
||||||
|
{
|
||||||
|
itemView.SetShowCaption(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.SetInscription("LVLKILLLIST".Localized() + " " + handoverRequirement.Level);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ownedCount = GetOwnedCount(requirement, inventoryController);
|
||||||
|
itemView.SetCount(string.Format("<color=#{2}><b>{0}</b></color>/{1}", ownedCount.FormatSeparate(" "), requirement.IntCount.FormatSeparate(" "), "C5C3B2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDogtag)
|
||||||
|
{
|
||||||
|
itemView.SetTooltip(string.Concat(
|
||||||
|
[
|
||||||
|
"Dogtag".Localized(),
|
||||||
|
" ≥ ",
|
||||||
|
handoverRequirement.Level,
|
||||||
|
" ",
|
||||||
|
"LVLKILLLIST".Localized(),
|
||||||
|
(handoverRequirement.Side != EDogtagExchangeSide.Any ? ", " + handoverRequirement.Side : "").ToUpper()
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 sizeDelta = expanded ? new Vector2(64f, 64f) : smallSizeDelta;
|
||||||
|
LayoutElement layoutElement = itemView.GetComponent<LayoutElement>();
|
||||||
|
layoutElement.preferredWidth = layoutElement.minWidth = sizeDelta.x;
|
||||||
|
layoutElement.preferredHeight = layoutElement.minHeight = sizeDelta.y;
|
||||||
|
|
||||||
|
itemView.Show(null, requirement.Item, ItemRotation.Horizontal, false, inventoryController, requirement.Item.Owner, itemUiContext, null);
|
||||||
|
|
||||||
|
ItemViewManager itemViewManager = __instance.GetOrAddComponent<ItemViewManager>();
|
||||||
|
itemViewManager.Init(itemView);
|
||||||
|
|
||||||
|
____barterIcon.SetActive(false);
|
||||||
|
____separator?.SetActive(false);
|
||||||
|
|
||||||
|
if (expanded)
|
||||||
|
{
|
||||||
|
____requirementName.transform.parent.gameObject.SetActive(false); // The name and the ? icon
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
____requirementName.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetOwnedCount(IExchangeRequirement requirement, InventoryControllerClass inventoryController)
|
||||||
|
{
|
||||||
|
List<Item> allItems = [];
|
||||||
|
inventoryController.Inventory.Stash.GetAllAssembledItemsNonAlloc(allItems);
|
||||||
|
inventoryController.Inventory.QuestStashItems.GetAllAssembledItemsNonAlloc(allItems);
|
||||||
|
inventoryController.Inventory.QuestRaidItems.GetAllAssembledItemsNonAlloc(allItems);
|
||||||
|
|
||||||
|
if (requirement is not HandoverRequirement handoverRequirement)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requirement.Item.GetItemComponent<DogtagComponent>() != null)
|
||||||
|
{
|
||||||
|
return allItems.Where(item => RagFairClass.CanUseForBarterExchange(item, out string error))
|
||||||
|
.Select(item => item.GetItemComponent<DogtagComponent>())
|
||||||
|
.Where(dogtag => dogtag != null)
|
||||||
|
.Where(dogtag => dogtag.Level >= handoverRequirement.Level)
|
||||||
|
.Where(dogtag => handoverRequirement.Side == EDogtagExchangeSide.Any || dogtag.Side.ToString() == handoverRequirement.Side.ToString())
|
||||||
|
.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
return allItems.Where(item => RagFairClass.CanUseForBarterExchange(item, out string error))
|
||||||
|
.Where(item => item.TemplateId == requirement.Item.TemplateId)
|
||||||
|
.Where(item => !requirement.OnlyFunctional || item is not LootItemClass lootItem || !lootItem.MissingVitalParts.Any())
|
||||||
|
.Where(item => item is not GInterface325 encodable || requirement.Item is not GInterface325 || encodable.IsEncoded() == requirement.IsEncoded)
|
||||||
|
.Sum(item => item.StackObjectsCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemViewScalePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.DeclaredMethod(typeof(RagfairOfferItemView), nameof(RagfairOfferItemView.UpdateScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(RagfairOfferItemView __instance, Image ___MainImage)
|
||||||
|
{
|
||||||
|
Vector2? sizeOverride = __instance.GetSizeOverride();
|
||||||
|
if (sizeOverride.HasValue)
|
||||||
|
{
|
||||||
|
Vector2 sizeDelta = ___MainImage.rectTransform.sizeDelta;
|
||||||
|
float x = sizeDelta.x;
|
||||||
|
float y = sizeDelta.y;
|
||||||
|
|
||||||
|
// Calculate scale and multiply to preserve aspect ratio
|
||||||
|
float scale = Mathf.Min((float)sizeOverride.Value.x / x, (float)sizeOverride.Value.y / y);
|
||||||
|
___MainImage.rectTransform.sizeDelta = new Vector2(x * scale, y * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemUpdateInfoPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.DeclaredMethod(typeof(RagfairOfferItemView), nameof(RagfairOfferItemView.UpdateInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(RagfairOfferItemView __instance, TextMeshProUGUI ___Caption, TextMeshProUGUI ___ItemInscription, TextMeshProUGUI ___ItemValue)
|
||||||
|
{
|
||||||
|
if (__instance.GetShowCaption())
|
||||||
|
{
|
||||||
|
___Caption.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
string inscription = __instance.GetInscription();
|
||||||
|
if (!string.IsNullOrEmpty(inscription))
|
||||||
|
{
|
||||||
|
___ItemInscription.text = inscription;
|
||||||
|
___ItemInscription.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
string value = __instance.GetCount();
|
||||||
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
___ItemValue.text = value;
|
||||||
|
___ItemValue.fontSize = 16f;
|
||||||
|
___ItemValue.alignment = TextAlignmentOptions.Left;
|
||||||
|
|
||||||
|
RectTransform rectTransform = ___ItemValue.RectTransform();
|
||||||
|
rectTransform.pivot = new Vector2(0f, 0.5f);
|
||||||
|
rectTransform.anchorMin = rectTransform.anchorMax = new Vector2(1f, 0.5f);
|
||||||
|
rectTransform.anchoredPosition = new Vector2(5f, 0f);
|
||||||
|
___ItemValue.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OverrideGridItemViewTooltipPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.DeclaredMethod(typeof(GridItemView), nameof(GridItemView.ShowTooltip));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(GridItemView __instance, ItemUiContext ___ItemUiContext)
|
||||||
|
{
|
||||||
|
if (__instance is not RagfairOfferItemView ragfairOfferItemView)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string tooltip = ragfairOfferItemView.GetTooltip();
|
||||||
|
if (!string.IsNullOrEmpty(tooltip))
|
||||||
|
{
|
||||||
|
___ItemUiContext.Tooltip.Show(tooltip, null, 0.5f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HideItemViewStatsPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemViewStats), nameof(ItemViewStats.SetStaticInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(ItemViewStats __instance, Image ____modIcon, Image ____modTypeIcon, Image ____specialIcon, Image ____armorClassIcon)
|
||||||
|
{
|
||||||
|
if (!__instance.GetHideMods())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
____modIcon.gameObject.SetActive(false);
|
||||||
|
____modTypeIcon.gameObject.SetActive(false);
|
||||||
|
____specialIcon.gameObject.SetActive(false);
|
||||||
|
____armorClassIcon?.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoPointerEnterPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(OfferItemPriceBarter), nameof(OfferItemPriceBarter.OnPointerEnter));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
return !Settings.ShowBarterIcons.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoPointerExitPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(OfferItemPriceBarter), nameof(OfferItemPriceBarter.OnPointerExit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
return !Settings.ShowBarterIcons.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoPointerClickPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(OfferItemPriceBarter), nameof(OfferItemPriceBarter.OnPointerClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
return !Settings.ShowBarterIcons.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemViewManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
RagfairOfferItemView itemView;
|
||||||
|
|
||||||
|
public void Init(RagfairOfferItemView itemView)
|
||||||
|
{
|
||||||
|
this.itemView = itemView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
itemView.IsStub = true;
|
||||||
|
itemView.Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -192,15 +192,22 @@ public static class ContextMenuPatches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(R.TradingInteractions.Type, "get_SubInteractions");
|
return AccessTools.PropertyGetter(
|
||||||
|
typeof(ItemInfoInteractionsAbstractClass<EItemInfoButton>),
|
||||||
|
nameof(ItemInfoInteractionsAbstractClass<EItemInfoButton>.SubInteractions));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void Postfix(ref IEnumerable<EItemInfoButton> __result)
|
public static void Postfix(
|
||||||
|
ItemInfoInteractionsAbstractClass<EItemInfoButton> __instance,
|
||||||
|
ref IEnumerable<EItemInfoButton> __result)
|
||||||
|
{
|
||||||
|
if (R.TradingInteractions.Type.IsInstanceOfType(__instance))
|
||||||
{
|
{
|
||||||
__result = __result.Append(EItemInfoButton.Repair).Append(EItemInfoButton.Insure);
|
__result = __result.Append(EItemInfoButton.Repair).Append(EItemInfoButton.Insure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class CreateSubInteractionsTradingPatch : ModulePatch
|
public class CreateSubInteractionsTradingPatch : ModulePatch
|
||||||
{
|
{
|
||||||
@@ -208,12 +215,23 @@ public static class ContextMenuPatches
|
|||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(R.TradingInteractions.Type, "CreateSubInteractions");
|
return AccessTools.Method(
|
||||||
|
typeof(ItemInfoInteractionsAbstractClass<EItemInfoButton>),
|
||||||
|
nameof(ItemInfoInteractionsAbstractClass<EItemInfoButton>.CreateSubInteractions));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(object __instance, EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, ItemUiContext ___itemUiContext_0)
|
public static bool Prefix(
|
||||||
|
ItemInfoInteractionsAbstractClass<EItemInfoButton> __instance,
|
||||||
|
EItemInfoButton parentInteraction,
|
||||||
|
ISubInteractions subInteractionsWrapper,
|
||||||
|
ItemUiContext ___itemUiContext_0)
|
||||||
{
|
{
|
||||||
|
if (!R.TradingInteractions.Type.IsInstanceOfType(__instance))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear this, since something else should be active (even a different mouseover of the insurance button)
|
// Clear this, since something else should be active (even a different mouseover of the insurance button)
|
||||||
LoadingInsuranceActions = false;
|
LoadingInsuranceActions = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using EFT.InventoryLogic;
|
using Comfort.Common;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using SPT.Reflection.Patching;
|
using SPT.Reflection.Patching;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
namespace UIFixes;
|
namespace UIFixes;
|
||||||
@@ -19,7 +19,6 @@ public static class ContextMenuShortcutPatches
|
|||||||
new ItemUiContextPatch().Enable();
|
new ItemUiContextPatch().Enable();
|
||||||
|
|
||||||
new HideoutItemViewRegisterContextPatch().Enable();
|
new HideoutItemViewRegisterContextPatch().Enable();
|
||||||
new HideoutItemViewUnegisterContextPatch().Enable();
|
|
||||||
|
|
||||||
new TradingPanelRegisterContextPatch().Enable();
|
new TradingPanelRegisterContextPatch().Enable();
|
||||||
new TradingPanelUnregisterContextPatch().Enable();
|
new TradingPanelUnregisterContextPatch().Enable();
|
||||||
@@ -76,12 +75,12 @@ public static class ContextMenuShortcutPatches
|
|||||||
|
|
||||||
if (Settings.UseAllKeyBind.Value.IsDown())
|
if (Settings.UseAllKeyBind.Value.IsDown())
|
||||||
{
|
{
|
||||||
TryInteraction(__instance, itemContext, EItemInfoButton.UseAll, EItemInfoButton.Use);
|
TryInteraction(__instance, itemContext, EItemInfoButton.UseAll, [EItemInfoButton.Use]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.UnloadKeyBind.Value.IsDown())
|
if (Settings.UnloadKeyBind.Value.IsDown())
|
||||||
{
|
{
|
||||||
TryInteraction(__instance, itemContext, EItemInfoButton.Unload, EItemInfoButton.UnloadAmmo);
|
TryInteraction(__instance, itemContext, EItemInfoButton.Unload, [EItemInfoButton.UnloadAmmo]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.UnpackKeyBind.Value.IsDown())
|
if (Settings.UnpackKeyBind.Value.IsDown())
|
||||||
@@ -99,15 +98,62 @@ public static class ContextMenuShortcutPatches
|
|||||||
TryInteraction(__instance, itemContext, EItemInfoButton.LinkedSearch);
|
TryInteraction(__instance, itemContext, EItemInfoButton.LinkedSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings.SortingTableKeyBind.Value.IsDown())
|
||||||
|
{
|
||||||
|
MoveToFromSortingTable(itemContext, __instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.ExamineKeyBind.Value.IsDown())
|
||||||
|
{
|
||||||
|
TryInteraction(__instance, itemContext, EItemInfoButton.Examine,
|
||||||
|
[EItemInfoButton.Fold, EItemInfoButton.Unfold, EItemInfoButton.TurnOn, EItemInfoButton.TurnOff, EItemInfoButton.CheckMagazine]);
|
||||||
|
}
|
||||||
|
|
||||||
Interactions = null;
|
Interactions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TryInteraction(ItemUiContext itemUiContext, ItemContextAbstractClass itemContext, EItemInfoButton interaction, EItemInfoButton? fallbackInteraction = null)
|
private static void TryInteraction(ItemUiContext itemUiContext, ItemContextAbstractClass itemContext, EItemInfoButton interaction, EItemInfoButton[] fallbackInteractions = null)
|
||||||
{
|
{
|
||||||
Interactions ??= itemUiContext.GetItemContextInteractions(itemContext, null);
|
Interactions ??= itemUiContext.GetItemContextInteractions(itemContext, null);
|
||||||
if (!Interactions.ExecuteInteraction(interaction) && fallbackInteraction.HasValue)
|
if (!Interactions.ExecuteInteraction(interaction) && fallbackInteractions != null)
|
||||||
{
|
{
|
||||||
Interactions.ExecuteInteraction(fallbackInteraction.Value);
|
foreach (var fallbackInteraction in fallbackInteractions)
|
||||||
|
{
|
||||||
|
if (Interactions.ExecuteInteraction(fallbackInteraction))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveToFromSortingTable(ItemContextAbstractClass itemContext, ItemUiContext itemUiContext)
|
||||||
|
{
|
||||||
|
Item item = itemContext.Item;
|
||||||
|
if (item.Owner is not InventoryControllerClass controller)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SortingTableClass sortingTable = controller.Inventory.SortingTable;
|
||||||
|
bool isInSortingTable = sortingTable != null && item.Parent.Container.ParentItem == sortingTable;
|
||||||
|
|
||||||
|
var operation = isInSortingTable ? itemUiContext.QuickFindAppropriatePlace(itemContext, controller, false, true, true) : itemUiContext.QuickMoveToSortingTable(item, true);
|
||||||
|
if (operation.Succeeded && controller.CanExecute(operation.Value))
|
||||||
|
{
|
||||||
|
if (operation.Value is IDestroyResult destroyResult && destroyResult.ItemsDestroyRequired)
|
||||||
|
{
|
||||||
|
NotificationManagerClass.DisplayWarningNotification(new DestroyError(item, destroyResult.ItemsToDestroy).GetLocalizedDescription());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.RunNetworkTransaction(operation.Value, null);
|
||||||
|
if (itemUiContext.Tooltip != null)
|
||||||
|
{
|
||||||
|
itemUiContext.Tooltip.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Singleton<GUISounds>.Instance.PlayItemSound(item.ItemSound, EInventorySoundType.pickup, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,20 +173,6 @@ public static class ContextMenuShortcutPatches
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HideoutItemViewUnegisterContextPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(HideoutItemView), nameof(HideoutItemView.OnPointerExit));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
public static void Postfix(HideoutItemView __instance, ItemUiContext ___ItemUiContext)
|
|
||||||
{
|
|
||||||
___ItemUiContext.UnregisterCurrentItemContext(__instance.ItemContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TradingPanelRegisterContextPatch : ModulePatch
|
public class TradingPanelRegisterContextPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using EFT.UI.Ragfair;
|
using EFT.UI;
|
||||||
|
using EFT.UI.Ragfair;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using SPT.Reflection.Patching;
|
using SPT.Reflection.Patching;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -12,12 +14,15 @@ public static class FixFleaPatches
|
|||||||
{
|
{
|
||||||
public static void Enable()
|
public static void Enable()
|
||||||
{
|
{
|
||||||
// These two are anal AF
|
// These are anal AF
|
||||||
new DoNotToggleOnMouseOverPatch().Enable();
|
new DoNotToggleOnMouseOverPatch().Enable();
|
||||||
new ToggleOnOpenPatch().Enable();
|
new ToggleOnOpenPatch().Enable();
|
||||||
|
new DropdownHeightPatch().Enable();
|
||||||
|
|
||||||
new OfferItemFixMaskPatch().Enable();
|
new OfferItemFixMaskPatch().Enable();
|
||||||
new OfferViewTweaksPatch().Enable();
|
new OfferViewTweaksPatch().Enable();
|
||||||
|
|
||||||
|
new SearchPatch().Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DoNotToggleOnMouseOverPatch : ModulePatch
|
public class DoNotToggleOnMouseOverPatch : ModulePatch
|
||||||
@@ -95,4 +100,57 @@ public static class FixFleaPatches
|
|||||||
timeLeft.childControlWidth = false;
|
timeLeft.childControlWidth = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SearchPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(RagfairCategoriesPanel), nameof(RagfairCategoriesPanel.method_9));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(RagfairCategoriesPanel __instance, string arg)
|
||||||
|
{
|
||||||
|
if (!Settings.ClearFiltersOnSearch.Value)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.StartsWith("#") || __instance.Ragfair == null || __instance.EViewListType_0 != EViewListType.AllOffers)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.FilteredNodes.Values.Sum(node => node.Count) > 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__instance.Ragfair.CancellableFilters.Clear();
|
||||||
|
|
||||||
|
FilterRule filterRule = __instance.Ragfair.method_3(EViewListType.AllOffers);
|
||||||
|
filterRule.HandbookId = string.Empty;
|
||||||
|
|
||||||
|
__instance.Ragfair.AddSearchesInRule(filterRule, true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DropdownHeightPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.DeclaredMethod(typeof(DropDownBox), nameof(DropDownBox.Init));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(ref float ____maxVisibleHeight)
|
||||||
|
{
|
||||||
|
if (____maxVisibleHeight == 120f)
|
||||||
|
{
|
||||||
|
____maxVisibleHeight = 240f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public static class MultiSelectPatches
|
|||||||
// Used to prevent infinite recursion of CanAccept/AcceptItem
|
// Used to prevent infinite recursion of CanAccept/AcceptItem
|
||||||
private static bool InPatch = false;
|
private static bool InPatch = false;
|
||||||
|
|
||||||
// If the CanAccept method should render highlights
|
// Keep track of preview images when dragging
|
||||||
private static readonly List<Image> Previews = [];
|
private static readonly List<Image> Previews = [];
|
||||||
|
|
||||||
// Point that various QuickFindPlace overrides should start at
|
// Point that various QuickFindPlace overrides should start at
|
||||||
@@ -150,7 +150,7 @@ public static class MultiSelectPatches
|
|||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void Postfix(ItemView __instance, PointerEventData eventData)
|
public static void Postfix(ItemView __instance, PointerEventData eventData, TraderControllerClass ___ItemController)
|
||||||
{
|
{
|
||||||
if (!MultiSelect.Enabled || __instance is RagfairNewOfferItemView || __instance is InsuranceItemView)
|
if (!MultiSelect.Enabled || __instance is RagfairNewOfferItemView || __instance is InsuranceItemView)
|
||||||
{
|
{
|
||||||
@@ -161,12 +161,36 @@ public static class MultiSelectPatches
|
|||||||
bool shiftDown = Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift);
|
bool shiftDown = Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift);
|
||||||
bool altDown = Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt);
|
bool altDown = Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt);
|
||||||
|
|
||||||
if (Settings.EnableMultiClick.Value && __instance is GridItemView gridItemView && eventData.button == PointerEventData.InputButton.Left && shiftDown && !ctrlDown && !altDown)
|
// If sorting table is open and default shift-click behavior is enabled, don't multiselect
|
||||||
|
bool couldBeSortingTableMove = false;
|
||||||
|
if (Settings.DefaultSortingTableBind.Value &&
|
||||||
|
shiftDown &&
|
||||||
|
eventData.button == PointerEventData.InputButton.Left &&
|
||||||
|
___ItemController is InventoryControllerClass inventoryController)
|
||||||
|
{
|
||||||
|
SortingTableClass sortingTable = inventoryController.Inventory.SortingTable;
|
||||||
|
if (sortingTable != null && sortingTable.IsVisible)
|
||||||
|
{
|
||||||
|
couldBeSortingTableMove = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.EnableMultiClick.Value &&
|
||||||
|
!couldBeSortingTableMove &&
|
||||||
|
__instance is GridItemView gridItemView &&
|
||||||
|
eventData.button == PointerEventData.InputButton.Left &&
|
||||||
|
shiftDown && !ctrlDown && !altDown)
|
||||||
{
|
{
|
||||||
MultiSelect.Toggle(gridItemView);
|
MultiSelect.Toggle(gridItemView);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mainly this tests for when selection box is rebound to another mouse button, to enable secondary selection
|
||||||
|
if (!couldBeSortingTableMove && shiftDown && Settings.SelectionBoxKey.Value.IsDownIgnoreOthers())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (__instance is not GridItemView gridItemView2 || !MultiSelect.IsSelected(gridItemView2))
|
if (__instance is not GridItemView gridItemView2 || !MultiSelect.IsSelected(gridItemView2))
|
||||||
{
|
{
|
||||||
MultiSelect.Clear();
|
MultiSelect.Clear();
|
||||||
@@ -211,9 +235,14 @@ public static class MultiSelectPatches
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shiftDown)
|
if (shiftDown && !ctrlDown && !altDown)
|
||||||
{
|
{
|
||||||
// Nothing to do, mousedown handled it.
|
if (Settings.DefaultSortingTableBind.Value)
|
||||||
|
{
|
||||||
|
QuickMove(__instance, ___ItemUiContext, ___ItemController, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,15 +251,17 @@ public static class MultiSelectPatches
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void QuickMove(GridItemView gridItemView, ItemUiContext itemUiContext, TraderControllerClass itemController)
|
private static void QuickMove(GridItemView gridItemView, ItemUiContext itemUiContext, TraderControllerClass itemController, bool moveToSortingTable = false)
|
||||||
{
|
{
|
||||||
bool succeeded = true;
|
bool succeeded = true;
|
||||||
DisableMerge = true;
|
DisableMerge = true;
|
||||||
IgnoreItemParent = true;
|
IgnoreItemParent = true;
|
||||||
Stack<ItemOperation> operations = new();
|
Stack<ItemOperation> operations = new();
|
||||||
foreach (DragItemContext selectedItemContext in MultiSelect.SortedItemContexts())
|
foreach (var selectedItemContext in MultiSelect.SortedItemContexts())
|
||||||
{
|
{
|
||||||
ItemOperation operation = itemUiContext.QuickFindAppropriatePlace(selectedItemContext, itemController, false /*forceStash*/, false /*showWarnings*/, false /*simulate*/);
|
ItemOperation operation = moveToSortingTable ?
|
||||||
|
itemUiContext.QuickMoveToSortingTable(selectedItemContext.Item, false /*simulate*/) :
|
||||||
|
itemUiContext.QuickFindAppropriatePlace(selectedItemContext, itemController, false /*forceStash*/, false /*showWarnings*/, false /*simulate*/);
|
||||||
if (operation.Succeeded && itemController.CanExecute(operation.Value))
|
if (operation.Succeeded && itemController.CanExecute(operation.Value))
|
||||||
{
|
{
|
||||||
operations.Push(operation);
|
operations.Push(operation);
|
||||||
@@ -434,6 +465,13 @@ public static class MultiSelectPatches
|
|||||||
return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnBeginDrag));
|
return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnBeginDrag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
// Disable drag if shift is down
|
||||||
|
return !Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift);
|
||||||
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void Postfix(ItemView __instance)
|
public static void Postfix(ItemView __instance)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
using Comfort.Common;
|
|
||||||
using EFT.UI;
|
|
||||||
using HarmonyLib;
|
|
||||||
using SPT.Reflection.Patching;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace UIFixes;
|
|
||||||
|
|
||||||
public class OpenSortingTablePatch : ModulePatch
|
|
||||||
{
|
|
||||||
private static readonly EItemUiContextType[] AllowedScreens = [EItemUiContextType.InventoryScreen, EItemUiContextType.ScavengerInventoryScreen];
|
|
||||||
|
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(ItemUiContext), nameof(ItemUiContext.QuickMoveToSortingTable));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPrefix]
|
|
||||||
public static bool Prefix(ItemUiContext __instance, ref ItemOperation __result)
|
|
||||||
{
|
|
||||||
// BSG checks visibility, not in-raid. There's a bug where somehow that visibility can be true in raid
|
|
||||||
if (Plugin.InRaid())
|
|
||||||
{
|
|
||||||
__result = new GClass3370("SortingTable/VisibilityError");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Settings.AutoOpenSortingTable.Value || !AllowedScreens.Contains(__instance.ContextType))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary work-around for LootValue bug - bail out if the ALT key is down
|
|
||||||
if (Input.GetKey(KeyCode.LeftAlt))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SortingTableClass sortingTable = __instance.R().InventoryController.Inventory.SortingTable;
|
|
||||||
if (sortingTable != null && !sortingTable.IsVisible)
|
|
||||||
{
|
|
||||||
if (__instance.ContextType == EItemUiContextType.InventoryScreen)
|
|
||||||
{
|
|
||||||
Singleton<CommonUI>.Instance.InventoryScreen.method_6();
|
|
||||||
Singleton<CommonUI>.Instance.InventoryScreen.R().SimpleStashPanel.ChangeSortingTableTabState(true);
|
|
||||||
}
|
|
||||||
else if (__instance.ContextType == EItemUiContextType.ScavengerInventoryScreen)
|
|
||||||
{
|
|
||||||
Singleton<CommonUI>.Instance.ScavengerInventoryScreen.method_7();
|
|
||||||
Singleton<CommonUI>.Instance.ScavengerInventoryScreen.R().SimpleStashPanel.ChangeSortingTableTabState(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
98
Patches/OpenSortingTablePatches.cs
Normal file
98
Patches/OpenSortingTablePatches.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using Comfort.Common;
|
||||||
|
using EFT.UI;
|
||||||
|
using EFT.UI.DragAndDrop;
|
||||||
|
using HarmonyLib;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
|
namespace UIFixes;
|
||||||
|
|
||||||
|
public static class OpenSortingTablePatches
|
||||||
|
{
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
new AutoOpenPatch().Enable();
|
||||||
|
new DefaultBindPatch().Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AutoOpenPatch : ModulePatch
|
||||||
|
{
|
||||||
|
private static readonly EItemUiContextType[] AllowedScreens = [EItemUiContextType.InventoryScreen, EItemUiContextType.ScavengerInventoryScreen];
|
||||||
|
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemUiContext), nameof(ItemUiContext.QuickMoveToSortingTable));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(ItemUiContext __instance, ref ItemOperation __result)
|
||||||
|
{
|
||||||
|
// BSG checks visibility, not in-raid. There's a bug where somehow that visibility can be true in raid
|
||||||
|
if (Plugin.InRaid())
|
||||||
|
{
|
||||||
|
__result = new GClass3370("SortingTable/VisibilityError");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allowed screens only, and auto-open is enabled or the custom bind is active
|
||||||
|
if (!AllowedScreens.Contains(__instance.ContextType) || (!Settings.AutoOpenSortingTable.Value && !Settings.SortingTableKeyBind.Value.IsDown()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary work-around for LootValue bug - bail out if the ALT key is down
|
||||||
|
if (Input.GetKey(KeyCode.LeftAlt))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SortingTableClass sortingTable = __instance.R().InventoryController.Inventory.SortingTable;
|
||||||
|
if (sortingTable != null && !sortingTable.IsVisible)
|
||||||
|
{
|
||||||
|
if (__instance.ContextType == EItemUiContextType.InventoryScreen)
|
||||||
|
{
|
||||||
|
Singleton<CommonUI>.Instance.InventoryScreen.method_6();
|
||||||
|
Singleton<CommonUI>.Instance.InventoryScreen.R().SimpleStashPanel.ChangeSortingTableTabState(true);
|
||||||
|
}
|
||||||
|
else if (__instance.ContextType == EItemUiContextType.ScavengerInventoryScreen)
|
||||||
|
{
|
||||||
|
Singleton<CommonUI>.Instance.ScavengerInventoryScreen.method_7();
|
||||||
|
Singleton<CommonUI>.Instance.ScavengerInventoryScreen.R().SimpleStashPanel.ChangeSortingTableTabState(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DefaultBindPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(PointerEventData.InputButton button, bool doubleClick)
|
||||||
|
{
|
||||||
|
if (Settings.DefaultSortingTableBind.Value)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
|
||||||
|
bool altDown = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
|
||||||
|
bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
|
||||||
|
|
||||||
|
if (button == PointerEventData.InputButton.Left && !doubleClick && !ctrlDown && !altDown && shiftDown)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
156
Patches/ReloadInPlacePatches.cs
Normal file
156
Patches/ReloadInPlacePatches.cs
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
using EFT;
|
||||||
|
using EFT.UI;
|
||||||
|
using HarmonyLib;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace UIFixes;
|
||||||
|
|
||||||
|
public static class ReloadInPlacePatches
|
||||||
|
{
|
||||||
|
private static bool IsReloading = false;
|
||||||
|
private static MagazineClass FoundMagazine = null;
|
||||||
|
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
// These patch ItemUiContext.ReloadWeapon, which is called from the context menu Reload
|
||||||
|
new ReloadInPlacePatch().Enable();
|
||||||
|
new ReloadInPlaceFindMagPatch().Enable();
|
||||||
|
new ReloadInPlaceFindSpotPatch().Enable();
|
||||||
|
|
||||||
|
// This patches the firearmsController code when you hit R in raid with an external magazine class
|
||||||
|
new SwapIfNoSpacePatch().Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReloadInPlacePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemUiContext), nameof(ItemUiContext.ReloadWeapon));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void Prefix()
|
||||||
|
{
|
||||||
|
IsReloading = Settings.SwapMags.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
IsReloading = false;
|
||||||
|
FoundMagazine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReloadInPlaceFindMagPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemUiContext), nameof(ItemUiContext.method_5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(MagazineClass __result)
|
||||||
|
{
|
||||||
|
if (IsReloading)
|
||||||
|
{
|
||||||
|
FoundMagazine = __result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReloadInPlaceFindSpotPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
Type type = typeof(ItemUiContext).GetNestedTypes().Single(t => t.GetField("currentMagazine") != null);
|
||||||
|
return AccessTools.Method(type, "method_0");
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void Prefix(StashGridClass grid, ref GStruct414<GClass2801> __state)
|
||||||
|
{
|
||||||
|
if (!Settings.SwapMags.Value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grid.Contains(FoundMagazine))
|
||||||
|
{
|
||||||
|
__state = InteractionsHandlerClass.Remove(FoundMagazine, grid.ParentItem.Owner as TraderControllerClass, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(GStruct414<GClass2801> __state)
|
||||||
|
{
|
||||||
|
if (!Settings.SwapMags.Value || __state.Value == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__state.Succeeded)
|
||||||
|
{
|
||||||
|
__state.Value.RollBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SwapIfNoSpacePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(Player.FirearmController), nameof(Player.FirearmController.ReloadMag));
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default this method will do a series of removes and adds, but not swap, to reload
|
||||||
|
// This tied to a different animation state machine sequence than Swap(), and is faster than Swap.
|
||||||
|
// So only use Swap if *needed*, otherwise its penalizing all reload speeds
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(Player.FirearmController __instance, MagazineClass magazine, ItemAddressClass gridItemAddress)
|
||||||
|
{
|
||||||
|
// If gridItemAddress isn't null, it already found a place for the current mag, so let it run (unless always swap is enabled)
|
||||||
|
if (!Settings.SwapMags.Value || (gridItemAddress != null && !Settings.AlwaysSwapMags.Value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon doesn't currently have a magazine, let the default run (will load one)
|
||||||
|
MagazineClass currentMagazine = __instance.Weapon.GetCurrentMagazine();
|
||||||
|
if (currentMagazine == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryControllerClass controller = __instance.Weapon.Owner as InventoryControllerClass;
|
||||||
|
|
||||||
|
// Null address means it couldn't find a spot. Try to remove magazine (temporarily) and try again
|
||||||
|
var operation = InteractionsHandlerClass.Remove(magazine, controller, false, false);
|
||||||
|
if (operation.Failed)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gridItemAddress = controller.Inventory.Equipment.GetPrioritizedGridsForUnloadedObject(false)
|
||||||
|
.Select(grid => grid.FindLocationForItem(currentMagazine))
|
||||||
|
.Where(address => address != null)
|
||||||
|
.OrderBy(address => address.Grid.GridWidth.Value * address.Grid.GridHeight.Value)
|
||||||
|
.FirstOrDefault(); // BSG's version checks null again, but there's no nulls already. If there's no matches, the enumerable is empty
|
||||||
|
|
||||||
|
// Put the magazine back
|
||||||
|
operation.Value.RollBack();
|
||||||
|
|
||||||
|
if (gridItemAddress == null)
|
||||||
|
{
|
||||||
|
// Didn't work, nowhere to put magazine. Let it run (will drop mag on ground)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.TryRunNetworkTransaction(InteractionsHandlerClass.Swap(currentMagazine, gridItemAddress, magazine, new GClass2783(__instance.Weapon.GetMagazineSlot()), controller, true), null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,10 @@ public static class ScrollPatches
|
|||||||
new EnchanceTraderStashScrollingPatch().Enable();
|
new EnchanceTraderStashScrollingPatch().Enable();
|
||||||
new EnhanceFleaScrollingPatch().Enable();
|
new EnhanceFleaScrollingPatch().Enable();
|
||||||
new EnhanceMailScrollingPatch().Enable();
|
new EnhanceMailScrollingPatch().Enable();
|
||||||
|
|
||||||
new MouseScrollingSpeedPatch().Enable();
|
new MouseScrollingSpeedPatch().Enable();
|
||||||
|
new LightScrollerSpeedPatch().Enable();
|
||||||
|
|
||||||
new EnhanceHideoutScrollingPatch().Enable();
|
new EnhanceHideoutScrollingPatch().Enable();
|
||||||
new EnhanceTaskListScrollingPatch().Enable();
|
new EnhanceTaskListScrollingPatch().Enable();
|
||||||
new OpenLastTaskPatch().Enable();
|
new OpenLastTaskPatch().Enable();
|
||||||
@@ -305,6 +308,21 @@ public static class ScrollPatches
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LightScrollerSpeedPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(LightScroller), nameof(LightScroller.method_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void Prefix(ref float deltaPixels)
|
||||||
|
{
|
||||||
|
int multi = Settings.UseRaidMouseScrollMulti.Value && Plugin.InRaid() ? Settings.MouseScrollMultiInRaid.Value : Settings.MouseScrollMulti.Value;
|
||||||
|
deltaPixels *= multi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class EnhanceTaskListScrollingPatch : ModulePatch
|
public class EnhanceTaskListScrollingPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ public static class SortPatches
|
|||||||
{
|
{
|
||||||
Error error = null;
|
Error error = null;
|
||||||
var mergeableItems = lootItem.Grids.SelectMany(g => g.Items)
|
var mergeableItems = lootItem.Grids.SelectMany(g => g.Items)
|
||||||
.OfType<Stackable>()
|
|
||||||
.Where(i => i.StackObjectsCount < i.StackMaxSize)
|
.Where(i => i.StackObjectsCount < i.StackMaxSize)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -131,7 +130,7 @@ public static class SortPatches
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InteractionsHandlerClass.smethod_0(lootItem.Grids, item, out Stackable targetItem, 1))
|
if (Sorter.FindStackForMerge(lootItem.Grids, item, out Item targetItem, 1))
|
||||||
{
|
{
|
||||||
var operation = InteractionsHandlerClass.TransferOrMerge(item, targetItem, inventoryController, true);
|
var operation = InteractionsHandlerClass.TransferOrMerge(item, targetItem, inventoryController, true);
|
||||||
if (operation.Succeeded)
|
if (operation.Succeeded)
|
||||||
|
|||||||
@@ -27,44 +27,10 @@ public static class StackFirItemsPatches
|
|||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reimplementing this entire method to ignore SpawnedInSession for certain types
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(IEnumerable<EFT.InventoryLogic.IContainer> containersToPut, Item itemToMerge, ref object mergeableItem, int overrideCount, ref bool __result)
|
public static bool Prefix(IEnumerable<EFT.InventoryLogic.IContainer> containersToPut, Item itemToMerge, ref Item mergeableItem, int overrideCount, ref bool __result)
|
||||||
{
|
{
|
||||||
if (!MergeableItemType.IsInstanceOfType(itemToMerge))
|
__result = Sorter.FindStackForMerge(containersToPut, itemToMerge, out mergeableItem, overrideCount);
|
||||||
{
|
|
||||||
mergeableItem = null;
|
|
||||||
__result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overrideCount <= 0)
|
|
||||||
{
|
|
||||||
overrideCount = itemToMerge.StackObjectsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ignoreSpawnedInSession;
|
|
||||||
if (itemToMerge.Template is MoneyClass)
|
|
||||||
{
|
|
||||||
ignoreSpawnedInSession = Settings.MergeFIRMoney.Value;
|
|
||||||
}
|
|
||||||
else if (itemToMerge.Template is AmmoTemplate)
|
|
||||||
{
|
|
||||||
ignoreSpawnedInSession = Settings.MergeFIRAmmo.Value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ignoreSpawnedInSession = Settings.MergeFIROther.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeableItem = containersToPut.SelectMany(x => x.Items)
|
|
||||||
.Where(MergeableItemType.IsInstanceOfType)
|
|
||||||
.Where(x => x != itemToMerge)
|
|
||||||
.Where(x => x.TemplateId == itemToMerge.TemplateId)
|
|
||||||
.Where(x => ignoreSpawnedInSession || x.SpawnedInSession == itemToMerge.SpawnedInSession)
|
|
||||||
.Where(x => x.StackObjectsCount < x.StackMaxSize)
|
|
||||||
.FirstOrDefault(x => overrideCount <= x.StackMaxSize - x.StackObjectsCount);
|
|
||||||
|
|
||||||
__result = mergeableItem != null;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,19 +45,12 @@ public static class StackFirItemsPatches
|
|||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(Item __instance, Item other, ref bool __result)
|
public static bool Prefix(Item __instance, Item other, ref bool __result)
|
||||||
{
|
{
|
||||||
bool ignoreSpawnedInSession;
|
bool ignoreSpawnedInSession = __instance.Template switch
|
||||||
if (__instance.Template is MoneyClass)
|
|
||||||
{
|
{
|
||||||
ignoreSpawnedInSession = Settings.MergeFIRMoney.Value;
|
MoneyClass _ => Settings.MergeFIRMoney.Value,
|
||||||
}
|
AmmoTemplate _ => Settings.MergeFIRMoney.Value,
|
||||||
else if (__instance.Template is AmmoTemplate)
|
_ => Settings.MergeFIROther.Value,
|
||||||
{
|
};
|
||||||
ignoreSpawnedInSession = Settings.MergeFIRAmmo.Value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ignoreSpawnedInSession = Settings.MergeFIROther.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
__result = __instance.TemplateId == other.TemplateId && __instance.Id != other.Id && (ignoreSpawnedInSession || __instance.SpawnedInSession == other.SpawnedInSession);
|
__result = __instance.TemplateId == other.TemplateId && __instance.Id != other.Id && (ignoreSpawnedInSession || __instance.SpawnedInSession == other.SpawnedInSession);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using EFT.InventoryLogic;
|
|||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using SPT.Reflection.Patching;
|
using SPT.Reflection.Patching;
|
||||||
|
using SPT.Reflection.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,12 +14,17 @@ namespace UIFixes;
|
|||||||
|
|
||||||
public static class UnloadAmmoPatches
|
public static class UnloadAmmoPatches
|
||||||
{
|
{
|
||||||
|
private static UnloadAmmoBoxState UnloadState = null;
|
||||||
|
|
||||||
public static void Enable()
|
public static void Enable()
|
||||||
{
|
{
|
||||||
new TradingPlayerPatch().Enable();
|
new TradingPlayerPatch().Enable();
|
||||||
new TransferPlayerPatch().Enable();
|
new TransferPlayerPatch().Enable();
|
||||||
new UnloadScavTransferPatch().Enable();
|
new UnloadScavTransferPatch().Enable();
|
||||||
new NoScavStashPatch().Enable();
|
new NoScavStashPatch().Enable();
|
||||||
|
|
||||||
|
new UnloadAmmoBoxPatch().Enable();
|
||||||
|
new QuickFindUnloadAmmoBoxPatch().Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TradingPlayerPatch : ModulePatch
|
public class TradingPlayerPatch : ModulePatch
|
||||||
@@ -98,4 +104,97 @@ public static class UnloadAmmoPatches
|
|||||||
scavController.Inventory.Stash = null;
|
scavController.Inventory.Stash = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class UnloadAmmoBoxPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(ItemUiContext), nameof(ItemUiContext.UnloadAmmo));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void Prefix(Item item)
|
||||||
|
{
|
||||||
|
if (item is AmmoBox)
|
||||||
|
{
|
||||||
|
UnloadState = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
UnloadState = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QuickFindUnloadAmmoBoxPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(InteractionsHandlerClass), nameof(InteractionsHandlerClass.QuickFindAppropriatePlace));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void Prefix(Item item, TraderControllerClass controller, ref IEnumerable<LootItemClass> targets, ref InteractionsHandlerClass.EMoveItemOrder order)
|
||||||
|
{
|
||||||
|
if (UnloadState == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AmmoBox box = item.Parent.Container.ParentItem as AmmoBox;
|
||||||
|
if (box == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ammo boxes with multiple stacks will loop through this code, so we only want to move the box once
|
||||||
|
if (UnloadState.initialized)
|
||||||
|
{
|
||||||
|
order = UnloadState.order;
|
||||||
|
targets = UnloadState.targets;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Have to do this for them, since the calls to get parent will be wrong once we move the box
|
||||||
|
if (!order.HasFlag(InteractionsHandlerClass.EMoveItemOrder.IgnoreItemParent))
|
||||||
|
{
|
||||||
|
LootItemClass parent = (item.GetNotMergedParent() as LootItemClass) ?? (item.GetRootMergedItem() as EquipmentClass);
|
||||||
|
if (parent != null)
|
||||||
|
{
|
||||||
|
UnloadState.targets = targets = order.HasFlag(InteractionsHandlerClass.EMoveItemOrder.PrioritizeParent) ?
|
||||||
|
parent.ToEnumerable().Concat(targets).Distinct() :
|
||||||
|
targets.Concat(parent.ToEnumerable()).Distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnloadState.order = order |= InteractionsHandlerClass.EMoveItemOrder.IgnoreItemParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
var operation = InteractionsHandlerClass.Move(box, UnloadState.fakeStash.Grid.FindLocationForItem(box), controller, false);
|
||||||
|
operation.Value.RaiseEvents(controller, CommandStatus.Begin);
|
||||||
|
operation.Value.RaiseEvents(controller, CommandStatus.Succeed);
|
||||||
|
|
||||||
|
UnloadState.initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnloadAmmoBoxState
|
||||||
|
{
|
||||||
|
public StashClass fakeStash;
|
||||||
|
public TraderControllerClass fakeController;
|
||||||
|
|
||||||
|
public bool initialized;
|
||||||
|
public InteractionsHandlerClass.EMoveItemOrder order;
|
||||||
|
public IEnumerable<LootItemClass> targets;
|
||||||
|
|
||||||
|
public UnloadAmmoBoxState()
|
||||||
|
{
|
||||||
|
fakeStash = (StashClass)Singleton<ItemFactory>.Instance.CreateItem("FakeStash", "566abbc34bdc2d92178b4576", null);
|
||||||
|
|
||||||
|
var profile = PatchConstants.BackEndSession.Profile;
|
||||||
|
fakeController = new(fakeStash, profile.ProfileId, profile.Nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
Patches/UnlockCursorPatch.cs
Normal file
33
Patches/UnlockCursorPatch.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UIFixes;
|
||||||
|
|
||||||
|
public class UnlockCursorPatch : ModulePatch
|
||||||
|
{
|
||||||
|
private static readonly FullScreenMode[] WindowedModes = [FullScreenMode.Windowed, FullScreenMode.MaximizedWindow, FullScreenMode.FullScreenWindow];
|
||||||
|
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(CursorManager), nameof(CursorManager.SetCursorLockMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool Prefix(bool cursorVisible, FullScreenMode fullscreenMode, Action ___action_0)
|
||||||
|
{
|
||||||
|
Cursor.lockState = cursorVisible ?
|
||||||
|
Settings.UnlockCursor.Value && WindowedModes.Contains(fullscreenMode) ? CursorLockMode.None : CursorLockMode.Confined :
|
||||||
|
CursorLockMode.Locked;
|
||||||
|
|
||||||
|
if (___action_0 != null)
|
||||||
|
{
|
||||||
|
___action_0();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,7 +47,7 @@ public class Plugin : BaseUnityPlugin
|
|||||||
new LoadMagPresetsPatch().Enable();
|
new LoadMagPresetsPatch().Enable();
|
||||||
KeepWindowsOnScreenPatches.Enable();
|
KeepWindowsOnScreenPatches.Enable();
|
||||||
ContextMenuShortcutPatches.Enable();
|
ContextMenuShortcutPatches.Enable();
|
||||||
new OpenSortingTablePatch().Enable();
|
OpenSortingTablePatches.Enable();
|
||||||
LoadAmmoInRaidPatches.Enable();
|
LoadAmmoInRaidPatches.Enable();
|
||||||
MultiSelectPatches.Enable();
|
MultiSelectPatches.Enable();
|
||||||
new FixUnloadLastBulletPatch().Enable();
|
new FixUnloadLastBulletPatch().Enable();
|
||||||
@@ -65,6 +65,9 @@ public class Plugin : BaseUnityPlugin
|
|||||||
MoveSortingTablePatches.Enable();
|
MoveSortingTablePatches.Enable();
|
||||||
FilterOutOfStockPatches.Enable();
|
FilterOutOfStockPatches.Enable();
|
||||||
SortPatches.Enable();
|
SortPatches.Enable();
|
||||||
|
ReloadInPlacePatches.Enable();
|
||||||
|
BarterOfferPatches.Enable();
|
||||||
|
new UnlockCursorPatch().Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool InRaid()
|
public static bool InRaid()
|
||||||
|
|||||||
@@ -28,12 +28,16 @@ Existing SPT features made better
|
|||||||
|
|
||||||
- Rebind Home/End, PageUp/PageDown to work like you would expect
|
- Rebind Home/End, PageUp/PageDown to work like you would expect
|
||||||
- Customizable mouse scrolling speed
|
- Customizable mouse scrolling speed
|
||||||
|
- Moving stacks into containers always moves entire stack
|
||||||
|
- ✨ Items made stackable by other mods follow normal stacking behavior
|
||||||
- Allow found in raid money and ammo automatically stack with non-found-in-raid items
|
- Allow found in raid money and ammo automatically stack with non-found-in-raid items
|
||||||
- Synchronize stash scroll position everywhere your stash is visible
|
- Synchronize stash scroll position everywhere your stash is visible
|
||||||
- Insure and repair items directly from the context menu
|
- Insure and repair items directly from the context menu
|
||||||
- Load ammo via context menu _in raid_
|
- Load ammo via context menu _in raid_
|
||||||
- Load ammo preset will pull ammo from inventory, not just stash
|
- Load ammo preset will pull ammo from inventory, not just stash
|
||||||
- ✨ Multi-grid vest and backpack grids reordered to be left to right, top to bottom.
|
- ✨ Multi-grid vest and backpack grids reordered to be left to right, top to bottom.
|
||||||
|
- ✨ Sorting will stack and combine stacks of items
|
||||||
|
- ✨ Shift-clicking sort will only sort loose items, leaving containers in place
|
||||||
|
|
||||||
#### Inspect windows
|
#### Inspect windows
|
||||||
|
|
||||||
@@ -57,6 +61,8 @@ Existing SPT features made better
|
|||||||
- Option to keep the Add Offer window open after placing your offer
|
- Option to keep the Add Offer window open after placing your offer
|
||||||
- Set prices in the Add Offer window by clicking the min/avg/max market prices (multiplies for bulk orders)
|
- Set prices in the Add Offer window by clicking the min/avg/max market prices (multiplies for bulk orders)
|
||||||
- Autoselect Similar checkbox is remembered across sessions and application restarts
|
- Autoselect Similar checkbox is remembered across sessions and application restarts
|
||||||
|
- ✨ Replace barter offers icons with actual item images, plus owned/required counts on expansion
|
||||||
|
- ✨ Clears filters for you when you type in search bar and there's no match
|
||||||
|
|
||||||
#### Weapon modding/presets
|
#### Weapon modding/presets
|
||||||
|
|
||||||
@@ -70,6 +76,7 @@ Existing SPT features made better
|
|||||||
|
|
||||||
#### In raid
|
#### In raid
|
||||||
|
|
||||||
|
- ✨ Reloading will swap magazines in-place, instead of dropping them on the ground when there's no room.
|
||||||
- ✨ Grenade quickbinds will transfer to the next grenade of the same type after throwing.
|
- ✨ Grenade quickbinds will transfer to the next grenade of the same type after throwing.
|
||||||
- ✨ Option to change the behavior of the grenade key from selecting a random grenade to a deterministic one
|
- ✨ Option to change the behavior of the grenade key from selecting a random grenade to a deterministic one
|
||||||
|
|
||||||
|
|||||||
98
Settings.cs
98
Settings.cs
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UIFixes;
|
namespace UIFixes;
|
||||||
@@ -47,6 +48,7 @@ internal class Settings
|
|||||||
private const string FleaMarketSection = "6. Flea Market";
|
private const string FleaMarketSection = "6. Flea Market";
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
public static ConfigEntry<bool> UnlockCursor { get; set; }
|
||||||
public static ConfigEntry<WeaponPresetConfirmationOption> ShowPresetConfirmations { get; set; }
|
public static ConfigEntry<WeaponPresetConfirmationOption> ShowPresetConfirmations { get; set; }
|
||||||
public static ConfigEntry<TransferConfirmationOption> ShowTransferConfirmations { get; set; }
|
public static ConfigEntry<TransferConfirmationOption> ShowTransferConfirmations { get; set; }
|
||||||
public static ConfigEntry<bool> KeepMessagesOpen { get; set; }
|
public static ConfigEntry<bool> KeepMessagesOpen { get; set; }
|
||||||
@@ -62,6 +64,7 @@ internal class Settings
|
|||||||
public static ConfigEntry<int> MouseScrollMulti { get; set; }
|
public static ConfigEntry<int> MouseScrollMulti { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> InspectKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> InspectKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> OpenKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> OpenKeyBind { get; set; }
|
||||||
|
public static ConfigEntry<KeyboardShortcut> ExamineKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> TopUpKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> TopUpKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> UseKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> UseKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> UseAllKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> UseAllKeyBind { get; set; }
|
||||||
@@ -69,6 +72,7 @@ internal class Settings
|
|||||||
public static ConfigEntry<KeyboardShortcut> UnpackKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> UnpackKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> FilterByKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> FilterByKeyBind { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> LinkedSearchKeyBind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> LinkedSearchKeyBind { get; set; }
|
||||||
|
public static ConfigEntry<KeyboardShortcut> SortingTableKeyBind { get; set; }
|
||||||
public static ConfigEntry<bool> UseRaidMouseScrollMulti { get; set; } // Advanced
|
public static ConfigEntry<bool> UseRaidMouseScrollMulti { get; set; } // Advanced
|
||||||
public static ConfigEntry<int> MouseScrollMultiInRaid { get; set; } // Advanced
|
public static ConfigEntry<int> MouseScrollMultiInRaid { get; set; } // Advanced
|
||||||
public static ConfigEntry<bool> ItemContextBlocksTextInputs { get; set; } // Advanced
|
public static ConfigEntry<bool> ItemContextBlocksTextInputs { get; set; } // Advanced
|
||||||
@@ -81,6 +85,8 @@ internal class Settings
|
|||||||
public static ConfigEntry<MultiSelectStrategy> MultiSelectStrat { get; set; }
|
public static ConfigEntry<MultiSelectStrategy> MultiSelectStrat { get; set; }
|
||||||
public static ConfigEntry<bool> ShowMultiSelectDebug { get; set; } // Advanced
|
public static ConfigEntry<bool> ShowMultiSelectDebug { get; set; } // Advanced
|
||||||
public static ConfigEntry<bool> SwapItems { get; set; }
|
public static ConfigEntry<bool> SwapItems { get; set; }
|
||||||
|
public static ConfigEntry<bool> SwapMags { get; set; }
|
||||||
|
public static ConfigEntry<bool> AlwaysSwapMags { get; set; }
|
||||||
public static ConfigEntry<bool> SwapImpossibleContainers { get; set; }
|
public static ConfigEntry<bool> SwapImpossibleContainers { get; set; }
|
||||||
public static ConfigEntry<bool> ReorderGrids { get; set; }
|
public static ConfigEntry<bool> ReorderGrids { get; set; }
|
||||||
public static ConfigEntry<bool> SynchronizeStashScrolling { get; set; }
|
public static ConfigEntry<bool> SynchronizeStashScrolling { get; set; }
|
||||||
@@ -90,6 +96,7 @@ internal class Settings
|
|||||||
public static ConfigEntry<bool> MergeFIRAmmo { get; set; }
|
public static ConfigEntry<bool> MergeFIRAmmo { get; set; }
|
||||||
public static ConfigEntry<bool> MergeFIROther { get; set; }
|
public static ConfigEntry<bool> MergeFIROther { get; set; }
|
||||||
public static ConfigEntry<bool> AutoOpenSortingTable { get; set; }
|
public static ConfigEntry<bool> AutoOpenSortingTable { get; set; }
|
||||||
|
public static ConfigEntry<bool> DefaultSortingTableBind { get; set; } // Advanced
|
||||||
public static ConfigEntry<bool> ContextMenuOnRight { get; set; }
|
public static ConfigEntry<bool> ContextMenuOnRight { get; set; }
|
||||||
public static ConfigEntry<bool> ShowGPCurrency { get; set; }
|
public static ConfigEntry<bool> ShowGPCurrency { get; set; }
|
||||||
public static ConfigEntry<bool> ShowOutOfStockCheckbox { get; set; }
|
public static ConfigEntry<bool> ShowOutOfStockCheckbox { get; set; }
|
||||||
@@ -113,9 +120,11 @@ internal class Settings
|
|||||||
|
|
||||||
// Flea Market
|
// Flea Market
|
||||||
public static ConfigEntry<bool> EnableFleaHistory { get; set; }
|
public static ConfigEntry<bool> EnableFleaHistory { get; set; }
|
||||||
|
public static ConfigEntry<bool> ShowBarterIcons { get; set; }
|
||||||
public static ConfigEntry<bool> EnableSlotSearch { get; set; }
|
public static ConfigEntry<bool> EnableSlotSearch { get; set; }
|
||||||
public static ConfigEntry<bool> ShowRequiredQuest { get; set; }
|
public static ConfigEntry<bool> ShowRequiredQuest { get; set; }
|
||||||
public static ConfigEntry<bool> AutoExpandCategories { get; set; }
|
public static ConfigEntry<bool> AutoExpandCategories { get; set; }
|
||||||
|
public static ConfigEntry<bool> ClearFiltersOnSearch { get; set; }
|
||||||
public static ConfigEntry<bool> KeepAddOfferOpen { get; set; }
|
public static ConfigEntry<bool> KeepAddOfferOpen { get; set; }
|
||||||
public static ConfigEntry<KeyboardShortcut> PurchaseAllKeybind { get; set; }
|
public static ConfigEntry<KeyboardShortcut> PurchaseAllKeybind { get; set; }
|
||||||
public static ConfigEntry<bool> KeepAddOfferOpenIgnoreMaxOffers { get; set; } // Advanced
|
public static ConfigEntry<bool> KeepAddOfferOpenIgnoreMaxOffers { get; set; } // Advanced
|
||||||
@@ -126,6 +135,15 @@ internal class Settings
|
|||||||
var configEntries = new List<ConfigEntryBase>();
|
var configEntries = new List<ConfigEntryBase>();
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
configEntries.Add(UnlockCursor = config.Bind(
|
||||||
|
GeneralSection,
|
||||||
|
"Unlock Cursor",
|
||||||
|
true,
|
||||||
|
new ConfigDescription(
|
||||||
|
"Unlock cursor in Windowed, Maximized Windowed, and FullScreen Windowed modes. Note that you must alt-tab out of the game and back in for this to take affect.",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(ShowPresetConfirmations = config.Bind(
|
configEntries.Add(ShowPresetConfirmations = config.Bind(
|
||||||
GeneralSection,
|
GeneralSection,
|
||||||
"Show Weapon Preset Confirmation Dialog",
|
"Show Weapon Preset Confirmation Dialog",
|
||||||
@@ -262,6 +280,15 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(ExamineKeyBind = config.Bind(
|
||||||
|
InputSection,
|
||||||
|
"Examine/Interact Shortcut",
|
||||||
|
new KeyboardShortcut(KeyCode.None),
|
||||||
|
new ConfigDescription(
|
||||||
|
"Keybind to examine an item, fold it, unfold it, turn it on, turn it off, or check a magazine",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(TopUpKeyBind = config.Bind(
|
configEntries.Add(TopUpKeyBind = config.Bind(
|
||||||
InputSection,
|
InputSection,
|
||||||
"Top Up Ammo Shortcut",
|
"Top Up Ammo Shortcut",
|
||||||
@@ -325,6 +352,15 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(SortingTableKeyBind = config.Bind(
|
||||||
|
InputSection,
|
||||||
|
"Transfer to/from Sorting Table",
|
||||||
|
new KeyboardShortcut(KeyCode.None),
|
||||||
|
new ConfigDescription(
|
||||||
|
"Keybind to transfer items to and from the sorting table. Will auto-open sorting table if necessary.",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(ItemContextBlocksTextInputs = config.Bind(
|
configEntries.Add(ItemContextBlocksTextInputs = config.Bind(
|
||||||
InputSection,
|
InputSection,
|
||||||
"Block Text Inputs on Item Mouseover",
|
"Block Text Inputs on Item Mouseover",
|
||||||
@@ -398,6 +434,24 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(SwapMags = config.Bind(
|
||||||
|
InventorySection,
|
||||||
|
"Reload Magazines In-Place",
|
||||||
|
true,
|
||||||
|
new ConfigDescription(
|
||||||
|
"When reloading a weapon with a magazine, swap locations with the new magazine if necessary (and possible)",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(AlwaysSwapMags = config.Bind(
|
||||||
|
InventorySection,
|
||||||
|
"Always Reload Magazines In-Place",
|
||||||
|
false,
|
||||||
|
new ConfigDescription(
|
||||||
|
"Always reload magazines in-place, even if there's space not to. Note that in-place reloads are slower.",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(SwapImpossibleContainers = config.Bind(
|
configEntries.Add(SwapImpossibleContainers = config.Bind(
|
||||||
InventorySection,
|
InventorySection,
|
||||||
"Swap with Incompatible Containers",
|
"Swap with Incompatible Containers",
|
||||||
@@ -479,6 +533,15 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(DefaultSortingTableBind = config.Bind(
|
||||||
|
InventorySection,
|
||||||
|
"Shift-Click to Sorting Table",
|
||||||
|
true,
|
||||||
|
new ConfigDescription(
|
||||||
|
"This setting lets you enable/disable the default Tarkov behavior of shift-clicking items to transfer them to the sorting table.",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { IsAdvanced = true })));
|
||||||
|
|
||||||
configEntries.Add(ContextMenuOnRight = config.Bind(
|
configEntries.Add(ContextMenuOnRight = config.Bind(
|
||||||
InventorySection,
|
InventorySection,
|
||||||
"Context Menu Flyout on Right",
|
"Context Menu Flyout on Right",
|
||||||
@@ -635,6 +698,15 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(ShowBarterIcons = config.Bind(
|
||||||
|
FleaMarketSection,
|
||||||
|
"Show Barter Icons",
|
||||||
|
true,
|
||||||
|
new ConfigDescription(
|
||||||
|
"Show item icons for barters instead of the generic barter icon",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(EnableSlotSearch = config.Bind(
|
configEntries.Add(EnableSlotSearch = config.Bind(
|
||||||
FleaMarketSection,
|
FleaMarketSection,
|
||||||
"Enable Linked Slot Search",
|
"Enable Linked Slot Search",
|
||||||
@@ -653,6 +725,15 @@ internal class Settings
|
|||||||
null,
|
null,
|
||||||
new ConfigurationManagerAttributes { })));
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
|
configEntries.Add(ClearFiltersOnSearch = config.Bind(
|
||||||
|
FleaMarketSection,
|
||||||
|
"Clear Filters on Search",
|
||||||
|
true,
|
||||||
|
new ConfigDescription(
|
||||||
|
"Pressing Enter after typing in the flea search bar will clear non-default filters",
|
||||||
|
null,
|
||||||
|
new ConfigurationManagerAttributes { })));
|
||||||
|
|
||||||
configEntries.Add(ShowRequiredQuest = config.Bind(
|
configEntries.Add(ShowRequiredQuest = config.Bind(
|
||||||
FleaMarketSection,
|
FleaMarketSection,
|
||||||
"Show Required Quest for Locked Offers",
|
"Show Required Quest for Locked Offers",
|
||||||
@@ -793,10 +874,25 @@ public static class SettingExtensions
|
|||||||
configEntry.SettingChanged += (_, _) => onChange(configEntry.Value);
|
configEntry.SettingChanged += (_, _) => onChange(configEntry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void Bind<T>(this ConfigEntry<T> configEntry, Action<T> onChange)
|
public static void Bind<T>(this ConfigEntry<T> configEntry, Action<T> onChange)
|
||||||
{
|
{
|
||||||
configEntry.Subscribe(onChange);
|
configEntry.Subscribe(onChange);
|
||||||
onChange(configEntry.Value);
|
onChange(configEntry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyboardShortcut methods return false if any other key is down
|
||||||
|
public static bool IsDownIgnoreOthers(this KeyboardShortcut shortcut)
|
||||||
|
{
|
||||||
|
return Input.GetKeyDown(shortcut.MainKey) && shortcut.Modifiers.All(Input.GetKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsPressedIgnoreOthers(this KeyboardShortcut shortcut)
|
||||||
|
{
|
||||||
|
return Input.GetKey(shortcut.MainKey) && shortcut.Modifiers.All(Input.GetKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsUpIgnoreOthers(this KeyboardShortcut shortcut)
|
||||||
|
{
|
||||||
|
return Input.GetKeyUp(shortcut.MainKey) && shortcut.Modifiers.All(Input.GetKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
Sorter.cs
26
Sorter.cs
@@ -106,4 +106,30 @@ public static class Sorter
|
|||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recreation of InteractionsHandlerClass.smethod_0, but without the out type being Stackable.
|
||||||
|
// minimumStackSpace of 0 means complete merge only, i.e. mininumStackSpace = itemToMerge.StackObjectCount
|
||||||
|
public static bool FindStackForMerge(IEnumerable<EFT.InventoryLogic.IContainer> containers, Item itemToMerge, out Item mergeableItem, int minimumStackSpace = 0)
|
||||||
|
{
|
||||||
|
if (minimumStackSpace <= 0)
|
||||||
|
{
|
||||||
|
minimumStackSpace = itemToMerge.StackObjectsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ignoreSpawnedInSession = itemToMerge.Template switch
|
||||||
|
{
|
||||||
|
MoneyClass _ => Settings.MergeFIRMoney.Value,
|
||||||
|
AmmoTemplate _ => Settings.MergeFIRMoney.Value,
|
||||||
|
_ => Settings.MergeFIROther.Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
mergeableItem = containers.SelectMany(x => x.Items)
|
||||||
|
.Where(x => x != itemToMerge)
|
||||||
|
.Where(x => x.TemplateId == itemToMerge.TemplateId)
|
||||||
|
.Where(x => ignoreSpawnedInSession || x.SpawnedInSession == itemToMerge.SpawnedInSession)
|
||||||
|
.Where(x => x.StackObjectsCount < x.StackMaxSize)
|
||||||
|
.FirstOrDefault(x => minimumStackSpace <= x.StackMaxSize - x.StackObjectsCount);
|
||||||
|
|
||||||
|
return mergeableItem != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>Tyfon.UIFixes</AssemblyName>
|
<AssemblyName>Tyfon.UIFixes</AssemblyName>
|
||||||
<Description>SPT UI Fixes</Description>
|
<Description>SPT UI Fixes</Description>
|
||||||
<Version>2.2.2</Version>
|
<Version>2.3.1</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
@@ -104,8 +104,7 @@
|
|||||||
xcopy /F /Y "$(TargetPath)" "$(ProjectDir)dist\BepInEx\plugins\"
|
xcopy /F /Y "$(TargetPath)" "$(ProjectDir)dist\BepInEx\plugins\"
|
||||||
xcopy /F /Y /S "$(ProjectDir)dist\BepInEx" "$(ProjectDir)$(PathToSPT)\BepInEx"
|
xcopy /F /Y /S "$(ProjectDir)dist\BepInEx" "$(ProjectDir)$(PathToSPT)\BepInEx"
|
||||||
xcopy /F /Y /S "$(ProjectDir)dist\user" "$(ProjectDir)$(PathToSPT)\user"
|
xcopy /F /Y /S "$(ProjectDir)dist\user" "$(ProjectDir)$(PathToSPT)\user"
|
||||||
7z a -t7z $(TargetName.Replace(".", "-"))-$(Version).7z $(ProjectDir)dist\BepInEx $(ProjectDir)dist\user
|
7z a -tzip dist\$(TargetName.Replace(".", "-"))-$(Version).zip $(ProjectDir)dist\BepInEx $(ProjectDir)dist\user
|
||||||
move /Y $(TargetName.Replace(".", "-"))-$(Version).7z dist\
|
|
||||||
)' />
|
)' />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import ignore from "ignore";
|
|||||||
import archiver from "archiver";
|
import archiver from "archiver";
|
||||||
import winston from "winston";
|
import winston from "winston";
|
||||||
|
|
||||||
const sptPath = "/SPT/3.9.2-debug";
|
const sptPath = "/SPT/3.9.3-debug";
|
||||||
|
|
||||||
// Get the command line arguments to determine whether to use verbose logging.
|
// Get the command line arguments to determine whether to use verbose logging.
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uifixes",
|
"name": "uifixes",
|
||||||
"version": "2.2.2",
|
"version": "2.3.1",
|
||||||
"main": "src/mod.js",
|
"main": "src/mod.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Tyfon",
|
"author": "Tyfon",
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import type { ICloner } from "@spt/utils/cloners/ICloner";
|
|||||||
import { RagfairLinkedSlotItemService } from "./RagfairLinkedSlotItemService";
|
import { RagfairLinkedSlotItemService } from "./RagfairLinkedSlotItemService";
|
||||||
|
|
||||||
import config from "../config/config.json";
|
import config from "../config/config.json";
|
||||||
|
import { RagfairOfferGenerator } from "@spt/generators/RagfairOfferGenerator";
|
||||||
|
import { IRagfairOffer } from "@spt/models/eft/ragfair/IRagfairOffer";
|
||||||
|
|
||||||
class UIFixes implements IPreSptLoadMod {
|
class UIFixes implements IPreSptLoadMod {
|
||||||
private databaseService: DatabaseService;
|
private databaseService: DatabaseService;
|
||||||
@@ -50,6 +52,36 @@ class UIFixes implements IPreSptLoadMod {
|
|||||||
{ frequency: "Always" }
|
{ frequency: "Always" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Trader offers with dogtag barter - fixed in next SPT release *after* 3.9.3
|
||||||
|
container.afterResolution(
|
||||||
|
"RagfairOfferGenerator",
|
||||||
|
(_, ragfairOfferGenerator: RagfairOfferGenerator) => {
|
||||||
|
const original = ragfairOfferGenerator["createOffer"]; // By name because protected
|
||||||
|
|
||||||
|
ragfairOfferGenerator["createOffer"] = (userID, time, items, barterScheme, loyalLevel, isPackOffer) => {
|
||||||
|
const offer: IRagfairOffer = original.call(
|
||||||
|
ragfairOfferGenerator,
|
||||||
|
userID,
|
||||||
|
time,
|
||||||
|
items,
|
||||||
|
barterScheme,
|
||||||
|
loyalLevel,
|
||||||
|
isPackOffer
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < offer.requirements.length; i++) {
|
||||||
|
if (barterScheme[i]["level"] !== undefined) {
|
||||||
|
offer.requirements[i]["level"] = barterScheme[i]["level"];
|
||||||
|
offer.requirements[i]["side"] = barterScheme[i]["side"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return offer;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ frequency: "Always" }
|
||||||
|
);
|
||||||
|
|
||||||
// Better tool return - starting production
|
// Better tool return - starting production
|
||||||
if (config.putToolsBack) {
|
if (config.putToolsBack) {
|
||||||
container.afterResolution(
|
container.afterResolution(
|
||||||
@@ -197,4 +229,4 @@ class UIFixes implements IPreSptLoadMod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { mod: new UIFixes() };
|
export const mod = new UIFixes();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"module": "CommonJS",
|
"module": "NodeNext",
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"moduleResolution": "Node10",
|
"moduleResolution": "NodeNext",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user