Merged to one repo cause platform is limited to 5 repos
This commit is contained in:
parent
b35f28cd81
commit
f5d3431f71
38
CustomInteractions.Prepatch/Prepatch.cs
Normal file
38
CustomInteractions.Prepatch/Prepatch.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Mono.Cecil;
|
||||||
|
|
||||||
|
namespace IcyClawz.CustomInteractions
|
||||||
|
{
|
||||||
|
public static class Prepatch
|
||||||
|
{
|
||||||
|
public static IEnumerable<string> TargetDLLs => new[] { "Assembly-CSharp.dll" };
|
||||||
|
|
||||||
|
public static void Patch(ref AssemblyDefinition assembly)
|
||||||
|
{
|
||||||
|
var type = assembly.MainModule.GetType("GClass2654"); // DynamicInteraction
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
type.IsSealed = false;
|
||||||
|
var field = type.Fields.SingleOrDefault(c => c.Name == "action_0");
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
field.IsFamily = true;
|
||||||
|
field.IsInitOnly = false;
|
||||||
|
}
|
||||||
|
var ctor = type.Methods.SingleOrDefault(c => c.Name == ".ctor");
|
||||||
|
if (ctor != null)
|
||||||
|
{
|
||||||
|
var param = ctor.Parameters.SingleOrDefault(c => c.Name == "callback");
|
||||||
|
if (param != null)
|
||||||
|
{
|
||||||
|
param.IsOptional = true;
|
||||||
|
param.HasDefault = true;
|
||||||
|
param.Constant = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//assembly.Write("Assembly-CSharp-CustomInteractions.dll");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
CustomInteractions.Prepatch/Prepatch.csproj
Normal file
16
CustomInteractions.Prepatch/Prepatch.csproj
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.CustomInteractions.Prepatch</AssemblyName>
|
||||||
|
<Version>1.1.1</Version>
|
||||||
|
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Mono.Cecil">
|
||||||
|
<HintPath>..\Shared\Mono.Cecil.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
30
CustomInteractions.sln
Normal file
30
CustomInteractions.sln
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomInteractions", "CustomInteractions\CustomInteractions.csproj", "{F296FF55-A8D8-47E3-90C0-6975CA0787F9}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomInteractions.Prepatch", "CustomInteractions.Prepatch\Prepatch.csproj", "{E8C5359B-95CE-4547-B72E-C9BEBB9220CC}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F296FF55-A8D8-47E3-90C0-6975CA0787F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F296FF55-A8D8-47E3-90C0-6975CA0787F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F296FF55-A8D8-47E3-90C0-6975CA0787F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F296FF55-A8D8-47E3-90C0-6975CA0787F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E8C5359B-95CE-4547-B72E-C9BEBB9220CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E8C5359B-95CE-4547-B72E-C9BEBB9220CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E8C5359B-95CE-4547-B72E-C9BEBB9220CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E8C5359B-95CE-4547-B72E-C9BEBB9220CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BF50C8C8-82A6-496A-B4A4-DB383A88705D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
206
CustomInteractions/CustomInteractions.cs
Normal file
206
CustomInteractions/CustomInteractions.cs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using DynamicInteraction = GClass2654;
|
||||||
|
using EmptyInteractions = GClass2655<System.Enum>;
|
||||||
|
|
||||||
|
namespace IcyClawz.CustomInteractions
|
||||||
|
{
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public interface ICustomInteractionsProvider { } // Do not implement this directly
|
||||||
|
|
||||||
|
public interface IItemCustomInteractionsProvider : ICustomInteractionsProvider
|
||||||
|
{
|
||||||
|
IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomInteractionsManager
|
||||||
|
{
|
||||||
|
internal static readonly List<ICustomInteractionsProvider> Providers = new List<ICustomInteractionsProvider>();
|
||||||
|
|
||||||
|
public static void Register(ICustomInteractionsProvider provider)
|
||||||
|
{
|
||||||
|
if (!Providers.Contains(provider))
|
||||||
|
{
|
||||||
|
Providers.Add(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomInteraction
|
||||||
|
{
|
||||||
|
internal readonly CustomInteractionImpl Impl;
|
||||||
|
|
||||||
|
public CustomInteraction()
|
||||||
|
{
|
||||||
|
Impl = new CustomInteractionImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<string> Caption { get => Impl.Caption; set => Impl.Caption = value; }
|
||||||
|
public Func<Sprite> Icon { get => Impl.Icon; set => Impl.Icon = value; }
|
||||||
|
public Action Action { get => Impl.Action; set => Impl.Action = value; }
|
||||||
|
public Func<CustomSubInteractions> SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; }
|
||||||
|
public Func<bool> Enabled { get => Impl.Enabled; set => Impl.Enabled = value; }
|
||||||
|
public Func<string> Error { get => Impl.Error; set => Impl.Error = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class CustomInteractionImpl : DynamicInteraction
|
||||||
|
{
|
||||||
|
public CustomInteractionImpl()
|
||||||
|
: base(UnityEngine.Random.Range(0, int.MaxValue).ToString("x4")) { }
|
||||||
|
|
||||||
|
public Func<string> Caption { get; set; }
|
||||||
|
public new Func<Sprite> Icon { get; set; }
|
||||||
|
public Action Action { get => action_0; set => action_0 = value; }
|
||||||
|
public Func<CustomSubInteractions> SubMenu { get; set; }
|
||||||
|
public Func<bool> Enabled { get; set; }
|
||||||
|
public Func<string> Error { get; set; }
|
||||||
|
|
||||||
|
public bool IsInteractive() =>
|
||||||
|
Enabled?.Invoke() ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class CustomSubInteractions
|
||||||
|
{
|
||||||
|
internal readonly CustomSubInteractionsImpl Impl;
|
||||||
|
|
||||||
|
public CustomSubInteractions(ItemUiContext uiContext)
|
||||||
|
{
|
||||||
|
Impl = new CustomSubInteractionsImpl(uiContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ExaminationRequired { get => Impl._ExaminationRequired; set => Impl._ExaminationRequired = value; }
|
||||||
|
|
||||||
|
public void Add(CustomInteraction customInteraction) =>
|
||||||
|
Impl.AddCustomInteraction(customInteraction);
|
||||||
|
|
||||||
|
public void Remove(CustomInteraction customInteraction) =>
|
||||||
|
Impl.RemoveCustomInteraction(customInteraction);
|
||||||
|
|
||||||
|
public void CallRedraw() =>
|
||||||
|
Impl.CallRedraw();
|
||||||
|
|
||||||
|
public void CallRedraw(string templateId) =>
|
||||||
|
Impl.CallRedraw(templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class CustomSubInteractionsImpl : EmptyInteractions
|
||||||
|
{
|
||||||
|
public CustomSubInteractionsImpl(ItemUiContext uiContext)
|
||||||
|
: base(uiContext) { }
|
||||||
|
|
||||||
|
public IEnumerable<CustomInteractionImpl> CustomInteractions => DynamicInteractions.OfType<CustomInteractionImpl>();
|
||||||
|
|
||||||
|
public bool _ExaminationRequired { get; set; } = true;
|
||||||
|
|
||||||
|
public override bool ExaminationRequired => _ExaminationRequired;
|
||||||
|
|
||||||
|
public override bool HasIcons => CustomInteractions.Any(customInteraction => customInteraction.Icon != null);
|
||||||
|
|
||||||
|
public void CallRedraw() =>
|
||||||
|
itemUiContext_0.RedrawContextMenus(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class AbstractInteractionsExtensions
|
||||||
|
{
|
||||||
|
private static Dictionary<string, DynamicInteraction> GetDynamicInteractions<T>(this GClass2655<T> instance) where T : Enum =>
|
||||||
|
typeof(GClass2655<T>).GetField("dictionary_1", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
|
.GetValue(instance) as Dictionary<string, DynamicInteraction>;
|
||||||
|
|
||||||
|
public static void AddCustomInteraction<T>(this GClass2655<T> instance, CustomInteraction customInteraction) where T : Enum =>
|
||||||
|
instance.GetDynamicInteractions()[customInteraction.Impl.Key] = customInteraction.Impl;
|
||||||
|
|
||||||
|
public static void RemoveCustomInteraction<T>(this GClass2655<T> instance, CustomInteraction customInteraction) where T : Enum =>
|
||||||
|
instance.GetDynamicInteractions().Remove(customInteraction.Impl.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class InteractionButtonsContainerExtensions
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo ButtonsContainerField =
|
||||||
|
typeof(InteractionButtonsContainer).GetField("_buttonsContainer", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static RectTransform GetButtonsContainer(this InteractionButtonsContainer instance) =>
|
||||||
|
ButtonsContainerField.GetValue(instance) as RectTransform;
|
||||||
|
|
||||||
|
private static readonly FieldInfo ButtonTemplateField =
|
||||||
|
typeof(InteractionButtonsContainer).GetField("_buttonTemplate", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static SimpleContextMenuButton GetButtonTemplate(this InteractionButtonsContainer instance) =>
|
||||||
|
ButtonTemplateField.GetValue(instance) as SimpleContextMenuButton;
|
||||||
|
|
||||||
|
private static readonly FieldInfo CurrentButtonField =
|
||||||
|
typeof(InteractionButtonsContainer).GetField("simpleContextMenuButton_0", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static void SetCurrentButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
|
||||||
|
CurrentButtonField.SetValue(instance, button);
|
||||||
|
|
||||||
|
private static readonly MethodInfo CreateButtonMethod =
|
||||||
|
typeof(InteractionButtonsContainer).GetMethod("method_1", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static SimpleContextMenuButton CreateButton(this InteractionButtonsContainer instance,
|
||||||
|
string key, string caption, SimpleContextMenuButton template, RectTransform container,
|
||||||
|
[CanBeNull] Sprite sprite, [CanBeNull] Action onButtonClicked, [CanBeNull] Action onMouseHover,
|
||||||
|
bool subMenu = false, bool autoClose = true) =>
|
||||||
|
(SimpleContextMenuButton)CreateButtonMethod.Invoke(instance, new object[] {
|
||||||
|
key, caption, template, container, sprite, onButtonClicked, onMouseHover, subMenu, autoClose
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly MethodInfo CloseSubMenuMethod =
|
||||||
|
typeof(InteractionButtonsContainer).GetMethod("method_4", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static void CloseSubMenu(this InteractionButtonsContainer instance) =>
|
||||||
|
CloseSubMenuMethod.Invoke(instance, null);
|
||||||
|
|
||||||
|
private static readonly MethodInfo AddButtonMethod =
|
||||||
|
typeof(InteractionButtonsContainer).GetMethod("method_5", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static void AddButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
|
||||||
|
AddButtonMethod.Invoke(instance, new object[] { button });
|
||||||
|
|
||||||
|
public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl customInteractionImpl)
|
||||||
|
{
|
||||||
|
bool isInteractive = customInteractionImpl.IsInteractive();
|
||||||
|
SimpleContextMenuButton button = null;
|
||||||
|
button = instance.CreateButton(
|
||||||
|
customInteractionImpl.Key,
|
||||||
|
customInteractionImpl.Caption?.Invoke() ?? string.Empty,
|
||||||
|
instance.GetButtonTemplate(),
|
||||||
|
instance.GetButtonsContainer(),
|
||||||
|
customInteractionImpl.Icon?.Invoke(),
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
if (isInteractive)
|
||||||
|
{
|
||||||
|
customInteractionImpl.Execute();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
instance.SetCurrentButton(button);
|
||||||
|
instance.CloseSubMenu();
|
||||||
|
if (isInteractive)
|
||||||
|
{
|
||||||
|
var subMenu = customInteractionImpl.SubMenu?.Invoke();
|
||||||
|
if (subMenu != null)
|
||||||
|
{
|
||||||
|
instance.SetSubInteractions(subMenu.Impl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
customInteractionImpl.SubMenu != null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
button.SetButtonInteraction(
|
||||||
|
(isInteractive, customInteractionImpl.Error?.Invoke() ?? string.Empty)
|
||||||
|
);
|
||||||
|
instance.AddButton(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
CustomInteractions/CustomInteractions.csproj
Normal file
31
CustomInteractions/CustomInteractions.csproj
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.CustomInteractions</AssemblyName>
|
||||||
|
<Version>1.1.1</Version>
|
||||||
|
<RootNamespace>IcyClawz.CustomInteractions</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Aki.Reflection">
|
||||||
|
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp-CustomInteractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Sirenix.Serialization">
|
||||||
|
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
61
CustomInteractions/Plugin.cs
Normal file
61
CustomInteractions/Plugin.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using BepInEx;
|
||||||
|
using EFT.UI;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using DynamicInteraction = GClass2654;
|
||||||
|
using ItemContext = GClass2466;
|
||||||
|
using ItemInfoInteractions = GClass2655<EFT.InventoryLogic.EItemInfoButton>;
|
||||||
|
|
||||||
|
namespace IcyClawz.CustomInteractions
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.CustomInteractions", "IcyClawz.CustomInteractions", "1.1.1")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
new ItemUiContextPatch().Enable();
|
||||||
|
new InteractionButtonsContainerPatch().Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemUiContextPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(ItemUiContext).GetMethod("GetItemContextInteractions", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void Postfix(ref ItemInfoInteractions __result, ItemUiContext __instance, ItemContext itemContext)
|
||||||
|
{
|
||||||
|
foreach (var provider in CustomInteractionsManager.Providers.OfType<IItemCustomInteractionsProvider>())
|
||||||
|
{
|
||||||
|
var customInteractions = provider.GetCustomInteractions(__instance, itemContext.ViewType, itemContext.Item);
|
||||||
|
if (customInteractions != null)
|
||||||
|
{
|
||||||
|
foreach (CustomInteraction customInteraction in customInteractions)
|
||||||
|
{
|
||||||
|
__result.AddCustomInteraction(customInteraction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InteractionButtonsContainerPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(InteractionButtonsContainer).GetMethod("method_3", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
private static bool Prefix(ref InteractionButtonsContainer __instance, DynamicInteraction interaction)
|
||||||
|
{
|
||||||
|
if (interaction is CustomInteractionImpl customInteractionImpl)
|
||||||
|
{
|
||||||
|
__instance.AddCustomButton(customInteractionImpl);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
ItemAttributeFix.sln
Normal file
25
ItemAttributeFix.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{1A806857-2204-4EF9-ADDA-36F4C5688DC1}") = "ItemAttributeFix", "ItemAttributeFix\ItemAttributeFix.csproj", "{F3186B2D-F170-4E31-98BF-4CC8CDAD565D}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F3186B2D-F170-4E31-98BF-4CC8CDAD565D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F3186B2D-F170-4E31-98BF-4CC8CDAD565D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F3186B2D-F170-4E31-98BF-4CC8CDAD565D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F3186B2D-F170-4E31-98BF-4CC8CDAD565D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BD4846A6-29F2-4AD6-91A5-7A0CA28D88CC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
28
ItemAttributeFix/ItemAttributeFix.csproj
Normal file
28
ItemAttributeFix/ItemAttributeFix.csproj
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.ItemAttributeFix</AssemblyName>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<RootNamespace>IcyClawz.ItemAttributeFix</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Aki.Reflection">
|
||||||
|
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
35
ItemAttributeFix/Plugin.cs
Normal file
35
ItemAttributeFix/Plugin.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using BepInEx;
|
||||||
|
using EFT.UI;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace IcyClawz.ItemAttributeFix
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.ItemAttributeFix", "IcyClawz.ItemAttributeFix", "1.0.0")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
new CompactCharacteristicPanelPatch().Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CompactCharacteristicPanelPatch : ModulePatch
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo ItemAttributeField =
|
||||||
|
typeof(CompactCharacteristicPanel).GetField("ItemAttribute", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static readonly FieldInfo StringField =
|
||||||
|
typeof(CompactCharacteristicPanel).GetField("string_0", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(CompactCharacteristicPanel).GetMethod("SetValues", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref CompactCharacteristicPanel __instance)
|
||||||
|
{
|
||||||
|
ItemAttributeClass attribute = ItemAttributeField.GetValue(__instance) as ItemAttributeClass;
|
||||||
|
StringField.SetValue(__instance, attribute.FullStringValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
ItemContextMenuExt.sln
Normal file
25
ItemContextMenuExt.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{16C72132-089A-4D00-BDA9-5DFC76E223AC}") = "ItemContextMenuExt", "ItemContextMenuExt\ItemContextMenuExt.csproj", "{F9FF8A66-A96D-45D2-BBD5-D976F101CCF7}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F9FF8A66-A96D-45D2-BBD5-D976F101CCF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F9FF8A66-A96D-45D2-BBD5-D976F101CCF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F9FF8A66-A96D-45D2-BBD5-D976F101CCF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F9FF8A66-A96D-45D2-BBD5-D976F101CCF7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B44F10FA-AB5A-4200-80B2-4ED636043F28}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
185
ItemContextMenuExt/ItemContextMenuExt.cs
Normal file
185
ItemContextMenuExt/ItemContextMenuExt.cs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI;
|
||||||
|
using IcyClawz.CustomInteractions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using ILightTemplate = GInterface240;
|
||||||
|
using LightsState = GStruct143;
|
||||||
|
using ResourceCache = GClass2014;
|
||||||
|
|
||||||
|
namespace IcyClawz.ItemContextMenuExt
|
||||||
|
{
|
||||||
|
internal static class PlayerExtensions
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo InventoryControllerField =
|
||||||
|
typeof(Player).GetField("_inventoryController", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
public static InventoryControllerClass GetInventoryController(this Player player) =>
|
||||||
|
InventoryControllerField.GetValue(player) as InventoryControllerClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class LightComponentExtensions
|
||||||
|
{
|
||||||
|
public static int GetModesCount(this LightComponent component) =>
|
||||||
|
((ILightTemplate)component.Item.Template).ModesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class CustomInteractionsProvider : IItemCustomInteractionsProvider
|
||||||
|
{
|
||||||
|
internal const string IconsPrefix = "Characteristics/Icons/";
|
||||||
|
internal static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
|
||||||
|
|
||||||
|
public IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item)
|
||||||
|
{
|
||||||
|
if (viewType != EItemViewType.Inventory)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var component = item.GetItemComponent<FireModeComponent>();
|
||||||
|
if (component != null)
|
||||||
|
{
|
||||||
|
// Firing mode
|
||||||
|
yield return new CustomInteraction()
|
||||||
|
{
|
||||||
|
Caption = () => "Firing mode",
|
||||||
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
|
||||||
|
SubMenu = () => new FireModeSubMenu(uiContext, component),
|
||||||
|
Enabled = () => component.AvailableEFireModes.Length > 1,
|
||||||
|
Error = () => "This weapon is incapable of selective fire"
|
||||||
|
};
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var component = item.GetItemComponent<LightComponent>();
|
||||||
|
if (component != null)
|
||||||
|
{
|
||||||
|
// Turn on/off
|
||||||
|
yield return new CustomInteraction()
|
||||||
|
{
|
||||||
|
Caption = () => (component.IsActive ? "TurnOff" : "TurnOn").Localized(),
|
||||||
|
Icon = () => ResourceCache.Pop<Sprite>(IconsPrefix + (component.IsActive ? "TurnOff" : "TurnOn")),
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetLightState(component, !component.IsActive, component.SelectedMode);
|
||||||
|
uiContext.RedrawContextMenus(new[] { item.TemplateId });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Switch mode
|
||||||
|
yield return new CustomInteraction()
|
||||||
|
{
|
||||||
|
Caption = () => "Switch mode",
|
||||||
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
||||||
|
SubMenu = () => new LightModeSubMenu(uiContext, component),
|
||||||
|
Enabled = () => component.GetModesCount() > 1,
|
||||||
|
Error = () => "This device has no alternative modes"
|
||||||
|
};
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FireModeSubMenu : CustomSubInteractions
|
||||||
|
{
|
||||||
|
public FireModeSubMenu(ItemUiContext uiContext, FireModeComponent component)
|
||||||
|
: base(uiContext)
|
||||||
|
{
|
||||||
|
foreach (var fireMode in component.AvailableEFireModes)
|
||||||
|
{
|
||||||
|
Add(new CustomInteraction()
|
||||||
|
{
|
||||||
|
Caption = () => fireMode.ToString().Localized(),
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetFireMode(component, fireMode);
|
||||||
|
},
|
||||||
|
Enabled = () => fireMode != component.FireMode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LightModeSubMenu : CustomSubInteractions
|
||||||
|
{
|
||||||
|
public LightModeSubMenu(ItemUiContext uiContext, LightComponent component)
|
||||||
|
: base(uiContext)
|
||||||
|
{
|
||||||
|
foreach (var lightMode in Enumerable.Range(0, component.GetModesCount()))
|
||||||
|
{
|
||||||
|
Add(new CustomInteraction()
|
||||||
|
{
|
||||||
|
Caption = () => $"Mode {lightMode + 1}",
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
||||||
|
ComponentUtils.SetLightState(component, component.IsActive, lightMode);
|
||||||
|
},
|
||||||
|
Enabled = () => lightMode != component.SelectedMode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ComponentUtils
|
||||||
|
{
|
||||||
|
public static void SetFireMode(FireModeComponent component, Weapon.EFireMode fireMode)
|
||||||
|
{
|
||||||
|
var player = GamePlayerOwner.MyPlayer;
|
||||||
|
if (player != null && player.HandsController is Player.FirearmController fc && component.Item == fc.Item)
|
||||||
|
{
|
||||||
|
if (fc.Item.MalfState.State == Weapon.EMalfunctionState.None)
|
||||||
|
{
|
||||||
|
fc.ChangeFireMode(fireMode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fc.FirearmsAnimator.MisfireSlideUnknown(false);
|
||||||
|
player.GetInventoryController().ExamineMalfunction(fc.Item, false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.SetFireMode(fireMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLightState(LightComponent component, bool isActive, int lightMode)
|
||||||
|
{
|
||||||
|
var player = GamePlayerOwner.MyPlayer;
|
||||||
|
if (player != null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
||||||
|
{
|
||||||
|
var state = new LightsState
|
||||||
|
{
|
||||||
|
Id = component.Item.Id,
|
||||||
|
IsActive = isActive,
|
||||||
|
LightMode = lightMode
|
||||||
|
};
|
||||||
|
fc.SetLightsState(new[] { state });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.IsActive = isActive;
|
||||||
|
component.SelectedMode = lightMode;
|
||||||
|
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
foreach (var tcvc in player.GetComponentsInChildren<TacticalComboVisualController>())
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(tcvc.LightMod, component))
|
||||||
|
{
|
||||||
|
tcvc.UpdateBeams();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
ItemContextMenuExt/ItemContextMenuExt.csproj
Normal file
37
ItemContextMenuExt/ItemContextMenuExt.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.ItemContextMenuExt</AssemblyName>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<RootNamespace>IcyClawz.ItemContextMenuExt</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Comfort">
|
||||||
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="IcyClawz.CustomInteractions">
|
||||||
|
<HintPath>..\Shared\IcyClawz.CustomInteractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ItemComponent.Types">
|
||||||
|
<HintPath>..\Shared\ItemComponent.Types.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ItemTemplate.Types">
|
||||||
|
<HintPath>..\Shared\ItemTemplate.Types.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
14
ItemContextMenuExt/Plugin.cs
Normal file
14
ItemContextMenuExt/Plugin.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using BepInEx;
|
||||||
|
using IcyClawz.CustomInteractions;
|
||||||
|
|
||||||
|
namespace IcyClawz.ItemContextMenuExt
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.ItemContextMenuExt", "IcyClawz.ItemContextMenuExt", "1.0.1")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
CustomInteractionsManager.Register(new CustomInteractionsProvider());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
ItemSellPrice.sln
Normal file
25
ItemSellPrice.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{1A9E4EC8-A583-446A-8918-2608C278F194}") = "ItemSellPrice", "ItemSellPrice\ItemSellPrice.csproj", "{FA2EAB19-7A7F-452F-80B3-DEAD18E43D88}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{FA2EAB19-7A7F-452F-80B3-DEAD18E43D88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FA2EAB19-7A7F-452F-80B3-DEAD18E43D88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FA2EAB19-7A7F-452F-80B3-DEAD18E43D88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FA2EAB19-7A7F-452F-80B3-DEAD18E43D88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B6B3C802-40C3-4FF0-9BAA-1DAC503CA619}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
217
ItemSellPrice/ItemSellPrice.cs
Normal file
217
ItemSellPrice/ItemSellPrice.cs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
using Aki.Reflection.Utils;
|
||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using CurrencyUtil = GClass2181;
|
||||||
|
|
||||||
|
namespace IcyClawz.ItemSellPrice
|
||||||
|
{
|
||||||
|
public static class ItemSellPrice
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, string[]> DisplayNames = new Dictionary<string, string[]>()
|
||||||
|
{
|
||||||
|
{ "ch", new[] { "售价({0})", "无法出售给商人" } },
|
||||||
|
{ "cz", new[] { "Prodejní cena ({0})", "Nemůže být prodán obchodníkům" } },
|
||||||
|
{ "en", new[] { "Selling price ({0})", "Cannot be sold to traders" } },
|
||||||
|
{ "es", new[] { "Precio de venta ({0})", "No puede ser vendido a los vendedores" } },
|
||||||
|
{ "es-mx", new[] { "Precio de venta ({0})", "No puede ser vendido a comerciantes" } },
|
||||||
|
{ "fr", new[] { "Prix de vente ({0})", "Ne peut pas être vendu aux marchands" } },
|
||||||
|
{ "ge", new[] { "Verkaufspreis ({0})", "Kann nicht an Händler verkauft werden" } },
|
||||||
|
{ "hu", new[] { "Eladási ár ({0})", "Kereskedőknek nem adható el" } },
|
||||||
|
{ "it", new[] { "Prezzo di vendita ({0})", "Non vendibile ai mercanti" } },
|
||||||
|
{ "jp", new[] { "販売価格({0})", "トレーダーには販売できません" } },
|
||||||
|
{ "kr", new[] { "판매 가격 ({0})", "상인에게 판매 불가" } },
|
||||||
|
{ "pl", new[] { "Cena sprzedaży ({0})", "Nie można sprzedawać handlarzom" } },
|
||||||
|
{ "po", new[] { "Preço de venda ({0})", "Não pode ser vendido a comerciantes" } },
|
||||||
|
{ "ru", new[] { "Цена продажи ({0})", "Невозможно продать торговцам" } },
|
||||||
|
{ "sk", new[] { "Predajná cena ({0})", "Nedá sa predať obchodníkom" } },
|
||||||
|
{ "tu", new[] { "Satış fiyatı ({0})", "Tüccarlara satılamaz" } }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly FieldInfo SupplyDataField =
|
||||||
|
typeof(TraderClass).GetField("supplyData_0", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static ISession Session => ClientAppUtils.GetMainApp().GetClientBackEndSession();
|
||||||
|
|
||||||
|
public static async void UpdateSupplyData(this TraderClass trader)
|
||||||
|
{
|
||||||
|
Result<SupplyData> result = await Session.GetSupplyData(trader.Id);
|
||||||
|
if (result.Failed)
|
||||||
|
{
|
||||||
|
Debug.LogError("Failed to download supply data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trader.SetSupplyData(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SupplyData GetSupplyData(this TraderClass trader) =>
|
||||||
|
SupplyDataField.GetValue(trader) as SupplyData;
|
||||||
|
|
||||||
|
public static void SetSupplyData(this TraderClass trader, SupplyData supplyData) =>
|
||||||
|
SupplyDataField.SetValue(trader, supplyData);
|
||||||
|
|
||||||
|
public static void AddTraderOfferAttribute(this Item item)
|
||||||
|
{
|
||||||
|
List<ItemAttributeClass> attributes = new List<ItemAttributeClass>
|
||||||
|
{
|
||||||
|
new ItemAttributeClass(EItemAttributeId.MoneySum)
|
||||||
|
{
|
||||||
|
Name = EItemAttributeId.MoneySum.GetName(),
|
||||||
|
DisplayNameFunc = () => GetDisplayName(item),
|
||||||
|
Base = () => GetBase(item),
|
||||||
|
StringValue = () => GetStringValue(item),
|
||||||
|
FullStringValue = () => GetFullStringValue(item),
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||||
|
}
|
||||||
|
};
|
||||||
|
attributes.AddRange(item.Attributes);
|
||||||
|
item.Attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TraderOffer
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public int Price;
|
||||||
|
public string Currency;
|
||||||
|
public double Course;
|
||||||
|
public int Count;
|
||||||
|
|
||||||
|
public TraderOffer(string name, int price, string currency, double course, int count)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Price = price;
|
||||||
|
Currency = currency;
|
||||||
|
Course = course;
|
||||||
|
Count = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TraderOffer GetTraderOffer(Item item, TraderClass trader)
|
||||||
|
{
|
||||||
|
var result = trader.GetUserItemPrice(item);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new TraderOffer(
|
||||||
|
trader.LocalizedName,
|
||||||
|
result.Value.Amount,
|
||||||
|
CurrencyUtil.GetCurrencyCharById(result.Value.CurrencyId),
|
||||||
|
trader.GetSupplyData().CurrencyCourses[result.Value.CurrencyId],
|
||||||
|
item.StackObjectsCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TraderOffer> GetAllTraderOffers(Item item)
|
||||||
|
{
|
||||||
|
if (!Session.Profile.Examined(item))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (item.Owner?.OwnerType)
|
||||||
|
{
|
||||||
|
case EOwnerType.RagFair:
|
||||||
|
case EOwnerType.Trader:
|
||||||
|
if (item.StackObjectsCount > 1 || item.UnlimitedCount)
|
||||||
|
{
|
||||||
|
item = item.CloneItem();
|
||||||
|
item.StackObjectsCount = 1;
|
||||||
|
item.UnlimitedCount = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
List<TraderOffer> offers = new List<TraderOffer>();
|
||||||
|
foreach (TraderClass trader in Session.Traders)
|
||||||
|
{
|
||||||
|
if (GetTraderOffer(item, trader) is TraderOffer offer)
|
||||||
|
{
|
||||||
|
offers.Add(offer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offers.Sort((x, y) => (y.Price * y.Course).CompareTo(x.Price * x.Course));
|
||||||
|
return offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TraderOffer GetBestTraderOffer(Item item)
|
||||||
|
{
|
||||||
|
if (GetAllTraderOffers(item) is List<TraderOffer> offers)
|
||||||
|
{
|
||||||
|
return offers.FirstOrDefault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDisplayName(Item item)
|
||||||
|
{
|
||||||
|
string language = Singleton<SharedGameSettingsClass>.Instance?.Game?.Settings?.Language?.GetValue();
|
||||||
|
if (language == null || !DisplayNames.ContainsKey(language))
|
||||||
|
{
|
||||||
|
language = "en";
|
||||||
|
}
|
||||||
|
if (GetBestTraderOffer(item) is TraderOffer offer)
|
||||||
|
{
|
||||||
|
return string.Format(DisplayNames[language][0], offer.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DisplayNames[language][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetBase(Item item)
|
||||||
|
{
|
||||||
|
if (GetBestTraderOffer(item) is TraderOffer offer)
|
||||||
|
{
|
||||||
|
return offer.Price;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0.01f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetStringValue(Item item)
|
||||||
|
{
|
||||||
|
if (GetBestTraderOffer(item) is TraderOffer offer)
|
||||||
|
{
|
||||||
|
string value = $"{offer.Currency} {offer.Price}";
|
||||||
|
if (offer.Count > 1)
|
||||||
|
{
|
||||||
|
value += $" ({offer.Count})";
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFullStringValue(Item item)
|
||||||
|
{
|
||||||
|
if (GetAllTraderOffers(item) is List<TraderOffer> offers)
|
||||||
|
{
|
||||||
|
string[] lines = new string[offers.Count];
|
||||||
|
for (int i = 0; i < offers.Count; i++)
|
||||||
|
{
|
||||||
|
TraderOffer offer = offers[i];
|
||||||
|
lines[i] = $"{offer.Name}: {offer.Currency} {offer.Price}";
|
||||||
|
}
|
||||||
|
return string.Join(Environment.NewLine, lines);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
ItemSellPrice/ItemSellPrice.csproj
Normal file
34
ItemSellPrice/ItemSellPrice.csproj
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.ItemSellPrice</AssemblyName>
|
||||||
|
<Version>1.0.2</Version>
|
||||||
|
<RootNamespace>IcyClawz.ItemSellPrice</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Aki.Common">
|
||||||
|
<HintPath>..\Shared\Aki.Common.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Aki.Reflection">
|
||||||
|
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Comfort">
|
||||||
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
82
ItemSellPrice/Plugin.cs
Normal file
82
ItemSellPrice/Plugin.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using BepInEx;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace IcyClawz.ItemSellPrice
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.ItemSellPrice", "IcyClawz.ItemSellPrice", "1.0.2")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
new TraderPatch().Enable();
|
||||||
|
new ItemPatch().Enable();
|
||||||
|
new AmmoPatch().Enable();
|
||||||
|
new GrenadePatch().Enable();
|
||||||
|
new SecureContainerPatch().Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TraderPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(TraderClass).GetConstructors()[0];
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref TraderClass __instance)
|
||||||
|
{
|
||||||
|
__instance.UpdateSupplyData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(Item).GetConstructors()[0];
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref Item __instance)
|
||||||
|
{
|
||||||
|
__instance.AddTraderOfferAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AmmoPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(BulletClass).GetConstructors()[0];
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref BulletClass __instance)
|
||||||
|
{
|
||||||
|
__instance.AddTraderOfferAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrenadePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(GrenadeClass).GetConstructors()[0];
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref GrenadeClass __instance)
|
||||||
|
{
|
||||||
|
__instance.AddTraderOfferAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecureContainerPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return typeof(ItemContainerClass).GetConstructors()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref ItemContainerClass __instance)
|
||||||
|
{
|
||||||
|
__instance.AddTraderOfferAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
MagazineInspector.sln
Normal file
25
MagazineInspector.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{1528224F-F248-466A-95DF-C841EA46D89E}") = "MagazineInspector", "MagazineInspector\MagazineInspector.csproj", "{F4F0DAB6-3A97-4656-A61F-945D63BAB4F8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F4F0DAB6-3A97-4656-A61F-945D63BAB4F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F4F0DAB6-3A97-4656-A61F-945D63BAB4F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F4F0DAB6-3A97-4656-A61F-945D63BAB4F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F4F0DAB6-3A97-4656-A61F-945D63BAB4F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BEB55B48-4A92-4A7E-8B4E-58FFADC9FE2C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
157
MagazineInspector/MagazineInspector.cs
Normal file
157
MagazineInspector/MagazineInspector.cs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
using Aki.Reflection.Utils;
|
||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using InGameStatus = GClass1756;
|
||||||
|
|
||||||
|
namespace IcyClawz.MagazineInspector
|
||||||
|
{
|
||||||
|
public static class MagazineInspector
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, string> DisplayNames = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "ch", "上膛弹药" },
|
||||||
|
{ "cz", "Nabité střelivo" },
|
||||||
|
{ "en", "Loaded ammo" },
|
||||||
|
{ "es", "Munición cargada" },
|
||||||
|
{ "es-mx", "Munición cargada" },
|
||||||
|
{ "fr", "Munitions chargées" },
|
||||||
|
{ "ge", "Geladene Munition" },
|
||||||
|
{ "hu", "Töltött lőszer" },
|
||||||
|
{ "it", "Munizioni caricate" },
|
||||||
|
{ "jp", "装填弾薬" },
|
||||||
|
{ "kr", "장전 탄약" },
|
||||||
|
{ "pl", "Załadowana amunicja" },
|
||||||
|
{ "po", "Munição carregada" },
|
||||||
|
{ "ru", "Заряженные боеприпасы" },
|
||||||
|
{ "sk", "Nabitá munícia" },
|
||||||
|
{ "tu", "Yüklü mühimmat" }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ISession Session => ClientAppUtils.GetMainApp().GetClientBackEndSession();
|
||||||
|
|
||||||
|
private static Profile ActiveProfile => InGameStatus.InRaid ? ClientPlayerOwner.MyPlayer.Profile : Session.Profile;
|
||||||
|
|
||||||
|
public static void AddAmmoCountAttribute(this MagazineClass magazine)
|
||||||
|
{
|
||||||
|
ItemAttributeClass attribute = magazine.Attributes.Find(attr => attr.Id is EItemAttributeId.MaxCount);
|
||||||
|
if (attribute == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attribute.DisplayNameFunc = GetDisplayName;
|
||||||
|
attribute.Base = () => GetBase(magazine);
|
||||||
|
attribute.StringValue = () => GetStringValue(magazine);
|
||||||
|
attribute.FullStringValue = () => GetFullStringValue(magazine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int? GetAmmoCount(MagazineClass magazine, Profile profile, out bool magChecked)
|
||||||
|
{
|
||||||
|
if (!InGameStatus.InRaid || magazine.Count == 0)
|
||||||
|
{
|
||||||
|
magChecked = true;
|
||||||
|
return magazine.Count;
|
||||||
|
}
|
||||||
|
magChecked = profile.CheckedMagazines.ContainsKey(magazine.Id);
|
||||||
|
if (magChecked)
|
||||||
|
{
|
||||||
|
bool equipped = profile.Inventory.Equipment.GetAllSlots().Any(slot => ReferenceEquals(slot.ContainedItem, magazine));
|
||||||
|
if (magazine.Count >= (equipped ? magazine.MaxCount - 1 : magazine.MaxCount))
|
||||||
|
{
|
||||||
|
return magazine.Count;
|
||||||
|
}
|
||||||
|
int skill = Mathf.Max(
|
||||||
|
profile.MagDrillsMastering,
|
||||||
|
profile.CheckedMagazineSkillLevel(magazine.Id),
|
||||||
|
magazine.CheckOverride
|
||||||
|
);
|
||||||
|
if (skill > 1 || (skill == 1 && magazine.MaxCount <= 10))
|
||||||
|
{
|
||||||
|
return magazine.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDisplayName()
|
||||||
|
{
|
||||||
|
string language = Singleton<SharedGameSettingsClass>.Instance?.Game?.Settings?.Language?.GetValue();
|
||||||
|
if (language == null || !DisplayNames.ContainsKey(language))
|
||||||
|
{
|
||||||
|
language = "en";
|
||||||
|
}
|
||||||
|
return DisplayNames[language];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetBase(MagazineClass magazine)
|
||||||
|
{
|
||||||
|
if (GetAmmoCount(magazine, ActiveProfile, out _) is int ammoCount)
|
||||||
|
{
|
||||||
|
return ammoCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetStringValue(MagazineClass magazine)
|
||||||
|
{
|
||||||
|
string value;
|
||||||
|
if (GetAmmoCount(magazine, ActiveProfile, out _) is int ammoCount)
|
||||||
|
{
|
||||||
|
value = ammoCount.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = "?";
|
||||||
|
}
|
||||||
|
return $"{value}/{magazine.MaxCount}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static string GetFullStringValue(MagazineClass magazine)
|
||||||
|
{
|
||||||
|
Profile profile = ActiveProfile;
|
||||||
|
int? ammoCount = GetAmmoCount(magazine, profile, out bool magChecked);
|
||||||
|
if (magChecked)
|
||||||
|
{
|
||||||
|
List<Item> cartridges = new List<Item>(magazine.Cartridges.Items);
|
||||||
|
string[] lines = new string[cartridges.Count];
|
||||||
|
int i = cartridges.Count - 1;
|
||||||
|
foreach (Item cartridge in cartridges)
|
||||||
|
{
|
||||||
|
string count;
|
||||||
|
if (ammoCount != null)
|
||||||
|
{
|
||||||
|
count = cartridge.StackObjectsCount.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = "?";
|
||||||
|
}
|
||||||
|
string name;
|
||||||
|
if (profile.Examined(cartridge))
|
||||||
|
{
|
||||||
|
name = cartridge.LocalizedName();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = "Unknown item".Localized();
|
||||||
|
}
|
||||||
|
lines[i--] = $"{count} × {name}";
|
||||||
|
}
|
||||||
|
return string.Join(Environment.NewLine, lines);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
MagazineInspector/MagazineInspector.csproj
Normal file
34
MagazineInspector/MagazineInspector.csproj
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.MagazineInspector</AssemblyName>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<RootNamespace>IcyClawz.MagazineInspector</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Aki.Common">
|
||||||
|
<HintPath>..\Shared\Aki.Common.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Aki.Reflection">
|
||||||
|
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Comfort">
|
||||||
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
27
MagazineInspector/Plugin.cs
Normal file
27
MagazineInspector/Plugin.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using BepInEx;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace IcyClawz.MagazineInspector
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.MagazineInspector", "IcyClawz.MagazineInspector", "1.0.1")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
new MagazinePatch().Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MagazinePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(MagazineClass).GetConstructors()[0];
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref MagazineClass __instance)
|
||||||
|
{
|
||||||
|
__instance.AddAmmoCountAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
MunitionsExpert.sln
Normal file
25
MunitionsExpert.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.2.32616.157
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{12CC1CB2-4C8C-40A8-834F-237AB5B50B90}") = "MunitionsExpert", "MunitionsExpert\MunitionsExpert.csproj", "{F1E2DE6A-7145-4ED7-8AB0-DE2FE9E33CCA}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F1E2DE6A-7145-4ED7-8AB0-DE2FE9E33CCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F1E2DE6A-7145-4ED7-8AB0-DE2FE9E33CCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F1E2DE6A-7145-4ED7-8AB0-DE2FE9E33CCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F1E2DE6A-7145-4ED7-8AB0-DE2FE9E33CCA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BA86C600-4494-49AD-A227-017B8142B09C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
195
MunitionsExpert/MunitionsExpert.cs
Normal file
195
MunitionsExpert/MunitionsExpert.cs
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
using Comfort.Common;
|
||||||
|
using EFT.HandBook;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI.DragAndDrop;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace IcyClawz.MunitionsExpert
|
||||||
|
{
|
||||||
|
internal enum EAmmoExtraAttributeId
|
||||||
|
{
|
||||||
|
Damage,
|
||||||
|
PenetrationPower,
|
||||||
|
ArmorDamage,
|
||||||
|
FragmentationChance,
|
||||||
|
RicochetChance
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ImageExtensions
|
||||||
|
{
|
||||||
|
public static Sprite ToSprite(this System.Drawing.Image instance)
|
||||||
|
{
|
||||||
|
byte[] data;
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
instance.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||||
|
data = ms.ToArray();
|
||||||
|
}
|
||||||
|
Texture2D texture = new Texture2D(instance.Width, instance.Height);
|
||||||
|
ImageConversion.LoadImage(texture, data);
|
||||||
|
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class IconCache
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<EAmmoExtraAttributeId, Sprite> Cache = new Dictionary<EAmmoExtraAttributeId, Sprite>(5);
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
Cache.Add(EAmmoExtraAttributeId.Damage, Properties.Resources.Damage.ToSprite());
|
||||||
|
Cache.Add(EAmmoExtraAttributeId.PenetrationPower, Properties.Resources.PenetrationPower.ToSprite());
|
||||||
|
Cache.Add(EAmmoExtraAttributeId.ArmorDamage, Properties.Resources.ArmorDamage.ToSprite());
|
||||||
|
Cache.Add(EAmmoExtraAttributeId.FragmentationChance, Properties.Resources.FragmentationChance.ToSprite());
|
||||||
|
Cache.Add(EAmmoExtraAttributeId.RicochetChance, Properties.Resources.RicochetChance.ToSprite());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sprite Get(Enum id) =>
|
||||||
|
id is EAmmoExtraAttributeId extraId ? Cache[extraId] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class AmmoTemplateExtensions
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo CachedQualitiesField =
|
||||||
|
typeof(AmmoTemplate).GetField("_cachedQualities", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
public static List<ItemAttributeClass> GetCachedQualities(this AmmoTemplate instance) =>
|
||||||
|
CachedQualitiesField.GetValue(instance) as List<ItemAttributeClass>;
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (instance.ProjectileCount > 1)
|
||||||
|
{
|
||||||
|
return $"{instance.ProjectileCount} × {instance.Damage} = {totalDamage}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 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();
|
||||||
|
string armorClassStr = armorClass > 0 ? $"Class {armorClass}" : "Unarmored";
|
||||||
|
return $"{armorClassStr} ({instance.PenetrationPower})";
|
||||||
|
},
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.ArmorDamage)
|
||||||
|
{
|
||||||
|
Name = EAmmoExtraAttributeId.ArmorDamage.ToString(),
|
||||||
|
DisplayNameFunc = () => "Armor damage",
|
||||||
|
Base = () => instance.ArmorDamage,
|
||||||
|
StringValue = () => $"{instance.ArmorDamage}%",
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.FragmentationChance)
|
||||||
|
{
|
||||||
|
Name = EAmmoExtraAttributeId.FragmentationChance.ToString(),
|
||||||
|
DisplayNameFunc = () => "Fragmentation chance",
|
||||||
|
Base = () => instance.FragmentationChance,
|
||||||
|
StringValue = () => $"{Math.Round(instance.FragmentationChance * 100, 1)}%",
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.SafelyAddQualityToList(new ItemAttributeClass(EAmmoExtraAttributeId.RicochetChance)
|
||||||
|
{
|
||||||
|
Name = EAmmoExtraAttributeId.RicochetChance.ToString(),
|
||||||
|
DisplayNameFunc = () => "Ricochet chance",
|
||||||
|
Base = () => instance.RicochetChance,
|
||||||
|
StringValue = () => $"{Math.Round(instance.RicochetChance * 100, 1)}%",
|
||||||
|
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetPenetrationArmorClass(this AmmoTemplate instance)
|
||||||
|
{
|
||||||
|
var armorClasses = Singleton<BackendConfigSettingsClass>.Instance.Armor.ArmorClass;
|
||||||
|
for (int i = armorClasses.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (armorClasses[i].Resistance <= instance.PenetrationPower)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ColorUtils
|
||||||
|
{
|
||||||
|
private const byte ALPHA = 38;
|
||||||
|
private static readonly Color[] ArmorClassColors = new Color[]
|
||||||
|
{
|
||||||
|
new Color32(120, 40, 135, ALPHA), // Unarmored => Violet
|
||||||
|
new Color32(0, 60, 170, ALPHA), // Class 1 => Blue
|
||||||
|
new Color32(0, 150, 150, ALPHA), // Class 2 => Cyan
|
||||||
|
new Color32(70, 140, 0, ALPHA), // Class 3 => Green
|
||||||
|
new Color32(170, 170, 0, ALPHA), // Class 4 => Yellow
|
||||||
|
new Color32(140, 70, 0, ALPHA), // Class 5 => Orange
|
||||||
|
new Color32(170, 20, 0, ALPHA) // Class 6+ => Red
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Color GetArmorClassColor(int armorClass) =>
|
||||||
|
ArmorClassColors[Mathf.Clamp(armorClass, 0, ArmorClassColors.Length - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ItemViewExtensions
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo BackgroundColorField =
|
||||||
|
typeof(ItemView).GetField("BackgroundColor", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static void SetBackgroundColor(this ItemView instance, Color color) =>
|
||||||
|
BackgroundColorField.SetValue(instance, color);
|
||||||
|
|
||||||
|
public static void OverrideColor(this ItemView instance, Item item)
|
||||||
|
{
|
||||||
|
if (item is BulletClass bullet && bullet.PenetrationPower > 0)
|
||||||
|
{
|
||||||
|
int armorClass = bullet.AmmoTemplate.GetPenetrationArmorClass();
|
||||||
|
instance.SetBackgroundColor(ColorUtils.GetArmorClassColor(armorClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class EntityIconExtensions
|
||||||
|
{
|
||||||
|
private static readonly FieldInfo ColorPanelField =
|
||||||
|
typeof(EntityIcon).GetField("_colorPanel", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
private static Image GetColorPanel(this EntityIcon instance) =>
|
||||||
|
ColorPanelField.GetValue(instance) as Image;
|
||||||
|
|
||||||
|
public static void OverrideColor(this EntityIcon instance, Item item)
|
||||||
|
{
|
||||||
|
if (item is BulletClass bullet && bullet.PenetrationPower > 0)
|
||||||
|
{
|
||||||
|
int armorClass = bullet.AmmoTemplate.GetPenetrationArmorClass();
|
||||||
|
instance.GetColorPanel().color = ColorUtils.GetArmorClassColor(armorClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
MunitionsExpert/MunitionsExpert.csproj
Normal file
55
MunitionsExpert/MunitionsExpert.csproj
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AssemblyName>IcyClawz.MunitionsExpert</AssemblyName>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<RootNamespace>IcyClawz.MunitionsExpert</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Aki.Reflection">
|
||||||
|
<HintPath>..\Shared\Aki.Reflection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\Shared\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BepInEx">
|
||||||
|
<HintPath>..\Shared\BepInEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Comfort">
|
||||||
|
<HintPath>..\Shared\Comfort.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Sirenix.Serialization">
|
||||||
|
<HintPath>..\Shared\Sirenix.Serialization.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\Shared\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ImageConversionModule">
|
||||||
|
<HintPath>..\Shared\UnityEngine.ImageConversionModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UI">
|
||||||
|
<HintPath>..\Shared\UnityEngine.UI.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Properties\Resources.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
96
MunitionsExpert/Plugin.cs
Normal file
96
MunitionsExpert/Plugin.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using BepInEx;
|
||||||
|
using EFT.HandBook;
|
||||||
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI;
|
||||||
|
using EFT.UI.DragAndDrop;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace IcyClawz.MunitionsExpert
|
||||||
|
{
|
||||||
|
[BepInPlugin("com.IcyClawz.MunitionsExpert", "IcyClawz.MunitionsExpert", "1.0.0")]
|
||||||
|
public class Plugin : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
IconCache.Initialize();
|
||||||
|
new StaticIconsPatch().Enable();
|
||||||
|
new AmmoTemplatePatch().Enable();
|
||||||
|
new ItemViewPatch().Enable();
|
||||||
|
new EntityIconPatch().Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class StaticIconsPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(StaticIcons).GetMethod("GetAttributeIcon", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
private static bool PatchPrefix(ref Sprite __result, Enum id)
|
||||||
|
{
|
||||||
|
var icon = IconCache.Get(id);
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
__result = icon;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AmmoTemplatePatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(AmmoTemplate).GetMethod("GetCachedReadonlyQualities", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
private static bool PatchPrefix(ref List<ItemAttributeClass> __result, AmmoTemplate __instance)
|
||||||
|
{
|
||||||
|
if (__instance.GetCachedQualities() != null)
|
||||||
|
{
|
||||||
|
__result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref List<ItemAttributeClass> __result, AmmoTemplate __instance)
|
||||||
|
{
|
||||||
|
if (__result == null)
|
||||||
|
{
|
||||||
|
__result = __instance.GetCachedQualities();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
__instance.AddExtraAttributes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ItemViewPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(ItemView).GetMethod("UpdateColor", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
private static void PatchPrefix(ref ItemView __instance)
|
||||||
|
{
|
||||||
|
__instance.OverrideColor(__instance.Item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EntityIconPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod() =>
|
||||||
|
typeof(EntityIcon).GetMethod("Show", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
private static void PatchPostfix(ref EntityIcon __instance, Item item)
|
||||||
|
{
|
||||||
|
__instance.OverrideColor(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
MunitionsExpert/Properties/Resources.Designer.cs
generated
Normal file
113
MunitionsExpert/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace IcyClawz.MunitionsExpert.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IcyClawz.MunitionsExpert.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap ArmorDamage {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("ArmorDamage", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap FragmentationChance {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("FragmentationChance", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap RicochetChance {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("RicochetChance", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
136
MunitionsExpert/Properties/Resources.resx
Normal file
136
MunitionsExpert/Properties/Resources.resx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<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>
|
||||||
|
</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">
|
||||||
|
<value>..\Resources\FragmentationChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</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">
|
||||||
|
<value>..\Resources\RicochetChance.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
BIN
MunitionsExpert/Resources/ArmorDamage.png
Normal file
BIN
MunitionsExpert/Resources/ArmorDamage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 649 B |
BIN
MunitionsExpert/Resources/Damage.png
Normal file
BIN
MunitionsExpert/Resources/Damage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 764 B |
BIN
MunitionsExpert/Resources/FragmentationChance.png
Normal file
BIN
MunitionsExpert/Resources/FragmentationChance.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 733 B |
BIN
MunitionsExpert/Resources/PenetrationPower.png
Normal file
BIN
MunitionsExpert/Resources/PenetrationPower.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 468 B |
BIN
MunitionsExpert/Resources/RicochetChance.png
Normal file
BIN
MunitionsExpert/Resources/RicochetChance.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 681 B |
Loading…
x
Reference in New Issue
Block a user