Decompiled source of NokepArmorSets v1.0.0

plugins\JotunnModStub.dll

Decompiled a day ago
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("JotunnModStub")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("JotunnModStub")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.0.0")]
namespace JotunnModStub;

internal static class Armor
{
	public static void AddAll()
	{
		foreach (ArmorSet set in Plugin.Sets)
		{
			AddEffect(set);
			AddPart(set, set.HelmetPrefab, set.VanillaHelmet, set.BaseName + " шлем: " + set.DisplayName.ToLower(), set.CfgHelmet.Value, set.IconName("Helmet"));
			AddPart(set, set.ChestPrefab, set.VanillaChest, set.BaseName + " нагрудник: " + set.DisplayName.ToLower(), set.CfgChest.Value, set.IconName("Chest"));
			AddPart(set, set.LegsPrefab, set.VanillaLegs, set.BaseName + " штаны: " + set.DisplayName.ToLower(), set.CfgLegs.Value, set.IconName("Legs"));
		}
	}

	private static void AddEffect(ArmorSet set)
	{
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Expected O, but got Unknown
		SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>();
		((Object)val).name = set.EffectName;
		((StatusEffect)val).m_name = set.DisplayName;
		((StatusEffect)val).m_tooltip = BuildTooltip(set);
		if (set.Bonus == "Armored")
		{
			val.m_addArmor = set.CfgBonus.Value;
		}
		if (set.CfgSpeed != null && set.CfgSpeed.Value != 0f)
		{
			if (set.Bonus == "Stamina")
			{
				val.m_runStaminaDrainModifier = set.CfgSpeed.Value / 100f;
			}
			else
			{
				val.m_speedModifier = set.CfgSpeed.Value / 100f;
			}
		}
		set.Effect = val;
		set.EffectHash = ((StatusEffect)val).NameHash();
		ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)val, false));
	}

	private static string BuildTooltip(ArmorSet set)
	{
		float value = set.CfgBonus.Value;
		string text;
		switch (set.Bonus)
		{
		case "Vitality":
			text = $"+{value:0} к максимальному здоровью";
			break;
		case "Armored":
			text = $"+{value:0} к броне";
			break;
		case "Magic":
			text = $"+{value:0} к максимальному эйтру";
			break;
		case "Stamina":
			text = $"+{value:0} к максимальной выносливости";
			break;
		default:
			return "";
		}
		if (set.CfgSpeed != null && set.CfgSpeed.Value != 0f)
		{
			float value2 = set.CfgSpeed.Value;
			text = ((!(set.Bonus == "Stamina")) ? (text + $"\n{value2:+0;-0}% к скорости передвижения") : (text + $"\n{value2:+0;-0}% к расходу выносливости на бег"));
		}
		return text;
	}

	private static void AddPart(ArmorSet set, string prefabName, string vanillaPrefab, string displayName, string recipeFromConfig, string iconName)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		CustomItem val = new CustomItem(prefabName, vanillaPrefab);
		val.ItemDrop.m_itemData.m_shared.m_name = displayName;
		val.ItemDrop.m_itemData.m_shared.m_description = "Часть комплекта: " + set.DisplayName.ToLower() + ".";
		Sprite val2 = Icons.Get(iconName);
		if ((Object)(object)val2 != (Object)null)
		{
			val.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { val2 };
		}
		val.ItemDrop.m_itemData.m_shared.m_setName = set.SetName;
		val.ItemDrop.m_itemData.m_shared.m_setSize = 3;
		val.ItemDrop.m_itemData.m_shared.m_setStatusEffect = (StatusEffect)(object)set.Effect;
		if (!ItemManager.Instance.AddItem(val))
		{
			Logger.LogError((object)("Не удалось добавить " + prefabName));
		}
		else
		{
			Recipes.Add(set, prefabName, vanillaPrefab, recipeFromConfig);
		}
	}
}
internal static class Recipes
{
	private static readonly Dictionary<string, string> Sources = new Dictionary<string, string>();

