Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
438b0fdb9e | |||
ec50b42dc7 | |||
7183b28e8b | |||
ccad3d23d0 | |||
0f7ee0b1e3 | |||
350abc8bf3 | |||
ab9ca14b93 |
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.CustomInteractions.Prepatch</AssemblyName>
|
<AssemblyName>IcyClawz.CustomInteractions.Prepatch</AssemblyName>
|
||||||
<Version>1.4.0</Version>
|
<Version>1.6.0</Version>
|
||||||
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -4,21 +4,17 @@ using EFT.UI;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
using EmptyInteractionsAbstractClass = GClass3039;
|
using EmptyInteractionsAbstractClass = GClass3423;
|
||||||
|
|
||||||
namespace IcyClawz.CustomInteractions;
|
namespace IcyClawz.CustomInteractions;
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
public interface ICustomInteractionsProvider
|
||||||
public interface ICustomInteractionsProvider { } // Do not implement this directly
|
|
||||||
|
|
||||||
public interface IItemCustomInteractionsProvider : ICustomInteractionsProvider
|
|
||||||
{
|
{
|
||||||
IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item);
|
IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext context, EItemViewType viewType, Item item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CustomInteractionsManager
|
public static class CustomInteractionsManager
|
||||||
@ -32,52 +28,35 @@ public static class CustomInteractionsManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomInteraction()
|
public class CustomInteraction(ItemUiContext context)
|
||||||
{
|
{
|
||||||
internal readonly CustomInteractionImpl Impl = new(UnityEngine.Random.Range(0, int.MaxValue).ToString("x4"));
|
internal readonly CustomInteractionImpl Impl = new(context, UnityEngine.Random.Range(0, int.MaxValue).ToString("x4"));
|
||||||
|
|
||||||
public Func<string> Caption { get => Impl.Caption; set => Impl.Caption = value; }
|
public Func<string> Caption { get => Impl.Caption; set => Impl.Caption = value; }
|
||||||
public Func<Sprite> Icon { get => Impl.Icon; set => Impl.Icon = value; }
|
public Func<Sprite> Icon { get => Impl.Icon; set => Impl.Icon = value; }
|
||||||
public Action Action { get => Impl.Action; set => Impl.Action = value; }
|
public Action Action { get => Impl.Action; set => Impl.Action = value; }
|
||||||
public Func<CustomSubInteractions> SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; }
|
public Func<IEnumerable<CustomInteraction>> SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; }
|
||||||
public Func<bool> Enabled { get => Impl.Enabled; set => Impl.Enabled = value; }
|
public Func<bool> Enabled { get => Impl.Enabled; set => Impl.Enabled = value; }
|
||||||
public Func<string> Error { get => Impl.Error; set => Impl.Error = value; }
|
public Func<string> Error { get => Impl.Error; set => Impl.Error = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class CustomInteractionImpl(string id) : DynamicInteractionClass(id, id)
|
internal sealed class CustomInteractionImpl(ItemUiContext context, string id) : DynamicInteractionClass(id, id)
|
||||||
{
|
{
|
||||||
|
internal readonly ItemUiContext Context = context;
|
||||||
|
|
||||||
public Func<string> Caption { get; set; }
|
public Func<string> Caption { get; set; }
|
||||||
public new Func<Sprite> Icon { get; set; }
|
public new Func<Sprite> Icon { get; set; }
|
||||||
public Action Action { get => action_0; set => action_0 = value; }
|
public Action Action { get => action_0; set => action_0 = value; }
|
||||||
public Func<CustomSubInteractions> SubMenu { get; set; }
|
public Func<IEnumerable<CustomInteraction>> SubMenu { get; set; }
|
||||||
public Func<bool> Enabled { get; set; }
|
public Func<bool> Enabled { get; set; }
|
||||||
public Func<string> Error { get; set; }
|
public Func<string> Error { get; set; }
|
||||||
|
|
||||||
public bool IsInteractive() => Enabled?.Invoke() ?? true;
|
public bool IsInteractive() => Enabled?.Invoke() ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class CustomSubInteractions(ItemUiContext uiContext)
|
internal sealed class CustomInteractionsImpl(ItemUiContext context) : EmptyInteractionsAbstractClass(context)
|
||||||
{
|
|
||||||
internal readonly CustomSubInteractionsImpl Impl = new(uiContext);
|
|
||||||
|
|
||||||
public bool ExaminationRequired
|
|
||||||
{
|
|
||||||
get => Impl.ExaminationRequiredInternal;
|
|
||||||
set => Impl.ExaminationRequiredInternal = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(CustomInteraction interaction) => Impl.AddCustomInteraction(interaction);
|
|
||||||
public void AddRange(IEnumerable<CustomInteraction> interactions) => interactions.ExecuteForEach(Impl.AddCustomInteraction);
|
|
||||||
public void Remove(CustomInteraction interaction) => Impl.RemoveCustomInteraction(interaction);
|
|
||||||
public void RemoveRange(IEnumerable<CustomInteraction> interactions) => interactions.ExecuteForEach(Impl.RemoveCustomInteraction);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class CustomSubInteractionsImpl(ItemUiContext uiContext) : EmptyInteractionsAbstractClass(uiContext)
|
|
||||||
{
|
{
|
||||||
public IEnumerable<CustomInteractionImpl> CustomInteractions => DynamicInteractions.OfType<CustomInteractionImpl>();
|
public IEnumerable<CustomInteractionImpl> CustomInteractions => DynamicInteractions.OfType<CustomInteractionImpl>();
|
||||||
|
|
||||||
public bool ExaminationRequiredInternal { get; set; } = true;
|
|
||||||
public override bool ExaminationRequired => ExaminationRequiredInternal;
|
|
||||||
public override bool HasIcons => CustomInteractions.Any(interaction => interaction.Icon is not null);
|
public override bool HasIcons => CustomInteractions.Any(interaction => interaction.Icon is not null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +66,8 @@ internal static class AbstractInteractionsExtensions
|
|||||||
typeof(ItemInfoInteractionsAbstractClass<T>).GetField("dictionary_0", BindingFlags.NonPublic | BindingFlags.Instance)
|
typeof(ItemInfoInteractionsAbstractClass<T>).GetField("dictionary_0", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
.GetValue(instance) as Dictionary<string, DynamicInteractionClass>;
|
.GetValue(instance) as Dictionary<string, DynamicInteractionClass>;
|
||||||
|
|
||||||
public static void AddCustomInteraction<T>(this ItemInfoInteractionsAbstractClass<T> instance, CustomInteraction interaction) where T : struct, Enum =>
|
public static void AddCustomInteraction<T>(this ItemInfoInteractionsAbstractClass<T> instance, CustomInteractionImpl impl) where T : struct, Enum =>
|
||||||
instance.GetDynamicInteractions()[interaction.Impl.Key] = interaction.Impl;
|
instance.GetDynamicInteractions()[impl.Key] = impl;
|
||||||
|
|
||||||
public static void RemoveCustomInteraction<T>(this ItemInfoInteractionsAbstractClass<T> instance, CustomInteraction interaction) where T : struct, Enum =>
|
|
||||||
instance.GetDynamicInteractions().Remove(interaction.Impl.Key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class InteractionButtonsContainerExtensions
|
internal static class InteractionButtonsContainerExtensions
|
||||||
@ -140,6 +116,7 @@ internal static class InteractionButtonsContainerExtensions
|
|||||||
public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl impl)
|
public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl impl)
|
||||||
{
|
{
|
||||||
bool isInteractive = impl.IsInteractive();
|
bool isInteractive = impl.IsInteractive();
|
||||||
|
IEnumerable<CustomInteraction> subMenu = impl.SubMenu?.Invoke();
|
||||||
SimpleContextMenuButton button = null;
|
SimpleContextMenuButton button = null;
|
||||||
button = instance.CreateButton(
|
button = instance.CreateButton(
|
||||||
impl.Key,
|
impl.Key,
|
||||||
@ -156,14 +133,15 @@ internal static class InteractionButtonsContainerExtensions
|
|||||||
{
|
{
|
||||||
instance.SetCurrentButton(button);
|
instance.SetCurrentButton(button);
|
||||||
instance.CloseSubMenu();
|
instance.CloseSubMenu();
|
||||||
if (isInteractive)
|
if (isInteractive && subMenu != null)
|
||||||
{
|
{
|
||||||
CustomSubInteractions subMenu = impl.SubMenu?.Invoke();
|
CustomInteractionsImpl subInteractions = new CustomInteractionsImpl(impl.Context);
|
||||||
if (subMenu is not null)
|
foreach (CustomInteractionImpl subImpl in subMenu.Select(item => item.Impl))
|
||||||
instance.SetSubInteractions(subMenu.Impl);
|
subInteractions.AddCustomInteraction(subImpl);
|
||||||
|
instance.SetSubInteractions(subInteractions);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
impl.SubMenu is not null,
|
subMenu?.Any() ?? false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
button.SetButtonInteraction(
|
button.SetButtonInteraction(
|
||||||
|
@ -3,15 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.CustomInteractions</AssemblyName>
|
<AssemblyName>IcyClawz.CustomInteractions</AssemblyName>
|
||||||
<Version>1.4.0</Version>
|
<Version>1.6.0</Version>
|
||||||
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Aki.Reflection">
|
|
||||||
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\Shared\Assembly-CSharp-CustomInteractions.dll</HintPath>
|
<HintPath>..\Shared\Assembly-CSharp-CustomInteractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@ -24,6 +21,9 @@
|
|||||||
<Reference Include="Sirenix.Serialization">
|
<Reference Include="Sirenix.Serialization">
|
||||||
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
using Aki.Reflection.Patching;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace IcyClawz.CustomInteractions;
|
namespace IcyClawz.CustomInteractions;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.CustomInteractions", "IcyClawz.CustomInteractions", "1.4.0")]
|
[BepInPlugin("com.IcyClawz.CustomInteractions", "IcyClawz.CustomInteractions", "1.6.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private void Awake()
|
private void Awake()
|
||||||
@ -25,13 +25,13 @@ internal class ItemUiContextPatch : ModulePatch
|
|||||||
private static void Postfix(ref ItemInfoInteractionsAbstractClass<EFT.InventoryLogic.EItemInfoButton> __result,
|
private static void Postfix(ref ItemInfoInteractionsAbstractClass<EFT.InventoryLogic.EItemInfoButton> __result,
|
||||||
ref ItemUiContext __instance, ItemContextClass itemContext)
|
ref ItemUiContext __instance, ItemContextClass itemContext)
|
||||||
{
|
{
|
||||||
foreach (var provider in CustomInteractionsManager.Providers.OfType<IItemCustomInteractionsProvider>())
|
foreach (var provider in CustomInteractionsManager.Providers)
|
||||||
{
|
{
|
||||||
var interactions = provider.GetCustomInteractions(__instance, itemContext.ViewType, itemContext.Item);
|
var interactions = provider.GetCustomInteractions(__instance, itemContext.ViewType, itemContext.Item);
|
||||||
if (interactions is null)
|
if (interactions is null)
|
||||||
continue;
|
continue;
|
||||||
foreach (CustomInteraction interaction in interactions)
|
foreach (CustomInteractionImpl impl in interactions.Select(interaction => interaction.Impl))
|
||||||
__result.AddCustomInteraction(interaction);
|
__result.AddCustomInteraction(impl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.ItemAttributeFix</AssemblyName>
|
<AssemblyName>IcyClawz.ItemAttributeFix</AssemblyName>
|
||||||
<Version>1.3.0</Version>
|
<Version>1.5.0</Version>
|
||||||
<RootNamespace>IcyClawz.ItemAttributeFix</RootNamespace>
|
<RootNamespace>IcyClawz.ItemAttributeFix</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Aki.Reflection">
|
|
||||||
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="BepInEx">
|
<Reference Include="BepInEx">
|
||||||
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using Aki.Reflection.Patching;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace IcyClawz.ItemAttributeFix;
|
namespace IcyClawz.ItemAttributeFix;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.ItemAttributeFix", "IcyClawz.ItemAttributeFix", "1.3.0")]
|
[BepInPlugin("com.IcyClawz.ItemAttributeFix", "IcyClawz.ItemAttributeFix", "1.5.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private void Awake() =>
|
private void Awake() =>
|
||||||
|
@ -5,116 +5,209 @@ using EFT.UI;
|
|||||||
using IcyClawz.CustomInteractions;
|
using IcyClawz.CustomInteractions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
using ILightTemplate = GInterface295;
|
using ILightTemplate = GInterface357;
|
||||||
using GlobalEvents = GClass3019;
|
using ISightTemplate = GInterface365;
|
||||||
|
using GlobalEvents = GClass3400;
|
||||||
|
|
||||||
namespace IcyClawz.ItemContextMenuExt;
|
namespace IcyClawz.ItemContextMenuExt;
|
||||||
|
|
||||||
internal static class PlayerExtensions
|
internal static class SightComponentExtensions
|
||||||
{
|
{
|
||||||
private static readonly FieldInfo InventoryControllerField =
|
public static int[] GetScopeCalibrationDistances(this SightComponent instance, int scopeIndex) =>
|
||||||
typeof(Player).GetField("_inventoryController", BindingFlags.NonPublic | BindingFlags.Instance);
|
((ISightTemplate)instance.Item.Template).CalibrationDistances[scopeIndex];
|
||||||
|
|
||||||
public static InventoryControllerClass GetInventoryController(this Player player) =>
|
public static float[] GetScopeZooms(this SightComponent instance, int scopeIndex) =>
|
||||||
InventoryControllerField.GetValue(player) as InventoryControllerClass;
|
((ISightTemplate)instance.Item.Template).Zooms[scopeIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class LightComponentExtensions
|
internal static class LightComponentExtensions
|
||||||
{
|
{
|
||||||
public static int GetModesCount(this LightComponent component) =>
|
public static int GetModesCount(this LightComponent instance) =>
|
||||||
((ILightTemplate)component.Item.Template).ModesCount;
|
((ILightTemplate)instance.Item.Template).ModesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class CustomInteractionsProvider : IItemCustomInteractionsProvider
|
internal sealed class CustomInteractionsProvider : ICustomInteractionsProvider
|
||||||
{
|
{
|
||||||
internal const string IconsPrefix = "Characteristics/Icons/";
|
private const string IconsPrefix = "Characteristics/Icons/";
|
||||||
internal static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
|
private static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
|
||||||
|
|
||||||
public IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item)
|
public IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext context, EItemViewType viewType, Item item)
|
||||||
{
|
{
|
||||||
if (viewType is not EItemViewType.Inventory)
|
if (viewType is EItemViewType.Inventory)
|
||||||
yield break;
|
|
||||||
|
|
||||||
FireModeComponent fireModeComponent = item.GetItemComponent<FireModeComponent>();
|
|
||||||
if (fireModeComponent is not null)
|
|
||||||
{
|
{
|
||||||
// Firing mode
|
FireModeComponent fireModeComponent = item.GetItemComponent<FireModeComponent>();
|
||||||
yield return new()
|
if (fireModeComponent is not null)
|
||||||
|
return GetFireModeInteractions(context, fireModeComponent);
|
||||||
|
|
||||||
|
SightComponent sightComponent = item.GetItemComponent<SightComponent>();
|
||||||
|
if (sightComponent is not null)
|
||||||
|
return GetSightInteractions(context, sightComponent);
|
||||||
|
|
||||||
|
LightComponent lightComponent = item.GetItemComponent<LightComponent>();
|
||||||
|
if (lightComponent is not null)
|
||||||
|
return GetLightInteractions(context, lightComponent);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CustomInteraction> GetFireModeInteractions(ItemUiContext context, FireModeComponent component)
|
||||||
|
{
|
||||||
|
if (component.AvailableEFireModes.Length > 1)
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
{
|
{
|
||||||
Caption = () => "Firing mode",
|
Caption = () => "Firing mode",
|
||||||
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
|
||||||
SubMenu = () => new FireModeSubMenu(uiContext, fireModeComponent),
|
SubMenu = () => GetFireModeSubInteractions(context, component),
|
||||||
Enabled = () => fireModeComponent.AvailableEFireModes.Length > 1,
|
|
||||||
Error = () => "This weapon is incapable of selective fire"
|
|
||||||
};
|
};
|
||||||
yield break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LightComponent lightComponent = item.GetItemComponent<LightComponent>();
|
private IEnumerable<CustomInteraction> GetFireModeSubInteractions(ItemUiContext context, FireModeComponent component)
|
||||||
if (lightComponent is not null)
|
{
|
||||||
|
foreach (Weapon.EFireMode fireMode in component.AvailableEFireModes)
|
||||||
{
|
{
|
||||||
// Turn on/off
|
yield return new(context)
|
||||||
yield return new()
|
|
||||||
{
|
{
|
||||||
Caption = () => (lightComponent.IsActive ? "TurnOff" : "TurnOn").Localized(),
|
Caption = () => fireMode.ToString().Localized(),
|
||||||
Icon = () => CacheResourcesPopAbstractClass.Pop<Sprite>(IconsPrefix + (lightComponent.IsActive ? "TurnOff" : "TurnOn")),
|
|
||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
ComponentUtils.SetLightState(lightComponent, !lightComponent.IsActive, lightComponent.SelectedMode);
|
ComponentUtils.SetFireMode(component, fireMode);
|
||||||
GlobalEvents.RequestGlobalRedraw();
|
},
|
||||||
}
|
Enabled = () => fireMode != component.FireMode,
|
||||||
};
|
};
|
||||||
// Switch mode
|
|
||||||
yield return new()
|
|
||||||
{
|
|
||||||
Caption = () => "Switch mode",
|
|
||||||
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
|
||||||
SubMenu = () => new LightModeSubMenu(uiContext, lightComponent),
|
|
||||||
Enabled = () => lightComponent.GetModesCount() > 1,
|
|
||||||
Error = () => "This device has no alternative modes"
|
|
||||||
};
|
|
||||||
yield break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal class FireModeSubMenu : CustomSubInteractions
|
private IEnumerable<CustomInteraction> GetSightInteractions(ItemUiContext context, SightComponent component)
|
||||||
{
|
|
||||||
public FireModeSubMenu(ItemUiContext uiContext, FireModeComponent component)
|
|
||||||
: base(uiContext)
|
|
||||||
{
|
{
|
||||||
AddRange(component.AvailableEFireModes.Select(fireMode => new CustomInteraction()
|
if (component.ScopesCount > 1)
|
||||||
{
|
{
|
||||||
Caption = () => fireMode.ToString().Localized(),
|
yield return new(context)
|
||||||
Action = () =>
|
|
||||||
{
|
{
|
||||||
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
Caption = () => "Active scope",
|
||||||
ComponentUtils.SetFireMode(component, fireMode);
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
||||||
},
|
SubMenu = () => GetScopeIndexSubInteractions(context, component),
|
||||||
Enabled = () => fireMode != component.FireMode
|
};
|
||||||
}));
|
}
|
||||||
|
if (component.GetScopeModesCount(component.SelectedScope) > 1)
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => "Active mode",
|
||||||
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
||||||
|
SubMenu = () => GetScopeModeSubInteractions(context, component),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (component.GetScopeCalibrationDistances(component.SelectedScope).Length > 1)
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => "Zero distance",
|
||||||
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
||||||
|
SubMenu = () => GetScopeCalibSubInteractions(context, component),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal class LightModeSubMenu : CustomSubInteractions
|
private IEnumerable<CustomInteraction> GetScopeIndexSubInteractions(ItemUiContext context, SightComponent component)
|
||||||
{
|
|
||||||
public LightModeSubMenu(ItemUiContext uiContext, LightComponent component)
|
|
||||||
: base(uiContext)
|
|
||||||
{
|
{
|
||||||
AddRange(Enumerable.Range(0, component.GetModesCount()).Select(lightMode => new CustomInteraction()
|
foreach (int scopeIndex in Enumerable.Range(0, component.ScopesCount))
|
||||||
{
|
{
|
||||||
Caption = () => $"Mode {lightMode + 1}",
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => $"Scope {scopeIndex + 1}",
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetScopeIndex(component, scopeIndex);
|
||||||
|
},
|
||||||
|
Enabled = () => scopeIndex != component.SelectedScope,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CustomInteraction> GetScopeModeSubInteractions(ItemUiContext context, SightComponent component)
|
||||||
|
{
|
||||||
|
int scopeIndex = component.SelectedScope;
|
||||||
|
float[] scopeZooms = component.GetScopeZooms(scopeIndex);
|
||||||
|
foreach (int scopeMode in Enumerable.Range(0, component.GetScopeModesCount(scopeIndex)))
|
||||||
|
{
|
||||||
|
float scopeZoom = scopeZooms.Length > 0 ? scopeZooms[scopeMode] : 0f;
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => $"Mode {scopeMode + 1} ({scopeZoom}x)",
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetScopeMode(component, scopeMode);
|
||||||
|
},
|
||||||
|
Enabled = () => scopeMode != component.ScopesSelectedModes[scopeIndex],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CustomInteraction> GetScopeCalibSubInteractions(ItemUiContext context, SightComponent component)
|
||||||
|
{
|
||||||
|
int scopeIndex = component.SelectedScope;
|
||||||
|
int[] scopeCalibDistances = component.GetScopeCalibrationDistances(scopeIndex);
|
||||||
|
foreach (int scopeCalibIndex in Enumerable.Range(0, scopeCalibDistances.Length))
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => $"{scopeCalibDistances[scopeCalibIndex]}",
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetScopeCalibIndex(component, scopeCalibIndex);
|
||||||
|
},
|
||||||
|
Enabled = () => scopeCalibIndex != component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CustomInteraction> GetLightInteractions(ItemUiContext context, LightComponent component)
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => component.IsActive ? "Turn off" : "Turn on",
|
||||||
|
Icon = () => CacheResourcesPopAbstractClass.Pop<Sprite>(IconsPrefix + (component.IsActive ? "TurnOff" : "TurnOn")),
|
||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
ComponentUtils.SetLightState(component, component.IsActive, lightMode);
|
ComponentUtils.SetLightActive(component, !component.IsActive);
|
||||||
|
GlobalEvents.RequestGlobalRedraw();
|
||||||
},
|
},
|
||||||
Enabled = () => lightMode != component.SelectedMode
|
};
|
||||||
}));
|
if (component.GetModesCount() > 1)
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => "Active mode",
|
||||||
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
||||||
|
SubMenu = () => GetLightModeSubInteractions(context, component),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CustomInteraction> GetLightModeSubInteractions(ItemUiContext context, LightComponent component)
|
||||||
|
{
|
||||||
|
foreach (int lightMode in Enumerable.Range(0, component.GetModesCount()))
|
||||||
|
{
|
||||||
|
yield return new(context)
|
||||||
|
{
|
||||||
|
Caption = () => $"Mode {lightMode + 1}",
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetLightMode(component, lightMode);
|
||||||
|
},
|
||||||
|
Enabled = () => lightMode != component.SelectedMode,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +222,7 @@ internal static class ComponentUtils
|
|||||||
if (fc.Item.MalfState.State is not Weapon.EMalfunctionState.None)
|
if (fc.Item.MalfState.State is not Weapon.EMalfunctionState.None)
|
||||||
{
|
{
|
||||||
fc.FirearmsAnimator.MisfireSlideUnknown(false);
|
fc.FirearmsAnimator.MisfireSlideUnknown(false);
|
||||||
player.GetInventoryController().ExamineMalfunction(fc.Item, false);
|
player.InventoryController.ExamineMalfunction(fc.Item, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,18 +233,89 @@ internal static class ComponentUtils
|
|||||||
component.SetFireMode(fireMode);
|
component.SetFireMode(fireMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetLightState(LightComponent component, bool isActive, int lightMode)
|
public static void SetScopeIndex(SightComponent component, int scopeIndex)
|
||||||
|
{
|
||||||
|
SetScopeState(component, new()
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
ScopeIndexInsideSight = scopeIndex,
|
||||||
|
ScopeMode = component.ScopesSelectedModes[scopeIndex],
|
||||||
|
ScopeCalibrationIndex = component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetScopeMode(SightComponent component, int scopeMode)
|
||||||
|
{
|
||||||
|
int scopeIndex = component.SelectedScope;
|
||||||
|
SetScopeState(component, new()
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
ScopeIndexInsideSight = scopeIndex,
|
||||||
|
ScopeMode = scopeMode,
|
||||||
|
ScopeCalibrationIndex = component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetScopeCalibIndex(SightComponent component, int scopeCalibIndex)
|
||||||
|
{
|
||||||
|
int scopeIndex = component.SelectedScope;
|
||||||
|
SetScopeState(component, new()
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
ScopeIndexInsideSight = scopeIndex,
|
||||||
|
ScopeMode = component.ScopesSelectedModes[scopeIndex],
|
||||||
|
ScopeCalibrationIndex = scopeCalibIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetScopeState(SightComponent component, FirearmScopeStateStruct scopeState)
|
||||||
{
|
{
|
||||||
Player player = GamePlayerOwner.MyPlayer;
|
Player player = GamePlayerOwner.MyPlayer;
|
||||||
|
|
||||||
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
||||||
{
|
{
|
||||||
fc.SetLightsState([new() { Id = component.Item.Id, IsActive = isActive, LightMode = lightMode }]);
|
fc.SetScopeMode([scopeState]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
component.IsActive = isActive;
|
int scopeIndex = scopeState.ScopeIndexInsideSight;
|
||||||
component.SelectedMode = lightMode;
|
component.SelectedScope = scopeIndex;
|
||||||
|
component.ScopesSelectedModes[scopeIndex] = scopeState.ScopeMode;
|
||||||
|
component.ScopesCurrentCalibPointIndexes[scopeIndex] = scopeState.ScopeCalibrationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLightActive(LightComponent component, bool isActive)
|
||||||
|
{
|
||||||
|
SetLightState(component, new()
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
IsActive = isActive,
|
||||||
|
LightMode = component.SelectedMode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLightMode(LightComponent component, int lightMode)
|
||||||
|
{
|
||||||
|
SetLightState(component, new()
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
IsActive = component.IsActive,
|
||||||
|
LightMode = lightMode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetLightState(LightComponent component, FirearmLightStateStruct lightState)
|
||||||
|
{
|
||||||
|
Player player = GamePlayerOwner.MyPlayer;
|
||||||
|
|
||||||
|
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
||||||
|
{
|
||||||
|
fc.SetLightsState([lightState]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.IsActive = lightState.IsActive;
|
||||||
|
component.SelectedMode = lightState.LightMode;
|
||||||
|
|
||||||
if (player is not null)
|
if (player is not null)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.ItemContextMenuExt</AssemblyName>
|
<AssemblyName>IcyClawz.ItemContextMenuExt</AssemblyName>
|
||||||
<Version>1.4.0</Version>
|
<Version>1.6.0</Version>
|
||||||
<RootNamespace>IcyClawz.ItemContextMenuExt</RootNamespace>
|
<RootNamespace>IcyClawz.ItemContextMenuExt</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -27,6 +27,9 @@
|
|||||||
<Reference Include="ItemTemplate.Types">
|
<Reference Include="ItemTemplate.Types">
|
||||||
<HintPath>..\Shared\ItemTemplate.Types.dll</HintPath>
|
<HintPath>..\Shared\ItemTemplate.Types.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,12 +1,35 @@
|
|||||||
using BepInEx;
|
using BepInEx;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using EFT.UI;
|
||||||
using IcyClawz.CustomInteractions;
|
using IcyClawz.CustomInteractions;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace IcyClawz.ItemContextMenuExt;
|
namespace IcyClawz.ItemContextMenuExt;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.ItemContextMenuExt", "IcyClawz.ItemContextMenuExt", "1.4.0")]
|
[BepInPlugin("com.IcyClawz.ItemContextMenuExt", "IcyClawz.ItemContextMenuExt", "1.6.0")]
|
||||||
[BepInDependency("com.IcyClawz.CustomInteractions")]
|
[BepInDependency("com.IcyClawz.CustomInteractions")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private void Awake() =>
|
private static ConfigEntry<float> ScaleConfig { get; set; }
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
const string SECTION = "Item Context Menu";
|
||||||
|
ScaleConfig = Config.Bind(SECTION, "Scale", 1f);
|
||||||
|
new ItemUiContextPatch().Enable();
|
||||||
CustomInteractionsManager.Register(new CustomInteractionsProvider());
|
CustomInteractionsManager.Register(new CustomInteractionsProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static float Scale => ScaleConfig.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ItemUiContextPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(ItemUiContext).GetMethod("ShowContextMenu", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void Postfix(ref ItemUiContext __instance) =>
|
||||||
|
__instance.ContextMenu.Transform.localScale = new(Plugin.Scale, Plugin.Scale);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
using Aki.Reflection.Utils;
|
|
||||||
using Comfort.Common;
|
using Comfort.Common;
|
||||||
using EFT;
|
using EFT;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
|
using SPT.Reflection.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
using CurrencyUtil = GClass2517;
|
using CurrencyUtil = GClass2867;
|
||||||
|
|
||||||
namespace IcyClawz.ItemSellPrice;
|
namespace IcyClawz.ItemSellPrice;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ internal static class ItemExtensions
|
|||||||
["po"] = ["Preço de venda ({0})", "Não pode ser vendido a comerciantes"],
|
["po"] = ["Preço de venda ({0})", "Não pode ser vendido a comerciantes"],
|
||||||
["ru"] = ["Цена продажи ({0})", "Невозможно продать торговцам"],
|
["ru"] = ["Цена продажи ({0})", "Невозможно продать торговцам"],
|
||||||
["sk"] = ["Predajná cena ({0})", "Nedá sa predať obchodníkom"],
|
["sk"] = ["Predajná cena ({0})", "Nedá sa predať obchodníkom"],
|
||||||
["tu"] = ["Satış fiyatı ({0})", "Tüccarlara satılamaz"]
|
["tu"] = ["Satış fiyatı ({0})", "Tüccarlara satılamaz"],
|
||||||
};
|
};
|
||||||
|
|
||||||
private static ISession _Session;
|
private static ISession _Session;
|
||||||
@ -91,11 +91,11 @@ internal static class ItemExtensions
|
|||||||
FullStringValue = () =>
|
FullStringValue = () =>
|
||||||
{
|
{
|
||||||
IEnumerable<TraderOffer> offers = GetAllTraderOffers(item);
|
IEnumerable<TraderOffer> offers = GetAllTraderOffers(item);
|
||||||
return offers is not null
|
return offers.Any()
|
||||||
? string.Join(Environment.NewLine, offers.Select(offer => $"{offer.Name}: {offer.Currency} {offer.Price}"))
|
? string.Join(Environment.NewLine, offers.Select(offer => $"{offer.Name}: {offer.Currency} {offer.Price}"))
|
||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
};
|
};
|
||||||
item.Attributes = [attribute, .. item.Attributes];
|
item.Attributes = [attribute, .. item.Attributes];
|
||||||
}
|
}
|
||||||
@ -111,38 +111,34 @@ internal static class ItemExtensions
|
|||||||
|
|
||||||
private static TraderOffer GetTraderOffer(Item item, TraderClass trader)
|
private static TraderOffer GetTraderOffer(Item item, TraderClass trader)
|
||||||
{
|
{
|
||||||
var result = trader.GetUserItemPrice(item);
|
var price = trader.GetUserItemPrice(item);
|
||||||
return result is null ? null : new(
|
return price.HasValue ? new(
|
||||||
trader.LocalizedName,
|
trader.LocalizedName,
|
||||||
result.Value.Amount,
|
price.Value.Amount,
|
||||||
CurrencyUtil.GetCurrencyCharById(result.Value.CurrencyId),
|
CurrencyUtil.GetCurrencyCharById(price.Value.CurrencyId.Value),
|
||||||
trader.GetSupplyData().CurrencyCourses[result.Value.CurrencyId],
|
trader.GetSupplyData().CurrencyCourses[price.Value.CurrencyId.Value],
|
||||||
item.StackObjectsCount
|
item.StackObjectsCount
|
||||||
);
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<TraderOffer> GetAllTraderOffers(Item item)
|
private static IEnumerable<TraderOffer> GetAllTraderOffers(Item item)
|
||||||
{
|
{
|
||||||
if (!Session.Profile.Examined(item))
|
if (!Session.Profile.Examined(item))
|
||||||
return null;
|
return [];
|
||||||
switch (item.Owner?.OwnerType)
|
if (item.Owner?.OwnerType is EOwnerType.RagFair or EOwnerType.Trader
|
||||||
|
&& (item.StackObjectsCount > 1 || item.UnlimitedCount))
|
||||||
{
|
{
|
||||||
case EOwnerType.RagFair:
|
item = item.CloneItem();
|
||||||
case EOwnerType.Trader:
|
item.StackObjectsCount = 1;
|
||||||
if (item.StackObjectsCount > 1 || item.UnlimitedCount)
|
item.UnlimitedCount = false;
|
||||||
{
|
|
||||||
item = item.CloneItem();
|
|
||||||
item.StackObjectsCount = 1;
|
|
||||||
item.UnlimitedCount = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return Session.Traders
|
return Session.Traders
|
||||||
|
.Where(trader => !trader.Settings.AvailableInRaid)
|
||||||
.Select(trader => GetTraderOffer(item, trader))
|
.Select(trader => GetTraderOffer(item, trader))
|
||||||
.Where(offer => offer is not null)
|
.Where(offer => offer is not null)
|
||||||
.OrderByDescending(offer => offer.Price * offer.Course);
|
.OrderByDescending(offer => offer.Price * offer.Course);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TraderOffer GetBestTraderOffer(Item item) =>
|
private static TraderOffer GetBestTraderOffer(Item item) =>
|
||||||
GetAllTraderOffers(item)?.FirstOrDefault() ?? null;
|
GetAllTraderOffers(item).FirstOrDefault();
|
||||||
}
|
}
|
@ -3,15 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.ItemSellPrice</AssemblyName>
|
<AssemblyName>IcyClawz.ItemSellPrice</AssemblyName>
|
||||||
<Version>1.3.0</Version>
|
<Version>1.5.0</Version>
|
||||||
<RootNamespace>IcyClawz.ItemSellPrice</RootNamespace>
|
<RootNamespace>IcyClawz.ItemSellPrice</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Aki.Reflection">
|
|
||||||
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@ -21,6 +18,9 @@
|
|||||||
<Reference Include="Comfort">
|
<Reference Include="Comfort">
|
||||||
<HintPath>..\Shared\Comfort.dll</HintPath>
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
using Aki.Reflection.Patching;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
|
using EFT;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace IcyClawz.ItemSellPrice;
|
namespace IcyClawz.ItemSellPrice;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.ItemSellPrice", "IcyClawz.ItemSellPrice", "1.3.0")]
|
[BepInPlugin("com.IcyClawz.ItemSellPrice", "IcyClawz.ItemSellPrice", "1.5.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
new TraderPatch().Enable();
|
new TraderPatch().Enable();
|
||||||
new ItemPatch().Enable();
|
new ItemPatch().Enable();
|
||||||
new AmmoPatch().Enable();
|
new AmmoItemPatch().Enable();
|
||||||
new GrenadePatch().Enable();
|
new ThrowWeapItemPatch().Enable();
|
||||||
new SecureContainerPatch().Enable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,32 +38,22 @@ internal class ItemPatch : ModulePatch
|
|||||||
__instance.AddTraderOfferAttribute();
|
__instance.AddTraderOfferAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AmmoPatch : ModulePatch
|
internal class AmmoItemPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod() =>
|
protected override MethodBase GetTargetMethod() =>
|
||||||
typeof(BulletClass).GetConstructors()[0];
|
typeof(AmmoItemClass).GetConstructors()[0];
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
private static void PatchPostfix(ref BulletClass __instance) =>
|
private static void PatchPostfix(ref AmmoItemClass __instance) =>
|
||||||
__instance.AddTraderOfferAttribute();
|
__instance.AddTraderOfferAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class GrenadePatch : ModulePatch
|
internal class ThrowWeapItemPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod() =>
|
protected override MethodBase GetTargetMethod() =>
|
||||||
typeof(GrenadeClass).GetConstructors()[0];
|
typeof(ThrowWeapItemClass).GetConstructors()[0];
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
private static void PatchPostfix(ref GrenadeClass __instance) =>
|
private static void PatchPostfix(ref ThrowWeapItemClass __instance) =>
|
||||||
__instance.AddTraderOfferAttribute();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SecureContainerPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod() =>
|
|
||||||
typeof(ItemContainerClass).GetConstructors()[0];
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
private static void PatchPostfix(ref ItemContainerClass __instance) =>
|
|
||||||
__instance.AddTraderOfferAttribute();
|
__instance.AddTraderOfferAttribute();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
using Aki.Reflection.Utils;
|
|
||||||
using Comfort.Common;
|
using Comfort.Common;
|
||||||
using EFT;
|
using EFT;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
|
using SPT.Reflection.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
using InGameStatus = GClass1849;
|
using InGameStatus = GClass2064;
|
||||||
|
|
||||||
namespace IcyClawz.MagazineInspector;
|
namespace IcyClawz.MagazineInspector;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ internal static class MagazineClassExtensions
|
|||||||
["po"] = "Munição carregada",
|
["po"] = "Munição carregada",
|
||||||
["ru"] = "Заряженные боеприпасы",
|
["ru"] = "Заряженные боеприпасы",
|
||||||
["sk"] = "Nabitá munícia",
|
["sk"] = "Nabitá munícia",
|
||||||
["tu"] = "Yüklü mühimmat"
|
["tu"] = "Yüklü mühimmat",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static ISession _Session;
|
private static ISession _Session;
|
||||||
@ -38,7 +38,7 @@ internal static class MagazineClassExtensions
|
|||||||
|
|
||||||
private static Profile ActiveProfile => InGameStatus.InRaid ? GamePlayerOwner.MyPlayer.Profile : Session.Profile;
|
private static Profile ActiveProfile => InGameStatus.InRaid ? GamePlayerOwner.MyPlayer.Profile : Session.Profile;
|
||||||
|
|
||||||
public static void AddAmmoCountAttribute(this MagazineClass magazine)
|
public static void AddAmmoCountAttribute(this MagazineItemClass magazine)
|
||||||
{
|
{
|
||||||
ItemAttributeClass attribute = magazine.Attributes.Find(attr => attr.Id is EItemAttributeId.MaxCount);
|
ItemAttributeClass attribute = magazine.Attributes.Find(attr => attr.Id is EItemAttributeId.MaxCount);
|
||||||
if (attribute is null)
|
if (attribute is null)
|
||||||
@ -74,7 +74,7 @@ internal static class MagazineClassExtensions
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int? GetAmmoCount(MagazineClass magazine, Profile profile, out bool magChecked)
|
private static int? GetAmmoCount(MagazineItemClass magazine, Profile profile, out bool magChecked)
|
||||||
{
|
{
|
||||||
if (!InGameStatus.InRaid || magazine.Count == 0)
|
if (!InGameStatus.InRaid || magazine.Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -3,15 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.MagazineInspector</AssemblyName>
|
<AssemblyName>IcyClawz.MagazineInspector</AssemblyName>
|
||||||
<Version>1.3.0</Version>
|
<Version>1.5.0</Version>
|
||||||
<RootNamespace>IcyClawz.MagazineInspector</RootNamespace>
|
<RootNamespace>IcyClawz.MagazineInspector</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Aki.Reflection">
|
|
||||||
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@ -21,6 +18,9 @@
|
|||||||
<Reference Include="Comfort">
|
<Reference Include="Comfort">
|
||||||
<HintPath>..\Shared\Comfort.dll</HintPath>
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using Aki.Reflection.Patching;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace IcyClawz.MagazineInspector;
|
namespace IcyClawz.MagazineInspector;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.MagazineInspector", "IcyClawz.MagazineInspector", "1.3.0")]
|
[BepInPlugin("com.IcyClawz.MagazineInspector", "IcyClawz.MagazineInspector", "1.5.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private void Awake() =>
|
private void Awake() =>
|
||||||
@ -14,9 +14,9 @@ public class Plugin : BaseUnityPlugin
|
|||||||
internal class MagazinePatch : ModulePatch
|
internal class MagazinePatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod() =>
|
protected override MethodBase GetTargetMethod() =>
|
||||||
typeof(MagazineClass).GetConstructors()[0];
|
typeof(MagazineItemClass).GetConstructors()[0];
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
private static void PatchPostfix(ref MagazineClass __instance) =>
|
private static void PatchPostfix(ref MagazineItemClass __instance) =>
|
||||||
__instance.AddAmmoCountAttribute();
|
__instance.AddAmmoCountAttribute();
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ internal static class ColorCache
|
|||||||
[ColorName.Silver] = new Color32(150, 150, 150, ALPHA),
|
[ColorName.Silver] = new Color32(150, 150, 150, ALPHA),
|
||||||
[ColorName.Tan] = new Color32(175, 145, 100, ALPHA),
|
[ColorName.Tan] = new Color32(175, 145, 100, ALPHA),
|
||||||
[ColorName.Violet] = new Color32(80, 50, 180, ALPHA),
|
[ColorName.Violet] = new Color32(80, 50, 180, ALPHA),
|
||||||
[ColorName.Yellow] = new Color32(170, 170, 0, ALPHA)
|
[ColorName.Yellow] = new Color32(170, 170, 0, ALPHA),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Color Get(ColorName name) => Cache.TryGetValue(name, out Color color) ? color : default;
|
public static Color Get(ColorName name) => Cache.TryGetValue(name, out Color color) ? color : default;
|
||||||
@ -39,7 +39,7 @@ internal static class ColorCache
|
|||||||
|
|
||||||
internal enum EAmmoExtraAttributeId
|
internal enum EAmmoExtraAttributeId
|
||||||
{
|
{
|
||||||
Damage, PenetrationPower, ArmorDamage, FragmentationChance, RicochetChance
|
ArmorDamage, FragmentationChance, RicochetChance
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class ImageExtensions
|
internal static class ImageExtensions
|
||||||
@ -48,8 +48,8 @@ internal static class ImageExtensions
|
|||||||
{
|
{
|
||||||
using MemoryStream ms = new();
|
using MemoryStream ms = new();
|
||||||
instance.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
instance.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||||
Texture2D texture = new(instance.Width, instance.Height);
|
Texture2D texture = new(instance.Width, instance.Height, TextureFormat.RGBA32, false);
|
||||||
ImageConversion.LoadImage(texture, ms.ToArray());
|
texture.LoadImage(ms.ToArray());
|
||||||
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,11 +58,9 @@ internal static class IconCache
|
|||||||
{
|
{
|
||||||
private static readonly Dictionary<Enum, Sprite> Cache = new()
|
private static readonly Dictionary<Enum, Sprite> Cache = new()
|
||||||
{
|
{
|
||||||
[EAmmoExtraAttributeId.Damage] = Properties.Resources.Damage.ToSprite(),
|
|
||||||
[EAmmoExtraAttributeId.PenetrationPower] = Properties.Resources.PenetrationPower.ToSprite(),
|
|
||||||
[EAmmoExtraAttributeId.ArmorDamage] = Properties.Resources.ArmorDamage.ToSprite(),
|
[EAmmoExtraAttributeId.ArmorDamage] = Properties.Resources.ArmorDamage.ToSprite(),
|
||||||
[EAmmoExtraAttributeId.FragmentationChance] = Properties.Resources.FragmentationChance.ToSprite(),
|
[EAmmoExtraAttributeId.FragmentationChance] = Properties.Resources.FragmentationChance.ToSprite(),
|
||||||
[EAmmoExtraAttributeId.RicochetChance] = Properties.Resources.RicochetChance.ToSprite()
|
[EAmmoExtraAttributeId.RicochetChance] = Properties.Resources.RicochetChance.ToSprite(),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Sprite Get(Enum id) => Cache.TryGetValue(id, out Sprite sprite) ? sprite : default;
|
public static Sprite Get(Enum id) => Cache.TryGetValue(id, out Sprite sprite) ? sprite : default;
|
||||||
@ -70,6 +68,15 @@ internal static class IconCache
|
|||||||
|
|
||||||
internal static class AmmoTemplateExtensions
|
internal static class AmmoTemplateExtensions
|
||||||
{
|
{
|
||||||
|
private static readonly string[] MalfChancesKeys = (string[])
|
||||||
|
typeof(AmmoTemplate).GetField("MalfChancesKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
|
||||||
|
|
||||||
|
private static readonly FieldInfo MaxMalfMisfireChance =
|
||||||
|
typeof(AmmoTemplate).GetField("MaxMalfMisfireChance", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
|
||||||
|
private static readonly FieldInfo MaxMalfFeedChance =
|
||||||
|
typeof(AmmoTemplate).GetField("MaxMalfFeedChance", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
|
||||||
private static readonly FieldInfo CachedQualitiesField =
|
private static readonly FieldInfo CachedQualitiesField =
|
||||||
typeof(AmmoTemplate).GetField("_cachedQualities", BindingFlags.NonPublic | BindingFlags.Instance);
|
typeof(AmmoTemplate).GetField("_cachedQualities", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
@ -78,41 +85,33 @@ internal static class AmmoTemplateExtensions
|
|||||||
|
|
||||||
public static void AddExtraAttributes(this AmmoTemplate instance)
|
public static void AddExtraAttributes(this AmmoTemplate instance)
|
||||||
{
|
{
|
||||||
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.Damage)
|
|
||||||
{
|
|
||||||
Name = EAmmoExtraAttributeId.Damage.ToString(),
|
|
||||||
DisplayNameFunc = () => "Damage",
|
|
||||||
Base = () => instance.Damage * instance.ProjectileCount,
|
|
||||||
StringValue = () =>
|
|
||||||
{
|
|
||||||
int totalDamage = instance.Damage * instance.ProjectileCount;
|
|
||||||
return instance.ProjectileCount > 1
|
|
||||||
? $"{instance.ProjectileCount} × {instance.Damage} = {totalDamage}"
|
|
||||||
: totalDamage.ToString();
|
|
||||||
},
|
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.PenetrationPower)
|
|
||||||
{
|
|
||||||
Name = EAmmoExtraAttributeId.PenetrationPower.ToString(),
|
|
||||||
DisplayNameFunc = () => "Penetration power",
|
|
||||||
Base = () => instance.PenetrationPower,
|
|
||||||
StringValue = () =>
|
|
||||||
{
|
|
||||||
int armorClass = instance.GetPenetrationArmorClass();
|
|
||||||
return (armorClass > 0 ? $"Class {armorClass}" : "Unarmored") + $" ({instance.PenetrationPower})";
|
|
||||||
},
|
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.ArmorDamage)
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.ArmorDamage)
|
||||||
{
|
{
|
||||||
Name = EAmmoExtraAttributeId.ArmorDamage.ToString(),
|
Name = EAmmoExtraAttributeId.ArmorDamage.ToString(),
|
||||||
DisplayNameFunc = () => "Armor damage",
|
DisplayNameFunc = () => "Armor damage",
|
||||||
Base = () => instance.ArmorDamage,
|
Base = () => instance.ArmorDamage,
|
||||||
StringValue = () => $"{instance.ArmorDamage}%",
|
StringValue = () => $"{instance.ArmorDamage}%",
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EItemAttributeId.DurabilityBurn)
|
||||||
|
{
|
||||||
|
Name = EItemAttributeId.DurabilityBurn.GetName(),
|
||||||
|
Base = () => instance.DurabilityBurnModificator - 1f,
|
||||||
|
StringValue = () => $"{(instance.DurabilityBurnModificator - 1f) * 100f:F1}%",
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
|
LabelVariations = EItemAttributeLabelVariations.Colored,
|
||||||
|
LessIsGood = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EItemAttributeId.HeatFactor)
|
||||||
|
{
|
||||||
|
Name = EItemAttributeId.HeatFactor.GetName(),
|
||||||
|
Base = () => instance.HeatFactor - 1f,
|
||||||
|
StringValue = () => $"{(instance.HeatFactor - 1f) * 100f:F1}%",
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
|
LabelVariations = EItemAttributeLabelVariations.Colored,
|
||||||
|
LessIsGood = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.FragmentationChance)
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.FragmentationChance)
|
||||||
@ -120,8 +119,8 @@ internal static class AmmoTemplateExtensions
|
|||||||
Name = EAmmoExtraAttributeId.FragmentationChance.ToString(),
|
Name = EAmmoExtraAttributeId.FragmentationChance.ToString(),
|
||||||
DisplayNameFunc = () => "Fragmentation chance",
|
DisplayNameFunc = () => "Fragmentation chance",
|
||||||
Base = () => instance.FragmentationChance,
|
Base = () => instance.FragmentationChance,
|
||||||
StringValue = () => $"{Math.Round(instance.FragmentationChance * 100, 1)}%",
|
StringValue = () => $"{instance.FragmentationChance * 100f:F1}%",
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.RicochetChance)
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.RicochetChance)
|
||||||
@ -129,8 +128,44 @@ internal static class AmmoTemplateExtensions
|
|||||||
Name = EAmmoExtraAttributeId.RicochetChance.ToString(),
|
Name = EAmmoExtraAttributeId.RicochetChance.ToString(),
|
||||||
DisplayNameFunc = () => "Ricochet chance",
|
DisplayNameFunc = () => "Ricochet chance",
|
||||||
Base = () => instance.RicochetChance,
|
Base = () => instance.RicochetChance,
|
||||||
StringValue = () => $"{Math.Round(instance.RicochetChance * 100, 1)}%",
|
StringValue = () => $"{(instance.RicochetChance * 100f):F1}%",
|
||||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EItemAttributeId.MalfMisfireChance)
|
||||||
|
{
|
||||||
|
Name = EItemAttributeId.MalfMisfireChance.GetName(),
|
||||||
|
Base = () => instance.MalfMisfireChance,
|
||||||
|
StringValue = () =>
|
||||||
|
{
|
||||||
|
float maxMalfMisfireChance = (float)MaxMalfMisfireChance.GetValue(null);
|
||||||
|
int index = instance.MalfMisfireChance <= 0f ? 0
|
||||||
|
: instance.MalfMisfireChance < 3f * maxMalfMisfireChance / 7f ? 1
|
||||||
|
: instance.MalfMisfireChance < 4f * maxMalfMisfireChance / 7f ? 2
|
||||||
|
: instance.MalfMisfireChance < 5f * maxMalfMisfireChance / 7f ? 3
|
||||||
|
: instance.MalfMisfireChance < 6f * maxMalfMisfireChance / 7f ? 4
|
||||||
|
: 5;
|
||||||
|
return MalfChancesKeys[index].Localized();
|
||||||
|
},
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EItemAttributeId.MalfFeedChance)
|
||||||
|
{
|
||||||
|
Name = EItemAttributeId.MalfFeedChance.GetName(),
|
||||||
|
Base = () => instance.MalfFeedChance,
|
||||||
|
StringValue = () =>
|
||||||
|
{
|
||||||
|
float maxMalfFeedChance = (float)MaxMalfFeedChance.GetValue(null);
|
||||||
|
int index = instance.MalfFeedChance <= 0f ? 0
|
||||||
|
: instance.MalfFeedChance < 1f * maxMalfFeedChance / 7f ? 1
|
||||||
|
: instance.MalfFeedChance < 3f * maxMalfFeedChance / 7f ? 2
|
||||||
|
: instance.MalfFeedChance < 5f * maxMalfFeedChance / 7f ? 3
|
||||||
|
: instance.MalfFeedChance < 6f * maxMalfFeedChance / 7f ? 4
|
||||||
|
: 5;
|
||||||
|
return MalfChancesKeys[index].Localized();
|
||||||
|
},
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AssemblyName>IcyClawz.MunitionsExpert</AssemblyName>
|
<AssemblyName>IcyClawz.MunitionsExpert</AssemblyName>
|
||||||
<Version>1.3.0</Version>
|
<Version>1.5.0</Version>
|
||||||
<RootNamespace>IcyClawz.MunitionsExpert</RootNamespace>
|
<RootNamespace>IcyClawz.MunitionsExpert</RootNamespace>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Aki.Reflection">
|
|
||||||
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@ -24,6 +21,9 @@
|
|||||||
<Reference Include="Sirenix.Serialization">
|
<Reference Include="Sirenix.Serialization">
|
||||||
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SPT.Reflection">
|
||||||
|
<HintPath>..\Shared\spt-reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using Aki.Reflection.Patching;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using EFT.HandBook;
|
using EFT.HandBook;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
|
using SPT.Reflection.Patching;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -13,24 +13,24 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
namespace IcyClawz.MunitionsExpert;
|
namespace IcyClawz.MunitionsExpert;
|
||||||
|
|
||||||
[BepInPlugin("com.IcyClawz.MunitionsExpert", "IcyClawz.MunitionsExpert", "1.3.0")]
|
[BepInPlugin("com.IcyClawz.MunitionsExpert", "IcyClawz.MunitionsExpert", "1.5.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
private static ConfigEntry<bool> ColorizeSwitch { get; set; }
|
private static ConfigEntry<bool> ColorizeConfig { get; set; }
|
||||||
private static ConfigEntry<ColorName>[] ArmorClassColors { get; set; }
|
private static ConfigEntry<ColorName>[] ArmorClassColorConfigs { get; set; }
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
const string COLORIZE = "Colorize Icon Backgrounds";
|
const string SECTION = "Colorize Icon Backgrounds";
|
||||||
ColorizeSwitch = Config.Bind(COLORIZE, "", true, new ConfigurationManagerAttributes { Order = 7 });
|
ColorizeConfig = Config.Bind(SECTION, "", true, new ConfigurationManagerAttributes { Order = 7 });
|
||||||
ArmorClassColors = [
|
ArmorClassColorConfigs = [
|
||||||
Config.Bind(COLORIZE, "Unarmored", ColorName.Purple, new ConfigurationManagerAttributes { Order = 6 }),
|
Config.Bind(SECTION, "Unarmored", ColorName.Purple, new ConfigurationManagerAttributes { Order = 6 }),
|
||||||
Config.Bind(COLORIZE, "Class 1", ColorName.Blue, new ConfigurationManagerAttributes { Order = 5 }),
|
Config.Bind(SECTION, "Class 1", ColorName.Blue, new ConfigurationManagerAttributes { Order = 5 }),
|
||||||
Config.Bind(COLORIZE, "Class 2", ColorName.Cyan, new ConfigurationManagerAttributes { Order = 4 }),
|
Config.Bind(SECTION, "Class 2", ColorName.Cyan, new ConfigurationManagerAttributes { Order = 4 }),
|
||||||
Config.Bind(COLORIZE, "Class 3", ColorName.Green, new ConfigurationManagerAttributes { Order = 3 }),
|
Config.Bind(SECTION, "Class 3", ColorName.Green, new ConfigurationManagerAttributes { Order = 3 }),
|
||||||
Config.Bind(COLORIZE, "Class 4", ColorName.Yellow, new ConfigurationManagerAttributes { Order = 2 }),
|
Config.Bind(SECTION, "Class 4", ColorName.Yellow, new ConfigurationManagerAttributes { Order = 2 }),
|
||||||
Config.Bind(COLORIZE, "Class 5", ColorName.Orange, new ConfigurationManagerAttributes { Order = 1 }),
|
Config.Bind(SECTION, "Class 5", ColorName.Orange, new ConfigurationManagerAttributes { Order = 1 }),
|
||||||
Config.Bind(COLORIZE, "Class 6+", ColorName.Red, new ConfigurationManagerAttributes { Order = 0 })
|
Config.Bind(SECTION, "Class 6+", ColorName.Red, new ConfigurationManagerAttributes { Order = 0 }),
|
||||||
];
|
];
|
||||||
new StaticIconsPatch().Enable();
|
new StaticIconsPatch().Enable();
|
||||||
new AmmoTemplatePatch().Enable();
|
new AmmoTemplatePatch().Enable();
|
||||||
@ -38,12 +38,12 @@ public class Plugin : BaseUnityPlugin
|
|||||||
new EntityIconPatch().Enable();
|
new EntityIconPatch().Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool Colorize => ColorizeSwitch.Value;
|
internal static bool Colorize => ColorizeConfig.Value;
|
||||||
|
|
||||||
internal static Color GetArmorClassColor(int index)
|
internal static Color GetArmorClassColor(int index)
|
||||||
{
|
{
|
||||||
index = Mathf.Clamp(index, 0, ArmorClassColors.Length - 1);
|
index = Mathf.Clamp(index, 0, ArmorClassColorConfigs.Length - 1);
|
||||||
return ColorCache.Get(ArmorClassColors[index].Value);
|
return ColorCache.Get(ArmorClassColorConfigs[index].Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ internal class ItemViewPatch : ModulePatch
|
|||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
private static void PatchPrefix(ref ItemView __instance)
|
private static void PatchPrefix(ref ItemView __instance)
|
||||||
{
|
{
|
||||||
if (!Plugin.Colorize || __instance.Item is not BulletClass bullet || bullet.PenetrationPower <= 0)
|
if (!Plugin.Colorize || __instance.Item is not AmmoItemClass ammo || ammo.PenetrationPower <= 0)
|
||||||
return;
|
return;
|
||||||
int armorClass = bullet.AmmoTemplate.GetPenetrationArmorClass();
|
int armorClass = ammo.AmmoTemplate.GetPenetrationArmorClass();
|
||||||
BackgroundColorField.SetValue(__instance, Plugin.GetArmorClassColor(armorClass));
|
BackgroundColorField.SetValue(__instance, Plugin.GetArmorClassColor(armorClass));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,10 +105,11 @@ internal class EntityIconPatch : ModulePatch
|
|||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
private static void PatchPostfix(ref EntityIcon __instance, Item item)
|
private static void PatchPostfix(ref EntityIcon __instance, Item item)
|
||||||
{
|
{
|
||||||
if (!Plugin.Colorize || item is not BulletClass bullet || bullet.PenetrationPower <= 0)
|
if (!Plugin.Colorize || item is not AmmoItemClass ammo || ammo.PenetrationPower <= 0)
|
||||||
return;
|
return;
|
||||||
int armorClass = bullet.AmmoTemplate.GetPenetrationArmorClass();
|
if (ColorPanelField.GetValue(__instance) is not Image image)
|
||||||
if (ColorPanelField.GetValue(__instance) is Image image)
|
return;
|
||||||
image.color = Plugin.GetArmorClassColor(armorClass);
|
int armorClass = ammo.AmmoTemplate.GetPenetrationArmorClass();
|
||||||
|
image.color = Plugin.GetArmorClassColor(armorClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
MunitionsExpert/Properties/Resources.Designer.cs
generated
20
MunitionsExpert/Properties/Resources.Designer.cs
generated
@ -70,16 +70,6 @@ internal class Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap Damage {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("Damage", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,16 +80,6 @@ internal class Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap PenetrationPower {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("PenetrationPower", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -121,15 +121,9 @@
|
|||||||
<data name="ArmorDamage" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="ArmorDamage" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\ArmorDamage.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\ArmorDamage.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Damage" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\Damage.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="FragmentationChance" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="FragmentationChance" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\FragmentationChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\FragmentationChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PenetrationPower" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\PenetrationPower.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="RicochetChance" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="RicochetChance" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\RicochetChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\RicochetChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 764 B |
Binary file not shown.
Before Width: | Height: | Size: 468 B |
Loading…
x
Reference in New Issue
Block a user