using Comfort.Common; using EFT.InventoryLogic; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; namespace IcyClawz.MunitionsExpert; internal enum ColorName { Blue, Brown, Cyan, Gray, Green, Magenta, Orange, Pink, Purple, Red, Silver, Tan, Violet, Yellow } internal static class ColorCache { private const byte ALPHA = 38; private static readonly Dictionary Cache = new() { [ColorName.Blue] = new Color32(0, 60, 170, ALPHA), [ColorName.Brown] = new Color32(140, 85, 30, ALPHA), [ColorName.Cyan] = new Color32(0, 150, 150, ALPHA), [ColorName.Gray] = new Color32(70, 70, 70, ALPHA), [ColorName.Green] = new Color32(70, 140, 0, ALPHA), [ColorName.Magenta] = new Color32(215, 0, 100, ALPHA), [ColorName.Orange] = new Color32(140, 70, 0, ALPHA), [ColorName.Pink] = new Color32(215, 120, 150, ALPHA), [ColorName.Purple] = new Color32(120, 40, 135, ALPHA), [ColorName.Red] = new Color32(170, 20, 0, ALPHA), [ColorName.Silver] = new Color32(150, 150, 150, ALPHA), [ColorName.Tan] = new Color32(175, 145, 100, ALPHA), [ColorName.Violet] = new Color32(80, 50, 180, ALPHA), [ColorName.Yellow] = new Color32(170, 170, 0, ALPHA) }; public static Color Get(ColorName name) => Cache.TryGetValue(name, out Color color) ? color : default; } internal enum EAmmoExtraAttributeId { Damage, PenetrationPower, ArmorDamage, FragmentationChance, RicochetChance } internal static class ImageExtensions { public static Sprite ToSprite(this System.Drawing.Image instance) { using MemoryStream ms = new(); instance.Save(ms, System.Drawing.Imaging.ImageFormat.Png); Texture2D texture = new(instance.Width, instance.Height); ImageConversion.LoadImage(texture, ms.ToArray()); return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); } } internal static class IconCache { private static readonly Dictionary Cache = new() { [EAmmoExtraAttributeId.Damage] = Properties.Resources.Damage.ToSprite(), [EAmmoExtraAttributeId.PenetrationPower] = Properties.Resources.PenetrationPower.ToSprite(), [EAmmoExtraAttributeId.ArmorDamage] = Properties.Resources.ArmorDamage.ToSprite(), [EAmmoExtraAttributeId.FragmentationChance] = Properties.Resources.FragmentationChance.ToSprite(), [EAmmoExtraAttributeId.RicochetChance] = Properties.Resources.RicochetChance.ToSprite() }; public static Sprite Get(Enum id) => Cache.TryGetValue(id, out Sprite sprite) ? sprite : default; } internal static class AmmoTemplateExtensions { private static readonly FieldInfo CachedQualitiesField = typeof(AmmoTemplate).GetField("_cachedQualities", BindingFlags.NonPublic | BindingFlags.Instance); public static List GetCachedQualities(this AmmoTemplate instance) => CachedQualitiesField.GetValue(instance) as List; 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) { 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.Instance.Armor.ArmorClass; for (int i = armorClasses.Length - 1; i >= 0; i--) if (armorClasses[i].Resistance <= instance.PenetrationPower) return i; return 0; } }