	private static readonly Dictionary<string, Dictionary<string, int>> Extras = new Dictionary<string, Dictionary<string, int>>();

	public static void Add(ArmorSet set, string prefabName, string vanillaPrefab, string recipeFromConfig)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Expected O, but got Unknown
		RecipeConfig val = new RecipeConfig();
		val.Name = "Recipe_" + prefabName;
		val.Item = prefabName;
		val.CraftingStation = "piece_nokep_leatherbench";
		val.MinStationLevel = 1;
		Dictionary<string, int> dictionary = Utils.ParseRecipe(recipeFromConfig);
		if (dictionary.Count > 0)
		{
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				val.AddRequirement(item.Key, item.Value, 0);
			}
		}
		else
		{
			val.AddRequirement("Wood", 1, 0);
			Sources[prefabName] = vanillaPrefab;
			Dictionary<string, int> dictionary2 = Utils.ParseRecipe(set.CfgExtra.Value);
			if (dictionary2.Count > 0)
			{
				Extras[prefabName] = dictionary2;
			}
		}
		ItemManager.Instance.AddRecipe(new CustomRecipe(val));
	}

	public static void FillFromVanilla()
	{
		if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null)
		{
			return;
		}
		foreach (KeyValuePair<string, string> source in Sources)
		{
			Recipe val = Find(source.Key);
			Recipe val2 = Find(source.Value);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogWarning((object)("Не нашёл свой рецепт для " + source.Key));
				continue;
			}
			if ((Object)(object)val2 == (Object)null || val2.m_resources == null)
			{
				Logger.LogWarning((object)("Не нашёл ванильный рецепт " + source.Value));
				continue;
			}
			List<Requirement> list = new List<Requirement>(val2.m_resources);
			if (Extras.TryGetValue(source.Key, out var value))
			{
				AddExtras(list, value);
			}
			val.m_resources = list.ToArray();
			Logger.LogInfo((object)$"{source.Key}: {val.m_resources.Length} требований");
		}
	}

	private static void AddExtras(List<Requirement> list, Dictionary<string, int> extra)
	{
		//IL_005a: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		foreach (KeyValuePair<string, int> item in extra)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Key);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				Logger.LogWarning((object)("Не нашёл ресурс " + item.Key + " — проверь написание в настройках"));
				continue;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if (!((Object)(object)component == (Object)null))
			{
				list.Add(new Requirement
				{
					m_resItem = component,
					m_amount = item.Value,
					m_recover = true
				});
			}
		}
	}

	private static Recipe Find(string itemPrefabName)
	{
		foreach (Recipe recipe in ObjectDB.instance.m_recipes)
		{
			if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && ((Object)((Component)recipe.m_item).gameObject).name == itemPrefabName)
			{
				return recipe;
			}
		}
		return null;
	}
}
internal static class Table
{
	public const string PrefabName = "piece_nokep_leatherbench";

	public static void Add()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		PieceConfig val = new PieceConfig();
		val.Name = ModConfig.TableName.Value;
		val.Description = "Здесь шьют особую кожаную броню.";
		val.PieceTable = "Hammer";
		val.Category = "Crafting";
		foreach (KeyValuePair<string, int> item in Utils.ParseRecipe(ModConfig.TableRecipe.Value))
		{
			val.AddRequirement(item.Key, item.Value, true);
		}
		CustomPiece val2 = new CustomPiece("piece_nokep_leatherbench", "piece_workbench", val);
		CraftingStation component = val2.PiecePrefab.GetComponent<CraftingStation>();
		if ((Object)(object)component != (Object)null)
		{
			component.m_name = ModConfig.TableName.Value;
			component.m_craftRequireRoof = ModConfig.RequireRoof.Value;
			component.m_craftRequireFire = ModConfig.RequireFire.Value;
			component.m_showBasicRecipies = false;
		}
		else
		{
			Logger.LogError((object)"На верстаке нет компонента CraftingStation");
		}
		PieceManager.Instance.AddPiece(val2);
	}
}
internal class ArmorSet
{
	public string Id;

