Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NorthernGemcraft v0.1.2
plugins/NorthernGemcraft.Core.dll
Decompiled 3 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("NorthernGemcraft.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fb61e20309b17b5c1cca7e2cd23a964eea5e02c8")] [assembly: AssemblyProduct("NorthernGemcraft.Core")] [assembly: AssemblyTitle("NorthernGemcraft.Core")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace NorthernGemcraft.Core { public enum Effect { MaxHealth, HealthRegen, StaminaRegen, EitrRegen, PhysicalDamageTaken, MoveSpeed, CarryWeight, RunStamina, Durability, AttackStamina, EitrCost, LifeSteal, Damage } public static class Effects { public static readonly Effect[] All = (Effect[])Enum.GetValues(typeof(Effect)); public static bool LowerIsBetter(Effect e) { if (e != Effect.PhysicalDamageTaken && e != Effect.AttackStamina && e != Effect.EitrCost) { return e == Effect.RunStamina; } return true; } public static bool OnItem(Effect e) { if (e != Effect.Durability) { return e == Effect.Damage; } return true; } public static float Goodness(Effect e, float value) { if (!LowerIsBetter(e)) { return value; } return 0f - value; } public static string Label(Effect e) { return e switch { Effect.MaxHealth => "max health", Effect.HealthRegen => "health regen", Effect.StaminaRegen => "stamina regen", Effect.EitrRegen => "eitr regen", Effect.PhysicalDamageTaken => "physical damage taken", Effect.MoveSpeed => "movement speed", Effect.CarryWeight => "carry weight", Effect.RunStamina => "stamina while running", Effect.Durability => "durability", Effect.AttackStamina => "stamina per attack", Effect.EitrCost => "eitr per cast", Effect.LifeSteal => "life steal", Effect.Damage => "damage", _ => e.ToString(), }; } public static string Format(Effect e, float value) { string text = value.ToString("+0.##;-0.##;0", CultureInfo.InvariantCulture); if (e == Effect.LifeSteal) { text = value.ToString("0.##", CultureInfo.InvariantCulture); } if (e != Effect.CarryWeight) { return text + "% " + Label(e); } return text + " " + Label(e); } } public sealed class EffectList { public static readonly EffectList Empty = new EffectList(new List<(Effect, float)>()); public IReadOnlyList<(Effect Effect, float PerGrade)> Entries { get; } public bool IsEmpty => Entries.Count == 0; public EffectList(IReadOnlyList<(Effect Effect, float PerGrade)> entries) { Entries = entries; } public static EffectList Parse(string text, List<string> errors = null) { List<(Effect, float)> list = new List<(Effect, float)>(); string[] array = (text ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length != 0) { int num = text2.IndexOf(':'); if (num <= 0 || !Enum.TryParse<Effect>(text2.Substring(0, num).Trim(), ignoreCase: true, out var result) || !float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || float.IsNaN(result2) || float.IsInfinity(result2)) { errors?.Add(text2); } else { list.Add((result, Math.Max(-100f, Math.Min(100f, result2)))); } } } return new EffectList(list); } public override string ToString() { return string.Join(", ", Entries.Select(((Effect Effect, float PerGrade) e) => string.Format("{0}:{1}", e.Effect, e.PerGrade.ToString("R", CultureInfo.InvariantCulture)))); } } public readonly struct Enhancement : IEquatable<Enhancement> { public const string GemKey = "northerngemcraft.gem"; public const string GradeKey = "northerngemcraft.grade"; public static readonly Enhancement Empty = new Enhancement(Gem.None, 0); public Gem Gem { get; } public int Grade { get; } public bool IsEmpty => Gem == Gem.None; public Enhancement(Gem gem, int grade) { Gem = gem; Grade = ((gem != Gem.None) ? Math.Max(1, grade) : 0); } public static Enhancement Read(IReadOnlyDictionary<string, string> data) { if (data == null || !data.TryGetValue("northerngemcraft.gem", out var value)) { return Empty; } Gem gem = Gems.Parse(value); if (gem == Gem.None) { return Empty; } string value2; int result; int grade = ((!data.TryGetValue("northerngemcraft.grade", out value2) || !int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) ? 1 : result); return new Enhancement(gem, grade); } public void Write(IDictionary<string, string> data) { if (IsEmpty) { data.Remove("northerngemcraft.gem"); data.Remove("northerngemcraft.grade"); } else { data["northerngemcraft.gem"] = Gem.ToString(); data["northerngemcraft.grade"] = Grade.ToString(CultureInfo.InvariantCulture); } } public static string Roman(int grade) { return grade switch { 1 => "I", 2 => "II", 3 => "III", 4 => "IV", 5 => "V", _ => grade.ToString(CultureInfo.InvariantCulture), }; } public bool Equals(Enhancement other) { if (Gem == other.Gem) { return Grade == other.Grade; } return false; } public override bool Equals(object obj) { if (obj is Enhancement other) { return Equals(other); } return false; } public override int GetHashCode() { return ((int)Gem * 397) ^ Grade; } public override string ToString() { if (!IsEmpty) { return $"{Gem} {Roman(Grade)}"; } return "none"; } } public sealed class EnhanceSettings { public sealed class Field { public string Section { get; } public string Name { get; } public float Default { get; } public float Min { get; } public float Max { get; } public string Description { get; } public Field(string section, string name, float defaultValue, float min, float max, string description) { Section = section; Name = name; Default = defaultValue; Min = min; Max = max; Description = description; } } public sealed class TextField { public string Section { get; } public string Name { get; } public string Default { get; } public string Description { get; } public TextField(string section, string name, string defaultValue, string description) { Section = section; Name = name; Default = defaultValue; Description = description; } } public const string CostsSection = "1 - Costs"; public const string EffectsSection = "2 - Gem effects"; public const string GeneralSection = "3 - General"; public const string EffectHelp = "Comma separated Effect:value-per-grade (grade III = 3x). The first entry is the main benefit, which ArmorCaps measure. Effects: MaxHealth, HealthRegen, StaminaRegen, EitrRegen, PhysicalDamageTaken, MoveSpeed, CarryWeight (flat), RunStamina, Durability, AttackStamina, EitrCost, LifeSteal, Damage. Values in % with their natural sign: StaminaRegen:2 = +2%, AttackStamina:-3 = 3% less stamina per attack, PhysicalDamageTaken:-1 = 1% less damage taken. Durability and Damage change the item itself. Empty = the gem does nothing in that slot."; public static readonly IReadOnlyList<Field> Fields = new Field[8] { new Field("1 - Costs", "MaxGrade", 3f, 1f, 3f, "Highest grade a gem can be polished to (1 = no polishing)."), new Field("1 - Costs", "SetCoins", 20f, 0f, 10000f, "Ancient Coins to set a gem (grade I)."), new Field("1 - Costs", "PolishToIICoins", 60f, 0f, 10000f, "Ancient Coins to polish a gem to grade II."), new Field("1 - Costs", "PolishToIIICoins", 150f, 0f, 10000f, "Ancient Coins to polish a gem to grade III."), new Field("1 - Costs", "RemoveCoins", 30f, 0f, 10000f, "Ancient Coins to remove a gem."), new Field("1 - Costs", "SetGems", 1f, 1f, 20f, "Gems used to set a gem."), new Field("1 - Costs", "PolishToIIGems", 1f, 0f, 20f, "Extra gems of the same kind used to polish to grade II."), new Field("1 - Costs", "PolishToIIIGems", 2f, 0f, 20f, "Extra gems of the same kind used to polish to grade III.") }; public static readonly IReadOnlyList<TextField> TextFields = new TextField[11] { new TextField("2 - Gem effects", "GrimvarnOnArmor", "MaxHealth:1, StaminaRegen:-1", "Grimvarn set in armor. Comma separated Effect:value-per-grade (grade III = 3x). The first entry is the main benefit, which ArmorCaps measure. Effects: MaxHealth, HealthRegen, StaminaRegen, EitrRegen, PhysicalDamageTaken, MoveSpeed, CarryWeight (flat), RunStamina, Durability, AttackStamina, EitrCost, LifeSteal, Damage. Values in % with their natural sign: StaminaRegen:2 = +2%, AttackStamina:-3 = 3% less stamina per attack, PhysicalDamageTaken:-1 = 1% less damage taken. Durability and Damage change the item itself. Empty = the gem does nothing in that slot."), new TextField("2 - Gem effects", "SolrythOnArmor", "StaminaRegen:2, MaxHealth:-0.5", "Solryth set in armor."), new TextField("2 - Gem effects", "VeydrisOnArmor", "EitrRegen:2, StaminaRegen:-1", "Veydris set in armor."), new TextField("2 - Gem effects", "DraumyxOnArmor", "PhysicalDamageTaken:-1, MoveSpeed:-0.5", "Draumyx set in armor."), new TextField("2 - Gem effects", "GrimvarnOnWeapon", "Durability:10, AttackStamina:1", "Grimvarn set in a weapon (works while it is in hand)."), new TextField("2 - Gem effects", "SolrythOnWeapon", "AttackStamina:-3, Durability:-5", "Solryth set in a weapon."), new TextField("2 - Gem effects", "VeydrisOnWeapon", "EitrCost:-3, Durability:-5", "Veydris set in a weapon."), new TextField("2 - Gem effects", "DraumyxOnWeapon", "LifeSteal:1, HealthRegen:-2", "Draumyx set in a weapon."), new TextField("2 - Gem effects", "ArmorCaps", "MaxHealth:10, StaminaRegen:15, EitrRegen:15, PhysicalDamageTaken:8", "Most a main benefit can give from all worn armor together, as Effect:percent (always the helpful amount, so PhysicalDamageTaken:8 = at most 8% less). When a cap cuts a gem's main benefit, its side effects are cut by the same share."), new TextField("3 - General", "Stations", "$piece_blackforge:max:3, $piece_magetable:max:2", "Where enhancing works, as station:stationLevel:gearLevel. The station must be upgraded to at least stationLevel; max = fully upgraded in vanilla (black forge 6, Galdr table 5; extensions from other mods do not raise it). Only gear whose recipe needs at least gearLevel at that station can take a gem (default: Ashlands gear and above). gearLevel defaults to 1 when left out."), new TextField("3 - General", "EnhanceableSlots", "Helmet,Chest,Legs,Cape,Shield,Weapon", "Which gear can hold a gem, comma separated: Helmet, Chest, Legs, Cape, Shield, Weapon. Shields and capes count as armor.") }; public static readonly EnhanceSettings Default = new EnhanceSettings(enabled: true, removeReturnsGem: false, null, null); private readonly Dictionary<string, float> values = new Dictionary<string, float>(StringComparer.Ordinal); private readonly Dictionary<string, string> texts = new Dictionary<string, string>(StringComparer.Ordinal); private readonly Dictionary<(Gem, bool), EffectList> effects = new Dictionary<(Gem, bool), EffectList>(); private readonly Dictionary<Effect, float> caps = new Dictionary<Effect, float>(); private readonly Dictionary<string, (int Station, int Gear)> stations = new Dictionary<string, (int, int)>(StringComparer.Ordinal); private readonly HashSet<Slot> slots = new HashSet<Slot>(); public const int MaxLevel = 0; public bool Enabled { get; } public bool RemoveReturnsGem { get; } public List<string> Errors { get; } public float this[string name] => values[name]; public int MaxGrade => (int)Math.Round(this["MaxGrade"]); public EnhanceSettings(bool enabled, bool removeReturnsGem, IReadOnlyDictionary<string, float> numbers, IReadOnlyDictionary<string, string> textValues) { Enabled = enabled; RemoveReturnsGem = removeReturnsGem; foreach (Field field in Fields) { float value; float val = ((numbers != null && numbers.TryGetValue(field.Name, out value) && !float.IsNaN(value) && !float.IsInfinity(value)) ? value : field.Default); values[field.Name] = Math.Min(field.Max, Math.Max(field.Min, val)); } foreach (TextField textField in TextFields) { string value2; string text = ((textValues != null && textValues.TryGetValue(textField.Name, out value2) && value2 != null) ? value2 : textField.Default); texts[textField.Name] = Sanitize(text); } Errors = new List<string>(); Gem[] all = Gems.All; for (int i = 0; i < all.Length; i++) { Gem item = all[i]; effects[(item, true)] = EffectList.Parse(texts[item.ToString() + "OnArmor"], Errors); effects[(item, false)] = EffectList.Parse(texts[item.ToString() + "OnWeapon"], Errors); } foreach (var (key, value3) in EffectList.Parse(texts["ArmorCaps"], Errors).Entries) { caps[key] = Math.Abs(value3); } string[] array = texts["Stations"].Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); string text2 = array2[0].Trim(); if (text2.Length > 0) { bool flag = array2.Length > 1 && array2[1].Trim().Equals("max", StringComparison.OrdinalIgnoreCase); stations[text2] = ((!flag) ? Level(array2, 1) : 0, Level(array2, 2)); } } array = texts["EnhanceableSlots"].Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { if (Enum.TryParse<Slot>(array[i].Trim(), ignoreCase: true, out var result) && result != Slot.None) { slots.Add(result); } } } public string Text(string name) { return texts[name]; } public bool CanEnhance(Slot slot) { if (Enabled && slot != Slot.None) { return slots.Contains(slot); } return false; } public EffectList EffectsOf(Gem gem, Slot slot) { if (gem == Gem.None || slot == Slot.None) { return EffectList.Empty; } return effects[(gem, Rules.IsArmor(slot))]; } public float? CapOf(Effect effect) { if (!caps.TryGetValue(effect, out var value)) { return null; } return value; } public static int? VanillaMaxLevel(string stationName) { return stationName switch { "$piece_blackforge" => 6, "$piece_magetable" => 5, "$piece_forge" => 7, "$piece_workbench" => 5, "$piece_cauldron" => 7, "$piece_artisanstation" => 2, _ => null, }; } public (int Station, int Gear)? StationRequirement(string stationName) { if (stationName == null || !stations.TryGetValue(stationName, out (int, int) value)) { return null; } return value; } private static int Level(string[] pieces, int index) { if (pieces.Length <= index || !int.TryParse(pieces[index].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return 1; } return Math.Max(1, result); } public string Encode() { List<string> list = new List<string> { Enabled ? "1" : "0", RemoveReturnsGem ? "1" : "0" }; list.AddRange(Fields.Select((Field f) => f.Name + "=" + values[f.Name].ToString("R", CultureInfo.InvariantCulture))); list.AddRange(TextFields.Select((TextField f) => f.Name + "=" + texts[f.Name])); return string.Join(";", list); } public static bool TryDecode(string text, out EnhanceSettings settings) { settings = null; string[] array = (text ?? "").Split(new char[1] { ';' }); if (array.Length < 2 || !IsBool(array[0]) || !IsBool(array[1])) { return false; } HashSet<string> hashSet = new HashSet<string>(Fields.Select((Field f) => f.Name)); Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.Ordinal); Dictionary<string, string> dictionary2 = new Dictionary<string, string>(StringComparer.Ordinal); for (int num = 2; num < array.Length; num++) { int num2 = array[num].IndexOf('='); if (num2 <= 0) { return false; } string text2 = array[num].Substring(0, num2); string text3 = array[num].Substring(num2 + 1); if (hashSet.Contains(text2)) { if (!float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return false; } dictionary[text2] = result; } else { dictionary2[text2] = text3; } } settings = new EnhanceSettings(array[0] == "1", array[1] == "1", dictionary, dictionary2); return true; } private static string Sanitize(string text) { return text.Replace(";", ",").Replace("=", ":").Trim(); } private static bool IsBool(string s) { if (!(s == "0")) { return s == "1"; } return true; } } public enum Gem { None, Grimvarn, Solryth, Veydris, Draumyx } public static class Gems { public static readonly Gem[] All = new Gem[4] { Gem.Grimvarn, Gem.Solryth, Gem.Veydris, Gem.Draumyx }; public const string AncientCoinPrefab = "AncientCoin"; public static string PrefabName(Gem gem) { return gem switch { Gem.Grimvarn => "AncientGemstoneGreen", Gem.Solryth => "AncientGemstoneOrange", Gem.Veydris => "AncientGemstonePurple", Gem.Draumyx => "AncientGemstoneBlack", _ => throw new ArgumentOutOfRangeException("gem", gem, null), }; } public static Gem Parse(string text) { if (!Enum.TryParse<Gem>(text, ignoreCase: true, out var result) || Array.IndexOf(All, result) < 0) { return Gem.None; } return result; } } public enum Slot { None, Helmet, Chest, Legs, Cape, Shield, Weapon } public enum EnhanceAction { Set, Polish, Remove } public readonly struct Cost { public int Gems { get; } public int Coins { get; } public Cost(int gems, int coins) { Gems = gems; Coins = coins; } } public sealed class EffectTotals { public static readonly EffectTotals None = new EffectTotals(new Dictionary<Effect, float>()); private readonly Dictionary<Effect, float> totals; public float this[Effect effect] { get { if (!totals.TryGetValue(effect, out var value)) { return 0f; } return value; } } public EffectTotals(Dictionary<Effect, float> totals) { this.totals = totals; } } public static class Rules { public static Slot SlotFor(int itemType) { switch (itemType) { case 3: case 4: case 14: case 22: return Slot.Weapon; case 5: return Slot.Shield; case 6: return Slot.Helmet; case 7: return Slot.Chest; case 11: return Slot.Legs; case 17: return Slot.Cape; default: return Slot.None; } } public static bool IsArmor(Slot slot) { if (slot != Slot.None) { return slot != Slot.Weapon; } return false; } public static bool CanDo(EnhanceAction action, Enhancement current, EnhanceSettings settings) { switch (action) { case EnhanceAction.Set: return current.IsEmpty; case EnhanceAction.Polish: if (!current.IsEmpty) { return current.Grade < settings.MaxGrade; } return false; case EnhanceAction.Remove: return !current.IsEmpty; default: return false; } } public static Cost CostOf(EnhanceAction action, Enhancement current, EnhanceSettings settings) { switch (action) { case EnhanceAction.Set: return new Cost(Int(settings["SetGems"]), Int(settings["SetCoins"])); case EnhanceAction.Polish: if (current.Grade + 1 < 3) { return new Cost(Int(settings["PolishToIIGems"]), Int(settings["PolishToIICoins"])); } return new Cost(Int(settings["PolishToIIIGems"]), Int(settings["PolishToIIICoins"])); case EnhanceAction.Remove: return new Cost(0, Int(settings["RemoveCoins"])); default: throw new ArgumentOutOfRangeException("action", action, null); } } public static Enhancement Apply(EnhanceAction action, Enhancement current, Gem chosen) { return action switch { EnhanceAction.Set => new Enhancement(chosen, 1), EnhanceAction.Polish => new Enhancement(current.Gem, current.Grade + 1), EnhanceAction.Remove => Enhancement.Empty, _ => throw new ArgumentOutOfRangeException("action", action, null), }; } public static IEnumerable<(Effect Effect, float Value)> ItemEffects(Enhancement e, Slot slot, EnhanceSettings s) { if (e.IsEmpty || !s.CanEnhance(slot)) { yield break; } int grade = Math.Min(e.Grade, s.MaxGrade); foreach (var (item, num) in s.EffectsOf(e.Gem, slot).Entries) { yield return (Effect: item, Value: num * (float)grade); } } public static float ItemOwnEffect(Enhancement e, Slot slot, Effect effect, EnhanceSettings s) { float num = 0f; foreach (var (effect2, num2) in ItemEffects(e, slot, s)) { if (effect2 == effect) { num += num2; } } return num; } public static EffectTotals PlayerTotals(IEnumerable<(Enhancement Enhancement, Slot Slot)> worn, Enhancement weapon, EnhanceSettings s) { Dictionary<Effect, float> dictionary = new Dictionary<Effect, float>(); if (!s.Enabled) { return new EffectTotals(dictionary); } List<(Effect, List<(Effect, float)>)> list = new List<(Effect, List<(Effect, float)>)>(); Dictionary<Effect, float> dictionary2 = new Dictionary<Effect, float>(); foreach (var (e, slot) in worn) { if (IsArmor(slot)) { List<(Effect, float)> list2 = new List<(Effect, float)>(ItemEffects(e, slot, s)); if (list2.Count != 0) { Effect item = list2[0].Item1; list.Add((item, list2)); dictionary2[item] = (dictionary2.TryGetValue(item, out var value) ? value : 0f) + Math.Max(0f, Effects.Goodness(item, list2[0].Item2)); } } } foreach (var item4 in list) { Effect item2 = item4.Item1; List<(Effect, float)> item3 = item4.Item2; float? num = s.CapOf(item2); float num2 = dictionary2[item2]; float num3 = ((num.HasValue && num2 > num.Value) ? (num.Value / num2) : 1f); foreach (var (effect, num4) in item3) { if (!Effects.OnItem(effect)) { dictionary[effect] = (dictionary.TryGetValue(effect, out var value2) ? value2 : 0f) + num4 * num3; } } } foreach (var (effect2, num5) in ItemEffects(weapon, Slot.Weapon, s)) { if (!Effects.OnItem(effect2)) { dictionary[effect2] = (dictionary.TryGetValue(effect2, out var value3) ? value3 : 0f) + num5; } } return new EffectTotals(dictionary); } private static int Int(float value) { return (int)Math.Round(value); } } }
plugins/NorthernGemcraft.dll
Decompiled 3 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using NorthernGemcraft.Core; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("jonasd")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2+fb61e20309b17b5c1cca7e2cd23a964eea5e02c8")] [assembly: AssemblyProduct("Northern Gemcraft")] [assembly: AssemblyTitle("NorthernGemcraft")] [assembly: AssemblyVersion("0.1.2.0")] namespace NorthernGemcraft { internal static class Discovery { [HarmonyPatch(typeof(Player), "AddKnownItem")] private static class PickupPatch { private static void Postfix(Player __instance) { Check(__instance); } } private const string DiscoveredKey = "northerngemcraft.discovered."; private static string lastReport; public static bool Knows(Player player, string prefabName) { ItemDrop val = Enhancer.PrefabItem(prefabName); if ((Object)(object)val != (Object)null) { return player.IsKnownMaterial(val.m_itemData.m_shared.m_name); } return false; } public unsafe static bool IsDiscovered(Player player, Gem gem) { if ((Object)(object)player != (Object)null) { if (!player.NoCostCheat()) { return player.m_customData.ContainsKey("northerngemcraft.discovered." + ((object)(*(Gem*)(&gem))/*cast due to .constrained prefix*/).ToString()); } return true; } return false; } public static bool AnyDiscovered(Player player) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Gem[] all = Gems.All; foreach (Gem gem in all) { if (IsDiscovered(player, gem)) { return true; } } return false; } public unsafe static void Check(Player player) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)MessageHud.instance == (Object)null) { return; } Report(player); if (!SettingsSync.Current.Enabled || !Eligibility.StationReady(player.GetCurrentCraftingStation()) || !Knows(player, "AncientCoin")) { return; } Gem[] all = Gems.All; for (int i = 0; i < all.Length; i++) { Gem val = all[i]; string key = "northerngemcraft.discovered." + ((object)(*(Gem*)(&val))/*cast due to .constrained prefix*/).ToString(); if (!player.m_customData.ContainsKey(key) && Knows(player, Gems.PrefabName(val))) { player.m_customData[key] = "1"; ItemDrop val2 = Enhancer.PrefabItem(Gems.PrefabName(val)); MessageHud.instance.QueueUnlockMsg(val2.m_itemData.GetIcon(), "Discovered: Enhancing", val2.m_itemData.m_shared.m_name); Plugin.Detail($"Discovered enhancing with {val}"); } } } private static void Report(Player player) { if (Plugin.LogDetails != null && Plugin.LogDetails.Value) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); string arg = string.Join(", ", Array.ConvertAll(Gems.All, (Gem g) => $"{g} known={Knows(player, Gems.PrefabName(g))} discovered={IsDiscovered(player, g)}")); string text = (((Object)(object)currentCraftingStation == (Object)null) ? "no station" : (string.Format("station {0} level {1} (needs {2}, ", currentCraftingStation.m_name, currentCraftingStation.GetLevel(true), Eligibility.RequiredLevel(currentCraftingStation)?.ToString() ?? "not allowed") + string.Format("craft tab {0}); coin known={1}; {2}", currentCraftingStation.m_hasCraftTab, Knows(player, "AncientCoin"), arg))); if (text != lastReport) { lastReport = text; Plugin.Log.LogInfo((object)("[enhance check] " + text)); } } } } internal static class Eligibility { private static readonly Dictionary<string, int> MaxLevels = new Dictionary<string, int>(); public static int? RequiredLevel(CraftingStation station) { int? num = (((Object)(object)station == (Object)null) ? ((int?)null) : SettingsSync.Current.StationRequirement(station.m_name)?.Item1); if (num != 0) { return num; } return MaxLevelOf(station); } public static int MaxLevelOf(CraftingStation station) { int? num = EnhanceSettings.VanillaMaxLevel(station.m_name); if (num.HasValue) { return num.Value; } if (MaxLevels.TryGetValue(station.m_name, out var value)) { return value; } int num2 = 0; if ((Object)(object)ZNetScene.instance != (Object)null) { foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { StationExtension val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<StationExtension>() : null); if ((Object)(object)val != (Object)null && (Object)(object)val.m_craftingStation != (Object)null && val.m_craftingStation.m_name == station.m_name) { num2++; } } } MaxLevels[station.m_name] = 1 + num2; Plugin.Detail($"Fully upgraded {station.m_name} = level {1 + num2}"); return 1 + num2; } public static bool StationReady(CraftingStation station) { int? num = RequiredLevel(station); if (num.HasValue) { return station.GetLevel(true) >= num.Value; } return false; } public static bool RecipeQualifies(Recipe recipe, CraftingStation station) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected I4, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) (int, int)? tuple = (((Object)(object)station == (Object)null) ? (((int, int)?)null) : SettingsSync.Current.StationRequirement(station.m_name)); if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_craftingStation != (Object)null && tuple.HasValue && recipe.m_craftingStation.m_name == station.m_name && recipe.m_minStationLevel >= tuple.Value.Item2) { return SettingsSync.Current.CanEnhance(Rules.SlotFor((int)recipe.m_item.m_itemData.m_shared.m_itemType)); } return false; } public static bool ItemQualifies(ItemData item, CraftingStation station) { if (item != null && (Object)(object)ObjectDB.instance != (Object)null) { return RecipeQualifies(ObjectDB.instance.GetRecipe(item), station); } return false; } } internal static class Enhancements { private static readonly List<(Enhancement, Slot)> Worn = new List<(Enhancement, Slot)>(); private static int totalsFrame = -1; private static EffectTotals totals = EffectTotals.None; public static EffectTotals Local { get { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (totalsFrame == Time.frameCount) { return totals; } totalsFrame = Time.frameCount; Worn.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { totals = EffectTotals.None; return totals; } foreach (ItemData equippedItem in ((Humanoid)localPlayer).GetInventory().GetEquippedItems()) { Enhancement item = Of(equippedItem); if (!((Enhancement)(ref item)).IsEmpty) { Worn.Add((item, SlotOf(equippedItem))); } } ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon(); Enhancement val = (((int)SlotOf(currentWeapon) == 6) ? Of(currentWeapon) : Enhancement.Empty); totals = Rules.PlayerTotals((IEnumerable<ValueTuple<Enhancement, Slot>>)Worn, val, SettingsSync.Current); return totals; } } public static Enhancement Of(ItemData item) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (item != null) { return Enhancement.Read((IReadOnlyDictionary<string, string>)item.m_customData); } return Enhancement.Empty; } public static Slot SlotOf(ItemData item) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (item != null) { return Rules.SlotFor((int)item.m_shared.m_itemType); } return (Slot)0; } public static void Write(ItemData item, Enhancement enhancement) { ((Enhancement)(ref enhancement)).Write((IDictionary<string, string>)item.m_customData); } public static bool IsLocalPlayer(Character character) { if ((Object)(object)character != (Object)null) { return (Object)(object)character == (Object)(object)Player.m_localPlayer; } return false; } public static float OwnEffect(ItemData item, Effect effect) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (item != null) { return Rules.ItemOwnEffect(Of(item), SlotOf(item), effect, SettingsSync.Current); } return 0f; } public unsafe static string GemName(Gem gem) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) ItemDrop val = Enhancer.PrefabItem(Gems.PrefabName(gem)); if (!((Object)(object)val != (Object)null)) { return ((object)(*(Gem*)(&gem))/*cast due to .constrained prefix*/).ToString(); } return Localization.instance.Localize(val.m_itemData.m_shared.m_name); } public static string EffectText(Gem gem, Slot slot, int grade) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) IEnumerable<string> values = from fx in Rules.ItemEffects(new Enhancement(gem, grade), slot, SettingsSync.Current) select "<color=" + ((Effects.Goodness(fx.Effect, fx.Value) >= 0f) ? "#9EE07A" : "#E08A7A") + ">" + Effects.Format(fx.Effect, fx.Value) + "</color>"; string text = string.Join(", ", values); if (text.Length <= 0) { return "no effect"; } return text; } } internal static class Enhancer { private static readonly MethodInfo HaveRequirementItems = AccessTools.Method(typeof(Player), "HaveRequirementItems", new Type[4] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) }, (Type[])null); private static Recipe costRecipe; public static ItemDrop PrefabItem(string prefabName) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<ItemDrop>(); } public static Gem GemFor(EnhanceAction action, Enhancement current, Gem chosen) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) if ((int)action != 0) { return ((Enhancement)(ref current)).Gem; } return chosen; } public static bool CanAfford(Player player, EnhanceAction action, Enhancement current, Gem chosen) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (player.NoCostCheat()) { return true; } if ((Object)(object)costRecipe == (Object)null) { costRecipe = ScriptableObject.CreateInstance<Recipe>(); ((Object)costRecipe).name = "NorthernGemcraftCost"; } costRecipe.m_resources = Requirements(action, current, chosen); return (bool)HaveRequirementItems.Invoke(player, new object[4] { costRecipe, false, 1, 1 }); } public static Requirement[] Requirements(EnhanceAction action, Enhancement current, Gem chosen) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Cost val = Rules.CostOf(action, current, SettingsSync.Current); List<Requirement> list = new List<Requirement>(2); Add(list, Gems.PrefabName(GemFor(action, current, chosen)), ((Cost)(ref val)).Gems); Add(list, "AncientCoin", ((Cost)(ref val)).Coins); return list.ToArray(); } private static void Add(List<Requirement> requirements, string prefabName, int amount) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown ItemDrop val = PrefabItem(prefabName); if ((Object)(object)val != (Object)null && amount > 0) { requirements.Add(new Requirement { m_resItem = val, m_amount = amount, m_amountPerLevel = 0, m_recover = false }); } } public static bool TryPerform(Player player, ItemData item, EnhanceAction action, Gem chosen) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) EnhanceSettings current = SettingsSync.Current; Inventory inventory = ((Humanoid)player).GetInventory(); Enhancement val = Enhancements.Of(item); if (!current.CanEnhance(Enhancements.SlotOf(item)) || !inventory.ContainsItem(item) || !Eligibility.StationReady(player.GetCurrentCraftingStation()) || !Eligibility.ItemQualifies(item, player.GetCurrentCraftingStation()) || ((int)action == 0 && !Discovery.IsDiscovered(player, chosen)) || !Rules.CanDo(action, val, current) || !CanAfford(player, action, val, chosen)) { return false; } Gem val2 = GemFor(action, val, chosen); if (!player.NoCostCheat()) { player.ConsumeResources(Requirements(action, val, chosen), 1, -1, 1); } Enhancement val3 = Rules.Apply(action, val, chosen); Enhancements.Write(item, val3); item.m_durability = Mathf.Min(item.m_durability, item.GetMaxDurability()); if ((int)action == 2 && current.RemoveReturnsGem) { inventory.AddItem(Gems.PrefabName(val2), 1, 1, 0, player.GetPlayerID(), player.GetPlayerName(), false, false); } string text = Localization.instance.Localize(item.m_shared.m_name); string text2 = Enhancements.GemName(val2); string text3 = (((int)action == 2) ? (text2 + " removed from " + text) : (text + ": " + text2 + " " + Enhancement.Roman(((Enhancement)(ref val3)).Grade))); ((Character)player).Message((MessageType)2, text3, 0, (Sprite)null, false); Plugin.Detail($"{action} on {item.m_shared.m_name}: {val} -> {val3}"); return true; } } [BepInPlugin("com.jonasd.valheim.northerngemcraft", "Northern Gemcraft", "0.1.2")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.jonasd.valheim.northerngemcraft"; public const string PluginName = "Northern Gemcraft"; public const string PluginVersion = "0.1.2"; internal static ManualLogSource Log; internal static ConfigEntry<bool> LogDetails; internal static ConfigEntry<bool> RequireOnClients; private readonly Dictionary<string, ConfigEntry<float>> numbers = new Dictionary<string, ConfigEntry<float>>(); private readonly Dictionary<string, ConfigEntry<string>> texts = new Dictionary<string, ConfigEntry<string>>(); private ConfigEntry<bool> enabledSetting; private ConfigEntry<bool> removeReturnsGem; private Harmony harmony; private void Awake() { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; EnhanceSettings val = EnhanceSettings.Default; foreach (Field field in EnhanceSettings.Fields) { numbers[field.Name] = ((BaseUnityPlugin)this).Config.Bind<float>(field.Section, field.Name, field.Default, $"{field.Description} Range {field.Min:0.##} to {field.Max:0.##}."); } removeReturnsGem = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Costs", "RemoveReturnsGem", val.RemoveReturnsGem, "true = removing a gem gives it back (one gem, whatever its grade). false = the gem is destroyed."); foreach (TextField textField in EnhanceSettings.TextFields) { texts[textField.Name] = ((BaseUnityPlugin)this).Config.Bind<string>(textField.Section, textField.Name, textField.Default, textField.Description); } enabledSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - General", "Enabled", val.Enabled, "Turns enhancing and all gem effects on or off. On a server, the server's settings (all except LogDetails) apply to every player."); RequireOnClients = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - General", "RequireOnClients", true, "Server only. true = players without this mod (or with another version) cannot join; they get the game's \"Incompatible version\" error."); LogDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - General", "LogDetails", false, "Write enhancements to the BepInEx log. For testing."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { SettingsSync.OnLocalSettingsChanged(ReadLocalSettings()); }; SettingsSync.Initialize(ReadLocalSettings()); harmony = new Harmony("com.jonasd.valheim.northerngemcraft"); harmony.PatchAll(); } private EnhanceSettings ReadLocalSettings() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00c2: Expected O, but got Unknown Dictionary<string, float> dictionary = new Dictionary<string, float>(); foreach (KeyValuePair<string, ConfigEntry<float>> number in numbers) { dictionary[number.Key] = number.Value.Value; } Dictionary<string, string> dictionary2 = new Dictionary<string, string>(); foreach (KeyValuePair<string, ConfigEntry<string>> text in texts) { dictionary2[text.Key] = text.Value.Value; } EnhanceSettings val = new EnhanceSettings(enabledSetting.Value, removeReturnsGem.Value, (IReadOnlyDictionary<string, float>)dictionary, (IReadOnlyDictionary<string, string>)dictionary2); WarnAbout(val); return val; } internal static void WarnAbout(EnhanceSettings settings) { if (settings.Errors.Count > 0) { Log.LogWarning((object)("Ignored unreadable gem effect/cap entries (use Effect:number, e.g. MaxHealth:1): " + string.Join(" | ", settings.Errors))); } } internal static void Detail(string message) { if (LogDetails != null && LogDetails.Value) { Log.LogInfo((object)message); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } internal static class SettingsSync { [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNetAwakePatch { private static void Postfix(ZNet __instance) { fromServer = null; ZRoutedRpc.instance.Register<string>("NG_Settings", (Action<long, string>)OnSettings); if (__instance.IsServer()) { ZRoutedRpc instance = ZRoutedRpc.instance; instance.m_onNewPeer = (Action<long>)Delegate.Combine(instance.m_onNewPeer, new Action<long>(SendTo)); } } } private const string SettingsRpc = "NG_Settings"; private static EnhanceSettings local = EnhanceSettings.Default; private static EnhanceSettings fromServer; public static EnhanceSettings Current => fromServer ?? local; public static void Initialize(EnhanceSettings settings) { local = settings; } public static void OnLocalSettingsChanged(EnhanceSettings settings) { local = settings; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null) { SendTo(0L); } } private static void SendTo(long peer) { ZRoutedRpc.instance.InvokeRoutedRPC(peer, "NG_Settings", new object[1] { local.Encode() }); } private static void OnSettings(long sender, string encoded) { ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) ? ZNet.instance.GetServerPeer() : null); if (val != null && sender == val.m_uid) { EnhanceSettings val2 = default(EnhanceSettings); if (EnhanceSettings.TryDecode(encoded, ref val2)) { fromServer = val2; Plugin.Detail("Using the server's settings: " + encoded); } else { Plugin.Log.LogWarning((object)("Ignoring unreadable settings from the server: " + encoded)); } } } } internal static class VersionCheck { private sealed class Box { public string Version; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class NewConnectionPatch { private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { peer.m_rpc.Register<string>("NorthernGemcraft_Version", (Action<ZRpc, string>)delegate(ZRpc rpc, string version) { Received.GetOrCreateValue(rpc).Version = version; }); } else { peer.m_rpc.Invoke("NorthernGemcraft_Version", new object[1] { "0.1.2" }); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class PeerInfoPatch { private static bool Prefix(ZNet __instance, ZRpc rpc) { if (!__instance.IsServer() || !Plugin.RequireOnClients.Value) { return true; } Box value; string text = (Received.TryGetValue(rpc, out value) ? value.Version : null); if (text == "0.1.2") { return true; } Plugin.Log.LogWarning((object)("Turned away " + rpc.GetSocket().GetHostName() + ": " + ((text == null) ? "no Northern Gemcraft" : ("Northern Gemcraft " + text)) + ", server runs 0.1.2.")); rpc.Invoke("Error", new object[1] { 3 }); return false; } } private const string VersionRpc = "NorthernGemcraft_Version"; private const int ErrorVersion = 3; private static readonly ConditionalWeakTable<ZRpc, Box> Received = new ConditionalWeakTable<ZRpc, Box>(); } } namespace NorthernGemcraft.Ui { internal static class EnhanceTab { private sealed class Entry { public ItemData Item; public EnhanceAction Action; public Gem Gem; public GameObject Element; public bool SameAs(Entry other) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (other != null && other.Item == Item && other.Action == Action) { return other.Gem == Gem; } return false; } } [HarmonyPatch(typeof(InventoryGui), "Show")] private static class ShowPatch { private static void Prefix(InventoryGui __instance) { if (Active) { SetActive(__instance, active: false); ((Selectable)__instance.m_tabCraft).interactable = false; } } } [HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")] private static class CraftTabPatch { private static void Prefix(InventoryGui __instance) { SetActive(__instance, active: false); } } [HarmonyPatch(typeof(InventoryGui), "OnTabUpgradePressed")] private static class UpgradeTabPatch { private static void Prefix(InventoryGui __instance) { SetActive(__instance, active: false); } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedRecipe")] private static class SelectRowPatch { private static void Postfix(InventoryGui __instance, GameObject button) { if (Active && (Object)(object)button != (Object)null && Entries.TryGetValue(button, out var value)) { Select(__instance, value); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")] private static class PanelPatch { private static bool Available(Player player) { CraftingStation val = (((Object)(object)player != (Object)null) ? player.GetCurrentCraftingStation() : null); if (SettingsSync.Current.Enabled && (Object)(object)val != (Object)null && val.m_hasCraftTab && Eligibility.StationReady(val)) { return Discovery.AnyDiscovered(player); } return false; } private static void Prefix(InventoryGui __instance) { if (Active) { if (!Available(Player.m_localPlayer)) { SetActive(__instance, active: false); ((Selectable)__instance.m_tabCraft).interactable = false; } else { ((Selectable)__instance.m_tabCraft).interactable = true; ((Selectable)__instance.m_tabUpgrade).interactable = true; } } } private static void Postfix(InventoryGui __instance) { Discovery.Check(Player.m_localPlayer); EnsureTab(__instance); ((Component)tab).gameObject.SetActive(Available(Player.m_localPlayer) && ((Component)__instance.m_tabCraft).gameObject.activeSelf && ((Component)__instance.m_tabUpgrade).gameObject.activeSelf); if (Active) { Entry entry = SelectedEntry(__instance) ?? ((Ordered.Count > 0) ? Ordered[0] : null); if (entry != null) { Select(__instance, entry); } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] private static class ListPatch { private static bool Prefix(InventoryGui __instance, List<Recipe> recipes) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected I4, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return true; } IList list = AvailableRecipes.Invoke(__instance); foreach (object item in list) { GameObject val = ElementOf(item); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } list.Clear(); Entries.Clear(); Ordered.Clear(); Entry previous = selected; selected = null; Player localPlayer = Player.m_localPlayer; listStation = localPlayer.GetCurrentCraftingStation(); EnhanceSettings current = SettingsSync.Current; foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { Recipe recipe = ObjectDB.instance.GetRecipe(allItem); if (Eligibility.RecipeQualifies(recipe, listStation)) { AddEntries(__instance, localPlayer, recipe, allItem, current); } else if ((int)Rules.SlotFor((int)allItem.m_shared.m_itemType) != 0) { Plugin.Detail($" skipped {allItem.m_shared.m_name} ({allItem.m_shared.m_itemType}): " + (((Object)(object)recipe == (Object)null) ? "no recipe" : string.Format("made at {0} level {1}", recipe.m_craftingStation?.m_name ?? "no station", recipe.m_minStationLevel))); } } Plugin.Detail($"Enhance list at {listStation?.m_name}: {Ordered.Count} rows"); selected = Ordered.Find((Entry e) => e.SameAs(previous)) ?? ((previous != null) ? Ordered.Find((Entry e) => e.Item == previous.Item) : null); float num = Mathf.Max(ListBaseSize.Invoke(__instance), (float)list.Count * __instance.m_recipeListSpace); __instance.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, num); return false; } private static void AddEntries(InventoryGui gui, Player player, Recipe recipe, ItemData item, EnhanceSettings settings) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Enhancement val = Enhancements.Of(item); if (((Enhancement)(ref val)).IsEmpty) { Gem[] all = Gems.All; foreach (Gem gem in all) { if (Discovery.IsDiscovered(player, gem)) { Add(gui, player, recipe, new Entry { Item = item, Action = (EnhanceAction)0, Gem = gem }); } } } else { if (Rules.CanDo((EnhanceAction)1, val, settings)) { Add(gui, player, recipe, new Entry { Item = item, Action = (EnhanceAction)1, Gem = ((Enhancement)(ref val)).Gem }); } Add(gui, player, recipe, new Entry { Item = item, Action = (EnhanceAction)2, Gem = ((Enhancement)(ref val)).Gem }); } } private static void Add(InventoryGui gui, Player player, Recipe recipe, Entry entry) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) Enhancement current = Enhancements.Of(entry.Item); bool flag = Enhancer.CanAfford(player, entry.Action, current, entry.Gem); AddRecipeToList.Invoke(gui, new object[4] { player, recipe, entry.Item, flag }); IList obj = AvailableRecipes.Invoke(gui); GameObject val = (entry.Element = ElementOf(obj[obj.Count - 1])); Entries[val] = entry; Ordered.Add(entry); Transform val2 = val.transform.Find("name"); if ((Object)(object)val2 != (Object)null) { ((Component)val2).GetComponent<TMP_Text>().text = Localization.instance.Localize(entry.Item.m_shared.m_name) + ": " + ActionText(entry, current); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] private static class DetailsPatch { private static readonly FieldRef<InventoryGui, Color> StationLevelColor = AccessTools.FieldRefAccess<InventoryGui, Color>("m_minStationLevelBasecolor"); private static void Postfix(InventoryGui __instance, Player player) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Invalid comparison between Unknown and I4 if (!Active) { return; } Entry entry = SelectedEntry(__instance); if (entry != null) { EnhanceSettings current = SettingsSync.Current; Enhancement val = Enhancements.Of(entry.Item); Slot slot = Enhancements.SlotOf(entry.Item); Cost val2 = Rules.CostOf(entry.Action, val, current); Gem val3 = Enhancer.GemFor(entry.Action, val, entry.Gem); Enhancement next = Rules.Apply(entry.Action, val, entry.Gem); __instance.m_recipeName.text = Localization.instance.Localize(entry.Item.m_shared.m_name); __instance.m_recipeDecription.text = Describe(val, next, slot, entry.Action, current); ((Component)__instance.m_itemCraftType).gameObject.SetActive(true); __instance.m_itemCraftType.text = ActionText(entry, val); ((Component)__instance.m_variantButton).gameObject.SetActive(false); ShowRequiredStationLevel(__instance, player); int num = 0; num += ShowRequirement(__instance, player, num, Gems.PrefabName(val3), ((Cost)(ref val2)).Gems); num += ShowRequirement(__instance, player, num, "AncientCoin", ((Cost)(ref val2)).Coins); for (int i = num; i < __instance.m_recipeRequirementList.Length; i++) { InventoryGui.HideRequirement(__instance.m_recipeRequirementList[i].transform); } bool flag = Enhancer.CanAfford(player, entry.Action, val, entry.Gem); ((Selectable)__instance.m_craftButton).interactable = flag && Rules.CanDo(entry.Action, val, current) && AtListStation(player); ((Component)__instance.m_craftButton).GetComponentInChildren<TMP_Text>().text = (((int)entry.Action == 0) ? "Set" : (((int)entry.Action == 1) ? "Polish" : "Remove")); ((Component)__instance.m_craftButton).GetComponent<UITooltip>().m_text = (flag ? "" : Localization.instance.Localize("$msg_missingrequirement")); } } private static void ShowRequiredStationLevel(InventoryGui gui, Player player) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); int? num = Eligibility.RequiredLevel(currentCraftingStation); ((Component)gui.m_minStationLevelIcon).gameObject.SetActive(num.HasValue); if (num.HasValue) { gui.m_minStationLevelText.text = num.Value.ToString(); bool flag = currentCraftingStation.GetLevel(true) < num.Value; ((Graphic)gui.m_minStationLevelText).color = ((flag && Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : StationLevelColor.Invoke(gui)); } } private static int ShowRequirement(InventoryGui gui, Player player, int index, string prefabName, int amount) { ItemDrop val = Enhancer.PrefabItem(prefabName); if (amount <= 0 || (Object)(object)val == (Object)null || index >= gui.m_recipeRequirementList.Length) { return 0; } Requirement val2 = Requirements[index]; val2.m_resItem = val; val2.m_amount = amount; val2.m_amountPerLevel = 0; return InventoryGui.SetupRequirement(gui.m_recipeRequirementList[index].transform, val2, player, true, 1, 1) ? 1 : 0; } private static string Describe(Enhancement current, Enhancement next, Slot slot, EnhanceAction action, EnhanceSettings settings) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) string text = (Rules.IsArmor(slot) ? "armor" : "weapon"); string text2 = (((Enhancement)(ref current)).IsEmpty ? "No gem set." : ("Now: " + Enhancements.GemName(((Enhancement)(ref current)).Gem) + " " + Enhancement.Roman(((Enhancement)(ref current)).Grade) + ": " + Enhancements.EffectText(((Enhancement)(ref current)).Gem, slot, ((Enhancement)(ref current)).Grade))); text2 = (((int)action != 2) ? (text2 + "\n\nAfter: " + Enhancements.GemName(((Enhancement)(ref next)).Gem) + " " + Enhancement.Roman(((Enhancement)(ref next)).Grade) + ": " + Enhancements.EffectText(((Enhancement)(ref next)).Gem, slot, ((Enhancement)(ref next)).Grade)) : (text2 + (settings.RemoveReturnsGem ? "\n\nRemoving gives one gem back." : "\n\n<color=orange>Removing destroys the gem.</color>"))); text2 = ((!Rules.IsArmor(slot)) ? (text2 + "\n\nWeapon bonuses work while this " + text + " is in your hands.") : (text2 + "\n\nArmor bonuses from all worn pieces add up, to a cap per stat.")); return text2 + "\nGrades: up to " + Enhancement.Roman(settings.MaxGrade) + "."; } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] private static class CraftButtonPatch { private static bool Prefix(InventoryGui __instance) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return true; } Entry entry = SelectedEntry(__instance); Player localPlayer = Player.m_localPlayer; if (!AtListStation(localPlayer)) { if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false); } return false; } if (entry != null && Enhancer.TryPerform(localPlayer, entry.Item, entry.Action, entry.Gem)) { CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation != (Object)null) { currentCraftingStation.m_craftItemEffects.Create(((Component)localPlayer).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } UpdateCraftingPanel.Invoke(__instance, new object[1] { false }); } return false; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__20_0; internal void <EnsureTab>b__20_0() { InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null)) { SetActive(instance, active: true); UpdateCraftingPanel.Invoke(instance, new object[1] { false }); } } } private static readonly MethodInfo AddRecipeToList = AccessTools.Method(typeof(InventoryGui), "AddRecipeToList", (Type[])null, (Type[])null); private static readonly MethodInfo UpdateCraftingPanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null); private static readonly FieldRef<InventoryGui, IList> AvailableRecipes = AccessTools.FieldRefAccess<InventoryGui, IList>("m_availableRecipes"); private static readonly FieldInfo SelectedRecipe = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); private static readonly FieldRef<InventoryGui, float> ListBaseSize = AccessTools.FieldRefAccess<InventoryGui, float>("m_recipeListBaseSize"); private static readonly MethodInfo SetRecipe = AccessTools.Method(typeof(InventoryGui), "SetRecipe", (Type[])null, (Type[])null); private static PropertyInfo elementProperty; private static readonly Dictionary<GameObject, Entry> Entries = new Dictionary<GameObject, Entry>(); private static readonly List<Entry> Ordered = new List<Entry>(); private static readonly Requirement[] Requirements = (Requirement[])(object)new Requirement[2] { new Requirement(), new Requirement() }; private static Button tab; private static Entry selected; private static CraftingStation listStation; public static bool Active { get; private set; } private static GameObject ElementOf(object pair) { if ((object)elementProperty == null) { elementProperty = AccessTools.Property(pair.GetType(), "InterfaceElement"); } object? value = elementProperty.GetValue(pair); return (GameObject)((value is GameObject) ? value : null); } private static void SetActive(InventoryGui gui, bool active) { Active = active; selected = null; if ((Object)(object)tab != (Object)null) { ((Selectable)tab).interactable = !active; } if (active) { ((Selectable)gui.m_tabCraft).interactable = true; ((Selectable)gui.m_tabUpgrade).interactable = true; } } private static void EnsureTab(InventoryGui gui) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown if ((Object)(object)tab != (Object)null) { return; } GameObject val = Object.Instantiate<GameObject>(((Component)gui.m_tabUpgrade).gameObject, ((Component)gui.m_tabUpgrade).transform.parent); ((Object)val).name = "NorthernGemcraftTab"; RectTransform val2 = (RectTransform)((Component)gui.m_tabUpgrade).transform; RectTransform val3 = (RectTransform)((Component)gui.m_tabCraft).transform; float num = val2.anchoredPosition.x - val3.anchoredPosition.x; if (Mathf.Abs(num) < 1f) { Rect rect = val2.rect; num = ((Rect)(ref rect)).width + 4f; } ((RectTransform)val.transform).anchoredPosition = val2.anchoredPosition + new Vector2(num, 0f); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = "ENHANCE"; } tab = val.GetComponent<Button>(); tab.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = tab.onClick; object obj = <>c.<>9__20_0; if (obj == null) { UnityAction val4 = delegate { InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null)) { SetActive(instance, active: true); UpdateCraftingPanel.Invoke(instance, new object[1] { false }); } }; <>c.<>9__20_0 = val4; obj = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj); ((Selectable)tab).interactable = true; val.transform.SetSiblingIndex(((Component)gui.m_tabUpgrade).transform.GetSiblingIndex() + 1); } private static Entry SelectedEntry(InventoryGui gui) { if (selected == null || !((Object)(object)selected.Element != (Object)null) || !Entries.ContainsKey(selected.Element)) { return null; } return selected; } private static void Select(InventoryGui gui, Entry entry) { IList list = AvailableRecipes.Invoke(gui); for (int i = 0; i < list.Count; i++) { if ((Object)(object)ElementOf(list[i]) == (Object)(object)entry.Element) { SetRecipe.Invoke(gui, new object[2] { i, false }); SelectedRecipe.SetValue(gui, list[i]); selected = entry; break; } } } private static bool AtListStation(Player player) { CraftingStation val = (((Object)(object)player != (Object)null) ? player.GetCurrentCraftingStation() : null); if ((Object)(object)val != (Object)null) { return (Object)(object)val == (Object)(object)listStation; } return false; } private static string ActionText(Entry entry, Enhancement current) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 EnhanceAction action = entry.Action; if ((int)action != 0) { if ((int)action == 1) { return "Polish to " + Enhancement.Roman(((Enhancement)(ref current)).Grade + 1); } return "Remove gem"; } return "Set " + Enhancements.GemName(entry.Gem); } } } namespace NorthernGemcraft.Patches { internal static class Percent { public static float Factor(float percent) { return Mathf.Max(0f, 1f + percent / 100f); } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] internal static class MaxHealthPatch { private static void Postfix(Player __instance, ref float hp) { if (Enhancements.IsLocalPlayer((Character)(object)__instance)) { hp *= Percent.Factor(Enhancements.Local[(Effect)0]); } } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] internal static class StaminaRegenPatch { private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); private static void Postfix(SEMan __instance, ref float staminaMultiplier) { if (Enhancements.IsLocalPlayer(Owner.Invoke(__instance))) { staminaMultiplier *= Percent.Factor(Enhancements.Local[(Effect)2]); } } } [HarmonyPatch(typeof(SEMan), "ModifyEitrRegen")] internal static class EitrRegenPatch { private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); private static void Postfix(SEMan __instance, ref float eitrMultiplier) { if (Enhancements.IsLocalPlayer(Owner.Invoke(__instance))) { eitrMultiplier *= Percent.Factor(Enhancements.Local[(Effect)3]); } } } [HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")] internal static class HealthRegenPatch { private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); private static void Postfix(SEMan __instance, ref float regenMultiplier) { if (Enhancements.IsLocalPlayer(Owner.Invoke(__instance))) { regenMultiplier *= Percent.Factor(Enhancements.Local[(Effect)1]); } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] internal static class RunStaminaPatch { private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); private static void Postfix(SEMan __instance, ref float drain) { if (drain > 0f && Enhancements.IsLocalPlayer(Owner.Invoke(__instance))) { drain *= Percent.Factor(Enhancements.Local[(Effect)7]); } } } [HarmonyPatch(typeof(Player), "GetEquipmentMovementModifier")] internal static class MoveSpeedPatch { private static void Postfix(Player __instance, ref float __result) { if (Enhancements.IsLocalPlayer((Character)(object)__instance)) { __result += Enhancements.Local[(Effect)5] / 100f; } } } [HarmonyPatch(typeof(Player), "GetMaxCarryWeight")] internal static class CarryWeightPatch { private static void Postfix(Player __instance, ref float __result) { if (Enhancements.IsLocalPlayer((Character)(object)__instance)) { __result = Mathf.Max(0f, __result + Enhancements.Local[(Effect)6]); } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class DamageTakenPatch { private static void Prefix(Character __instance, HitData hit) { if (hit != null && Enhancements.IsLocalPlayer(__instance)) { float num = Enhancements.Local[(Effect)4]; if (num != 0f) { float num2 = Percent.Factor(num); hit.m_damage.m_blunt *= num2; hit.m_damage.m_slash *= num2; hit.m_damage.m_pierce *= num2; } } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class LifeStealPatch { private static void Prefix(Character __instance, HitData hit) { Player localPlayer = Player.m_localPlayer; if (hit != null && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance == (Object)(object)localPlayer) && !((Object)(object)hit.GetAttacker() != (Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && !__instance.IsPlayer() && !__instance.IsTamed() && !__instance.IsDead()) { float num = Enhancements.Local[(Effect)11]; float num2 = Mathf.Min(hit.GetTotalDamage(), __instance.GetHealth()) * num / 100f; if (num2 > 0.05f) { ((Character)localPlayer).Heal(num2, true); } } } } [HarmonyPatch(typeof(Attack), "GetAttackStamina")] internal static class AttackStaminaPatch { private static readonly FieldRef<Attack, Humanoid> Attacker = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); private static void Postfix(Attack __instance, ref float __result) { if (__result > 0f && Enhancements.IsLocalPlayer((Character)(object)Attacker.Invoke(__instance))) { __result *= Percent.Factor(Enhancements.Local[(Effect)9]); } } } [HarmonyPatch(typeof(Attack), "GetAttackEitr", new Type[] { typeof(Character), typeof(ItemData) })] internal static class AttackEitrPatch { private static void Postfix(Character character, ref float __result) { if (__result > 0f && Enhancements.IsLocalPlayer(character)) { __result *= Percent.Factor(Enhancements.Local[(Effect)10]); } } } [HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { typeof(int) })] internal static class DurabilityPatch { private static void Postfix(ItemData __instance, ref float __result) { float num = Enhancements.OwnEffect(__instance, (Effect)8); if (num != 0f) { __result *= Percent.Factor(num); } } } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] internal static class WeaponDamagePatch { private static void Postfix(ItemData __instance, ref DamageTypes __result) { float num = Enhancements.OwnEffect(__instance, (Effect)12); if (num != 0f) { ((DamageTypes)(ref __result)).Modify(Percent.Factor(num)); } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class TooltipPatch { private const string GemColor = "#E8B04B"; private static void Postfix(ItemData item, ref string __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Enhancement val = Enhancements.Of(item); Slot val2 = Enhancements.SlotOf(item); if (!((Enhancement)(ref val)).IsEmpty && (int)val2 != 0) { EnhanceSettings current = SettingsSync.Current; if ((int)val2 == 6 && current.CanEnhance(val2)) { Attack attack = item.m_shared.m_attack; __result = WithEnhanced(__result, "$item_staminause", attack.m_attackStamina, Rules.ItemOwnEffect(val, val2, (Effect)9, current)); __result = WithEnhanced(__result, "$item_eitruse", attack.m_attackEitr, Rules.ItemOwnEffect(val, val2, (Effect)10, current)); } string text = "\n\n<color=#E8B04B>" + Enhancements.GemName(((Enhancement)(ref val)).Gem) + " " + Enhancement.Roman(((Enhancement)(ref val)).Grade) + "</color>"; if (current.CanEnhance(val2)) { text = text + ": " + Enhancements.EffectText(((Enhancement)(ref val)).Gem, val2, ((Enhancement)(ref val)).Grade); text += Totals(current); } else { text += " (inactive)"; } __result += text; } } private static string Totals(EnhanceSettings settings) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) EffectTotals local = Enhancements.Local; StringBuilder stringBuilder = new StringBuilder("\n\n<color=#E8B04B>All your gems together</color>"); int num = 0; Effect[] all = Effects.All; foreach (Effect val in all) { float num2 = local[val]; float? num3 = settings.CapOf(val); if (!Effects.OnItem(val) && (num2 != 0f || num3.HasValue)) { stringBuilder.Append("\n ").Append(Effects.Format(val, num2)); if (num3.HasValue) { bool flag = Effects.Goodness(val, num2) >= num3.Value - 0.01f; stringBuilder.Append(flag ? $" <color=yellow>(cap {num3.Value:0.#}% reached)</color>" : $" (cap {num3.Value:0.#}%)"); } num++; } } if (num <= 0) { return ""; } return stringBuilder.ToString(); } private static string WithEnhanced(string tooltip, string token, float baseValue, float percent) { if (baseValue <= 0f || percent == 0f) { return tooltip; } string text = $"\n{token}: <color=orange>{baseValue}</color>"; float num = baseValue * Percent.Factor(percent); return tooltip.Replace(text, string.Format("{0} (<color={1}>{2:0.#}</color>)", text, "#E8B04B", num)); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class UpgradeKeepsGemPatch { private struct Carried { public Enhancement Enhancement; public Vector2i Position; public string Name; } private static readonly FieldRef<InventoryGui, ItemData> UpgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem"); private static void Prefix(InventoryGui __instance, out Carried? __state) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) ItemData val = UpgradeItem.Invoke(__instance); Enhancement enhancement = Enhancements.Of(val); __state = (((Enhancement)(ref enhancement)).IsEmpty ? ((Carried?)null) : new Carried?(new Carried { Enhancement = enhancement, Position = val.m_gridPos, Name = val.m_shared.m_name })); } private static void Postfix(Player player, Carried? __state) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!__state.HasValue || (Object)(object)player == (Object)null) { return; } Carried value = __state.Value; ItemData itemAt = ((Humanoid)player).GetInventory().GetItemAt(value.Position.x, value.Position.y); if (itemAt == null || !(itemAt.m_shared.m_name == value.Name)) { return; } Enhancement val = Enhancements.Of(itemAt); if (((Enhancement)(ref val)).IsEmpty) { bool num = itemAt.m_durability >= itemAt.GetMaxDurability() - 0.01f; Enhancements.Write(itemAt, value.Enhancement); if (num) { itemAt.m_durability = itemAt.GetMaxDurability(); } Plugin.Detail($"Kept {value.Enhancement} on upgraded {value.Name}"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentModifierPlusSE")] internal static class MovementTotalPatch { private static void Postfix(Player __instance, int index, ref float __result) { if (index == 0 && Enhancements.IsLocalPlayer((Character)(object)__instance)) { __result += Enhancements.Local[(Effect)5] / 100f; } } } }