	public string DisplayName;

	public string BaseName;

	public string Bonus;

	public string VanillaHelmet;

	public string VanillaChest;

	public string VanillaLegs;

	public string IconFolder = "";

	public string IconPrefix = "";

	public string EffectName;

	public int EffectHash;

	public SE_Stats Effect;

	public ConfigEntry<float> CfgBonus;

	public ConfigEntry<float> CfgSpeed;

	public ConfigEntry<string> CfgExtra;

	public ConfigEntry<string> CfgHelmet;

	public ConfigEntry<string> CfgChest;

	public ConfigEntry<string> CfgLegs;

	public string HelmetPrefab => "Nokep_Helmet_" + Id;

	public string ChestPrefab => "Nokep_Chest_" + Id;

	public string LegsPrefab => "Nokep_Legs_" + Id;

	public string SetName => "Nokep_Set_" + Id;

	public string IconName(string part)
	{
		string text = (string.IsNullOrEmpty(IconPrefix) ? (Bonus + "_" + part) : (IconPrefix + "_" + Bonus + "_" + part));
		if (!string.IsNullOrEmpty(IconFolder))
		{
			return IconFolder + "/" + text;
		}
		return text;
	}
}
internal static class Icons
{
	private static readonly Dictionary<string, Sprite> cache = new Dictionary<string, Sprite>();

	public static Sprite Get(string name)
	{
		if (cache.TryGetValue(name, out var value))
		{
			return value;
		}
		Sprite val = Load(name);
		if ((Object)(object)val == (Object)null)
		{
			Logger.LogWarning((object)("Иконка " + name + " не загрузилась"));
		}
		cache[name] = val;
		return val;
	}

	private static Sprite Load(string name)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		Assembly executingAssembly = Assembly.GetExecutingAssembly();
		string text = "NokepArmorSets.Assets." + name.Replace("/", ".") + ".png";
		using Stream stream = executingAssembly.GetManifestResourceStream(text);
		if (stream == null)
		{
			Logger.LogWarning((object)("Не нашёл ресурс " + text));
			return null;
		}
		byte[] array = new byte[stream.Length];
		stream.Read(array, 0, array.Length);
		Texture2D val = AssetUtils.LoadImage(array);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
	}

	public static void LogResourceNames()
	{
		string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
		Logger.LogInfo((object)("Встроенные ресурсы: " + string.Join(", ", manifestResourceNames)));
	}
}
internal static class ModConfig
{
	public static ConfigEntry<string> TableName;

	public static ConfigEntry<string> TableRecipe;

	public static ConfigEntry<bool> RequireRoof;

	public static ConfigEntry<bool> RequireFire;

	private static ConfigFile file;

	public static void Bind(ConfigFile config)
	{
		file = config;
		TableName = config.Bind<string>("0. Верстак", "Название", "Верстак скорняка", "Как называется верстак в игре. Применяется после перезапуска.");
		TableRecipe = config.Bind<string>("0. Верстак", "Рецепт", "Wood:10", "Из чего строится верстак. Формат: Предмет:Количество, через запятую.");
		RequireRoof = config.Bind<bool>("0. Верстак", "Нужна крыша", true, "Требовать крышу для работы верстака.");
		RequireFire = config.Bind<bool>("0. Верстак", "Нужен огонь", false, "Требовать огонь рядом для работы верстака.");
		BindSet("Vitality", "1. Луга — живучесть", 15f, 0f, "BoneFragments:8, LeatherScraps:6");
		BindSet("Armored", "1. Луга — прочность", 3f, 0f, "Flint:8, LeatherScraps:6");
		BindSet("Magic", "1. Луга — магия", 10f, 0f, "Feathers:10, Wood:10");
		BindSet("Stamina", "1. Луга — выносливость", 15f, 0f, "Resin:10, Wood:10");
		BindSet("Troll_Vitality", "2. Тролль — живучесть", 25f, 5f, "TrollHide:2, RoundLog:15, Resin:10");
		BindSet("Troll_Armored", "2. Тролль — прочность", 5f, 0f, "TrollHide:5, FineWood:10");
		BindSet("Troll_Magic", "2. Тролль — магия", 25f, 0f, "TrollHide:2, GreydwarfEye:20, Resin:10");
		BindSet("Troll_Stamina", "2. Тролль — выносливость", 25f, -10f, "TrollHide:2, Thistle:10, FineWood:10");
		BindSet("Bronze_Vitality", "3. Бронза — живучесть", 35f, 0f, "Bronze:2, Copper:5, RoundLog:15");
		BindSet("Bronze_Armored", "3. Бронза — прочность", 8f, -5f, "Bronze:6, Coal:10");
		BindSet("Bronze_Magic", "3. Бронза — магия", 20f, 0f, "Bronze:2, SurtlingCore:5, Coal:10");
		BindSet("Bronze_Stamina", "3. Бронза — выносливость", 25f, 0f, "Bronze:2, Tin:5, RoundLog:15");
	}

	private static void BindSet(string setId, string section, float bonus, float speed, string extraDefault)
	{
		ArmorSet armorSet = Plugin.Sets.Find((ArmorSet s) => s.Id == setId);
		if (armorSet == null)
		{
			Logger.LogError((object)("Нет комплекта " + setId + " — настройки не привязаны"));
			return;
		}
		armorSet.CfgBonus = file.Bind<float>(section, "Бонус", bonus, BonusHint(armorSet.Bonus));
		armorSet.CfgSpeed = file.Bind<float>(section, "Доп. бонус", speed, (armorSet.Bonus == "Stamina") ? "Изменение расхода выносливости на бег, в процентах. Минус — экономия." : "Изменение скорости передвижения, в процентах. 0 — без изменений.");
		armorSet.CfgExtra = file.Bind<string>(section, "Доп. ресурс", extraDefault, "Что добавляется к ванильному рецепту каждой вещи. Формат: Предмет:Количество. Пусто — ничего не добавлять.");
		armorSet.CfgHelmet = file.Bind<string>(section, "Рецепт шлема", "", "Свой рецепт вместо ванильного. Формат: Предмет:Количество, через запятую. Пусто — ванильный рецепт плюс доп. ресурс.");
		armorSet.CfgChest = file.Bind<string>(section, "Рецепт нагрудника", "", "Свой рецепт вместо ванильного. Формат: Предмет:Количество, через запятую. Пусто — ванильный рецепт плюс доп. ресурс.");
		armorSet.CfgLegs = file.Bind<string>(section, "Рецепт штанов", "", "Свой рецепт вместо ванильного. Формат: Предмет:Количество, через запятую. Пусто — ванильный рецепт плюс доп. ресурс.");
	}

	private static string BonusHint(string bonus)
	{
		return bonus switch
		{
			"Vitality" => "Сколько максимального здоровья даёт полный комплект.", 
			"Armored" => "Сколько брони даёт полный комплект.", 
			"Magic" => "Сколько максимального эйтра даёт полный комплект.", 
			"Stamina" => "Сколько максимальной выносливости даёт полный комплект.", 
			_ => "", 
		};
	}
}
[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
internal static class FoodValuePatch
{
	private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		SEMan sEMan = ((Character)__instance).GetSEMan();
		if (sEMan == null)
		{
			return;
		}
		foreach (ArmorSet set in Plugin.Sets)
		{
			if (!((Object)(object)set.Effect == (Object)null) && sEMan.HaveStatusEffect(set.EffectHash))
			{
				float value = set.CfgBonus.Value;
				switch (set.Bonus)
				{
				case "Vitality":
					hp += value;
					break;
				case "Stamina":
					stamina += value;
					break;
				case "Magic":
					eitr += value;
					break;
				}
			}
		}
	}
}
[BepInPlugin("nokep.valheim.armorsets", "NokepArmorSets", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal class Plugin : BaseUnityPlugin
{
	public const string PluginGUID = "nokep.valheim.armorsets";

	public const string PluginName = "NokepArmorSets";

	public const string PluginVersion = "0.3.0";

	public static readonly List<ArmorSet> Sets = new List<ArmorSet>();

	private Harmony harmony;

	private void Awake()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		Sets.AddRange(Meadows.GetSets());
		Sets.AddRange(BlackForest.GetSets());
		ModConfig.Bind(((BaseUnityPlugin)this).Config);
		harmony = new Harmony("nokep.valheim.armorsets");
		harmony.PatchAll();
		PrefabManager.OnVanillaPrefabsAvailable += AddContent;
		ItemManager.OnItemsRegistered += Recipes.FillFromVanilla;
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	private void AddContent()
	{
		Table.Add();
		Armor.AddAll();
		PrefabManager.OnVanillaPrefabsAvailable -= AddContent;
	}
}
internal static class BlackForest
{
	public const string IconFolder = "BlackForest";

	public static List<ArmorSet> GetSets()
	{
		return new List<ArmorSet>
		{
			Troll("Vitality", "Живучесть"),
			Troll("Armored", "Прочность"),
			Troll("Magic", "Магия"),
			Troll("Stamina", "Выносливость"),
			Bronze("Vitality", "Живучесть"),
			Bronze("Armored", "Прочность"),
			Bronze("Magic", "Магия"),
			Bronze("Stamina", "Выносливость")
		};
	}

	private static ArmorSet Troll(string bonus, string displayName)
	{
		return new ArmorSet
		{
			Id = "Troll_" + bonus,
			Bonus = bonus,
			DisplayName = displayName,
			BaseName = "Тролльий",
			VanillaHelmet = "HelmetTrollLeather",
			VanillaChest = "ArmorTrollLeatherChest",
			VanillaLegs = "ArmorTrollLeatherLegs",
			IconFolder = "BlackForest",
			IconPrefix = "Troll",
			EffectName = "Nokep_SetEffect_Troll_" + bonus
		};
	}

	private static ArmorSet Bronze(string bonus, string displayName)
	{
		return new ArmorSet
		{
			Id = "Bronze_" + bonus,
			Bonus = bonus,
			DisplayName = displayName,
			BaseName = "Бронзовый",
			VanillaHelmet = "HelmetBronze",
			VanillaChest = "ArmorBronzeChest",
			VanillaLegs = "ArmorBronzeLegs",
			IconFolder = "BlackForest",
			IconPrefix = "Bronze",
			EffectName = "Nokep_SetEffect_Bronze_" + bonus
		};
	}
}
internal static class Meadows
{
	private const string Helmet = "HelmetLeather";

	private const string Chest = "ArmorLeatherChest";

	private const string Legs = "ArmorLeatherLegs";

	public static List<ArmorSet> GetSets()
	{
		return new List<ArmorSet>
		{
			Make("Vitality", "Живучесть"),
			Make("Armored", "Прочность"),
			Make("Magic", "Магия"),
			Make("Stamina", "Выносливость")
		};
	}

	private static ArmorSet Make(string bonus, string displayName)
	{
		return new ArmorSet
		{
			Id = bonus,
			Bonus = bonus,
			DisplayName = displayName,
			BaseName = "Кожаный",
			VanillaHelmet = "HelmetLeather",
			VanillaChest = "ArmorLeatherChest",
			VanillaLegs = "ArmorLeatherLegs",
			EffectName = "Nokep_SetEffect_" + bonus
		};
	}
}
internal static class Utils
{
	public static Dictionary<string, int> ParseRecipe(string text)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		if (string.IsNullOrEmpty(text))
		{
			return dictionary;
		}
		string[] array = text.Split(new char[1] { ',' });
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Trim().Split(new char[1] { ':' });
			if (array2.Length == 2)
			{
				string text2 = array2[0].Trim();
				if (text2.Length != 0 && int.TryParse(array2[1].Trim(), out var result) && result >= 1)
				{
					dictionary[text2] = result;
				}
			}
		}
		return dictionary;
	}
}