Decompiled source of MasterRings v1.2.1

MasterRings.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace GoblinHeim.MasterRings;

internal sealed class MasterRingRuntimeCache : MonoBehaviour
{
	internal bool KindInitialized;

	internal bool Greydwarf;

	internal bool Skeleton;

	internal float BoundValidUntil;

	internal bool Bound;

	internal float AuraValidUntil;

	internal bool Aura;

	internal float LichRingValidUntil;

	internal bool LichRing;
}
public class SE_MasterRingBiome : StatusEffect
{
	public override void ModifyRunStaminaDrain(float baseDrain, ref float drain, Vector3 dir)
	{
		drain *= 0.9f;
		float finalCost = drain;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Run", baseDrain, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifyJumpStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Jump", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifyAttackStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Attack", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifyBlockStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Block", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifyDodgeStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Dodge", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifySwimStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Swim", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifyHomeItemStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("HomeItem", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}

	public override void ModifySneakStaminaUsage(float baseStaminaUse, ref float staminaUse)
	{
		staminaUse *= 0.9f;
		float finalCost = staminaUse;
		Character character = base.m_character;
		StaminaDiagnostics.Log("Sneak", baseStaminaUse, finalCost, (Player)(object)((character is Player) ? character : null));
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[BepInPlugin("goblinheim.masterrings", "Master Rings", "1.2.1")]
public class MasterRingsPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "goblinheim.masterrings";

	public const string PluginName = "Master Rings";

	public const string PluginVersion = "1.2.1";

	internal const string Meadows = "MR_MeadowsLordRing";

	internal const string Sylvian = "MR_SylvianRing";

	internal const string Dreadful = "MR_DreadfulRing";

	internal const string Wind = "MR_WindMasterRing";

	internal const string Lich = "MR_LichKingRing";

	internal const string BoundSkeletonZdoKey = "MR_BoundSkeleton";

	internal const string BoundSkeletonExpiryZdoKey = "MR_BoundSkeletonExpiry";

	internal const string LichSkeletonZdoKey = "MR_LichSkeleton";

	internal const string LichSkeletonDamageZdoKey = "MR_LichSkeletonDamage";

	internal const string SylvianAuraZdoKey = "MR_SylvianAura";

	internal const string LichEquippedZdoKey = "MR_LichEquipped";

	internal static readonly HashSet<string> MasterRingPrefabs = new HashSet<string>(StringComparer.Ordinal) { "MR_MeadowsLordRing", "MR_SylvianRing", "MR_DreadfulRing", "MR_WindMasterRing", "MR_LichKingRing" };

	internal static MasterRingsPlugin Instance;

	internal static readonly Dictionary<int, float> BoundSkeletons = new Dictionary<int, float>();

	internal static readonly Dictionary<int, Character> BoundSkeletonCharacters = new Dictionary<int, Character>();

	private static readonly Dictionary<string, Sprite> SpriteCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

	private static Player cachedLocalPlayer;

	private static string cachedLocalRing;

	private static bool localRingCacheValid;

	private static bool cachedLocalConstructedOrPath;

	private static string cachedLocalSurface = "Unknown";

	private static string appliedLanguage;

	private float nextSkeletonScan;

	private float nextBoundExpiryScan;

	private float nextBoundDiscoveryScan;

	private float nextBiomeEffectCheck;

	private float nextExclusivityCheck;

	private float nextNecromancyCleanup;

	internal static readonly Dictionary<string, StatusEffect> BiomeEffects = new Dictionary<string, StatusEffect>();

	internal static bool DiagnosticsEnabled = true;

	private static readonly FieldInfo CharacterNViewField = AccessTools.Field(typeof(Character), "m_nview");

	private static Type cachedViewType;

	private static MethodInfo getZdoMethod;

	private static Type cachedZdoType;

	private static MethodInfo zdoSetBool;

	private static MethodInfo zdoSetLong;

	private static MethodInfo zdoSetFloat;

	private static MethodInfo zdoGetBool;

	private static MethodInfo zdoGetLong;

	private static MethodInfo zdoGetFloat;

	private static readonly Dictionary<string, string> French = new Dictionary<string, string>
	{
		{ "mr_meadows_name", "Anneau du Seigneur des Prairies" },
		{ "mr_meadows_item", "Il régnait sans partage sur la Prairie" },
		{ "mr_meadows_effect_name", "Seigneur des Prairies" },
		{ "mr_meadows_effect", "Bonus actifs dans la Prairie:\n+10% de vitesse\n-10% de consommation d'endurance\n+20% de dégâts aux animaux\n+20 à la fabrication" },
		{ "mr_sylvian_name", "Anneau Sylvestre" },
		{ "mr_sylvian_item", "La forêt refleurira" },
		{ "mr_sylvian_effect_name", "Forêt noire" },
		{ "mr_sylvian_effect", "Bonus actifs dans la Forêt noire:\n+10% de vitesse\n-10% de consommation d'endurance\n+20 à l'agriculture" },
		{ "mr_sylvian_perm_name", "Anneau Sylvestre" },
		{ "mr_sylvian_perm", "Vous faites parti de la forêt." },
		{ "mr_dread_name", "Anneau d'Effroi" },
		{ "mr_dread_item", "Un royaume de vase et de boue" },
		{ "mr_dread_effect_name", "Marais" },
		{ "mr_dread_effect", "Bonus actifs dans les Marais:\n+10% de vitesse\n-10% de consommation d'endurance" },
		{ "mr_dread_perm_name", "Anneau d'Effroi" },
		{ "mr_dread_perm", "Insensible à l'humidité\nNécromancien" },
		{ "mr_wind_name", "Anneau du Maître des Vents" },
		{ "mr_wind_item", "Le dernier souffle de la Reine des Dragons" },
		{ "mr_wind_effect_name", "Montagne" },
		{ "mr_wind_effect", "Bonus actifs dans la Montagne:\n+10% de vitesse\n-10% de consommation d'endurance" },
		{ "mr_wind_perm_name", "Maître des Vents" },
		{ "mr_wind_perm", "Le vent arrive toujours en poupe quand vous naviguez" },
		{ "mr_lich_name", "Anneau du Roi-Liche" },
		{ "mr_lich_item", "Le vent souffle sur les plaines" },
		{ "mr_lich_perm_name", "Anneau du Roi-Liche" },
		{ "mr_lich_perm", "Très résistant au feu\nNécromancien" },
		{ "mr_lich_effect_name", "Plaines" },
		{ "mr_lich_effect", "Bonus actifs dans les plaines :\n+10% de vitesse\n-10% de consommation d'endurance\nInsensible au ralentissement du goudron" }
	};

	private static readonly Dictionary<string, string> English = new Dictionary<string, string>
	{
		{ "mr_meadows_name", "Meadows Lord Ring" },
		{ "mr_meadows_item", "He ruled the Meadows without equal" },
		{ "mr_meadows_effect_name", "Lord of the Meadows" },
		{ "mr_meadows_effect", "Active bonuses in the Meadows:\n+10% movement speed\n-10% stamina consumption\n+20% damage to animals\n+20 Crafting" },
		{ "mr_sylvian_name", "Sylvian Ring" },
		{ "mr_sylvian_item", "The forest will bloom again" },
		{ "mr_sylvian_effect_name", "Black Forest" },
		{ "mr_sylvian_effect", "Active bonuses in the Black Forest:\n+10% movement speed\n-10% stamina consumption\n+20 Farming" },
		{ "mr_sylvian_perm_name", "Sylvian Ring" },
		{ "mr_sylvian_perm", "You are part of the forest." },
		{ "mr_dread_name", "Dreadful Ring" },
		{ "mr_dread_item", "A kingdom of slime and mud" },
		{ "mr_dread_effect_name", "Swamp" },
		{ "mr_dread_effect", "Active bonuses in the Swamp:\n+10% movement speed\n-10% stamina consumption" },
		{ "mr_dread_perm_name", "Dreadful Ring" },
		{ "mr_dread_perm", "Unaffected by wetness\nNecromancer" },
		{ "mr_wind_name", "Wind Master Ring" },
		{ "mr_wind_item", "The Dragon Queen's last breath" },
		{ "mr_wind_effect_name", "Mountain" },
		{ "mr_wind_effect", "Active bonuses in the Mountains:\n+10% movement speed\n-10% stamina consumption" },
		{ "mr_wind_perm_name", "Master of Winds" },
		{ "mr_wind_perm", "The wind is always at your back when sailing" },
		{ "mr_lich_name", "Lich King Ring" },
		{ "mr_lich_item", "The wind blows across the plains" },
		{ "mr_lich_perm_name", "Lich King Ring" },
		{ "mr_lich_perm", "Very resistant to fire\nNecromancer" },
		{ "mr_lich_effect_name", "Plains" },
		{ "mr_lich_effect", "Active bonuses in the Plains:\n+10% movement speed\n-10% stamina consumption\nImmune to tar slowdown" }
	};

	private void Awake()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		Instance = this;
		DiagnosticsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Enabled", false, "Enable detailed diagnostic messages for troubleshooting.").Value;
		PrefabManager.OnVanillaPrefabsAvailable += RegisterRings;
		Harmony val = new Harmony("goblinheim.masterrings");
		val.PatchAll();
		DreadfulWetImmunityPatch.Install(val);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Master Rings 1.2.1 loaded");
	}

	internal static void DiagnosticLog(string message)
	{
		if ((DiagnosticsEnabled || message == null || !message.StartsWith("[DIAG]", StringComparison.Ordinal)) && (Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
		}
	}

	private void OnDestroy()
	{
		PrefabManager.OnVanillaPrefabsAvailable -= RegisterRings;
	}

	private void RegisterRings()
	{
		//IL_003e: 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_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		//IL_0078: Expected O, but got Unknown
		//IL_0078: Expected O, but got Unknown
		//IL_0078: Expected O, but got Unknown
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: 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_00df: Expected O, but got Unknown
		//IL_00df: Expected O, but got Unknown
		//IL_00df: Expected O, but got Unknown
		//IL_00df: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Expected O, but got Unknown
		//IL_0149: Expected O, but got Unknown
		//IL_0149: Expected O, but got Unknown
		//IL_0149: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Expected O, but got Unknown
		//IL_01a3: Expected O, but got Unknown
		//IL_01a3: Expected O, but got Unknown
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Expected O, but got Unknown
		//IL_0209: Expected O, but got Unknown
		//IL_0209: Expected O, but got Unknown
		//IL_0209: Expected O, but got Unknown
		PrefabManager.OnVanillaPrefabsAvailable -= RegisterRings;
		try
		{
			CreateRing("MR_MeadowsLordRing", "MeadowsLordRing.png", "MeadowsEffect.png", "$mr_meadows_name", "$mr_meadows_item", "$mr_meadows_effect_name", "$mr_meadows_effect", 1, new RequirementConfig("TrophyEikthyr", 1, 0, true), new RequirementConfig("Tin", 4, 0, true), new RequirementConfig("Copper", 2, 0, true), new RequirementConfig("Amber", 2, 0, true));
			CreateRing("MR_SylvianRing", "SylvianRing.png", "BlackForestEffect.png", "$mr_sylvian_name", "$mr_sylvian_item", "$mr_sylvian_effect_name", "$mr_sylvian_effect", 2, new RequirementConfig("TrophyTheElder", 1, 0, true), new RequirementConfig("Root", 4, 0, true), new RequirementConfig("Thistle", 1, 0, true), new RequirementConfig("Acorn", 4, 0, true));
			CreateRing("MR_DreadfulRing", "DreadfulRing.png", "SwampEffect.png", "$mr_dread_name", "$mr_dread_item", "$mr_dread_effect_name", "$mr_dread_effect", 3, new RequirementConfig("TrophyBonemass", 1, 0, true), new RequirementConfig("Ruby", 4, 0, true), new RequirementConfig("Obsidian", 10, 0, true), new RequirementConfig("BoneFragments", 10, 0, true), (DamageType)256);
			CreateRing("MR_WindMasterRing", "WindMasterRing.png", "MountainEffect.png", "$mr_wind_name", "$mr_wind_item", "$mr_wind_effect_name", "$mr_wind_effect", 4, new RequirementConfig("TrophyDragonQueen", 1, 0, true), new RequirementConfig("AmberPearl", 1, 0, true), new RequirementConfig("SerpentScale", 12, 0, true), null, (DamageType)64);
			CreateRing("MR_LichKingRing", "LichKingRing.png", "PlainsEffect.png", "$mr_lich_name", "$mr_lich_item", "$mr_lich_effect_name", "$mr_lich_effect", 5, new RequirementConfig("TrophyGoblinKing", 1, 0, true), new RequirementConfig("GoblinTotem", 1, 0, true), new RequirementConfig("BlackMarble", 10, 0, true), new RequirementConfig("Wisp", 4, 0, true), (DamageType)32);
			ApplyLocalization();
			LogRegistrationDiagnostics();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"All five Master Rings registered. Recipe IDs: TrophyGoblinKing, GoblinTotem, BlackMarble, Wisp; Lich Workbench level 5.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
	}

	private void LogRegistrationDiagnostics()
	{
		if (!((Object)(object)ZNetScene.instance == (Object)null))
		{
			GameObject prefab = ZNetScene.instance.GetPrefab("AmberPearl");
			ItemDrop val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<ItemDrop>());
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Trade invariant: vanilla AmberPearl value=" + (((Object)(object)val == (Object)null) ? "missing" : val.m_itemData.m_shared.m_value.ToString())));
			string[] array = new string[5] { "MR_MeadowsLordRing", "MR_SylvianRing", "MR_DreadfulRing", "MR_WindMasterRing", "MR_LichKingRing" };
			foreach (string text in array)
			{
				GameObject prefab2 = ZNetScene.instance.GetPrefab(text);
				ItemDrop val2 = (((Object)(object)prefab2 == (Object)null) ? null : prefab2.GetComponent<ItemDrop>());
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Trade invariant: " + text + " value=" + (((Object)(object)val2 == (Object)null) ? "missing" : val2.m_itemData.m_shared.m_value.ToString())));
			}
			string[] array2 = new string[5] { "TrophyGoblinKing", "GoblinTotem", "BlackMarble", "Wisp", "Skeleton" };
			foreach (string text2 in array2)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Prefab check: " + text2 + "=" + (((Object)(object)ZNetScene.instance.GetPrefab(text2) == (Object)null) ? "MISSING" : "OK")));
			}
		}
	}

	private void CreateRing(string prefabName, string iconFile, string effectIconFile, string name, string desc, string effectName, string effectDesc, int stationLevel, RequirementConfig r1, RequirementConfig r2, RequirementConfig r3, RequirementConfig r4 = null, DamageType? resistance = null)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Expected O, but got Unknown
		//IL_0337: Unknown result type (might be due to invalid IL or missing references)
		//IL_0341: Expected O, but got Unknown
		//IL_0391: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f0: Expected O, but got Unknown
		//IL_0437: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Expected O, but got Unknown
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_028a: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Unknown result type (might be due to invalid IL or missing references)
		//IL_030c: Expected O, but got Unknown
		//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, "AmberPearl");
		ItemDrop component = val.GetComponent<ItemDrop>();
		MethodInfo method = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);
		component.m_itemData.m_shared = (SharedData)method.Invoke(component.m_itemData.m_shared, null);
		component.m_itemData.m_shared.m_name = name;
		component.m_itemData.m_shared.m_description = desc;
		component.m_itemData.m_shared.m_itemType = (ItemType)18;
		component.m_itemData.m_shared.m_weight = 0.1f;
		component.m_itemData.m_shared.m_maxStackSize = 1;
		component.m_itemData.m_shared.m_value = 0;
		Sprite val2 = LoadEmbeddedIcon(iconFile);
		if ((Object)(object)val2 != (Object)null)
		{
			component.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { val2 };
		}
		StatusEffect val3 = (StatusEffect)(object)ScriptableObject.CreateInstance<SE_MasterRingBiome>();
		((Object)val3).name = "SE_" + prefabName + "_Biome";
		val3.m_name = effectName;
		val3.m_tooltip = effectDesc;
		Sprite val4 = LoadEmbeddedIcon(effectIconFile);
		val3.m_icon = (((Object)(object)val4 != (Object)null) ? val4 : val2);
		CustomStatusEffect val5 = new CustomStatusEffect(val3, false);
		ItemManager.Instance.AddStatusEffect(val5);
		BiomeEffects[prefabName] = val5.StatusEffect;
		switch (prefabName)
		{
		case "MR_SylvianRing":
		case "MR_DreadfulRing":
		case "MR_WindMasterRing":
		case "MR_LichKingRing":
		{
			SE_Stats val6 = ScriptableObject.CreateInstance<SE_Stats>();
			((Object)val6).name = "SE_" + prefabName + "_Permanent";
			((StatusEffect)val6).m_name = prefabName switch
			{
				"MR_WindMasterRing" => "$mr_wind_perm_name", 
				"MR_DreadfulRing" => "$mr_dread_perm_name", 
				"MR_SylvianRing" => "$mr_sylvian_perm_name", 
				_ => "$mr_lich_perm_name", 
			};
			((StatusEffect)val6).m_tooltip = prefabName switch
			{
				"MR_WindMasterRing" => "$mr_wind_perm", 
				"MR_DreadfulRing" => "$mr_dread_perm", 
				"MR_SylvianRing" => "$mr_sylvian_perm", 
				_ => "$mr_lich_perm", 
			};
			((StatusEffect)val6).m_icon = val2;
			val6.m_mods = new List<DamageModPair>();
			switch (prefabName)
			{
			case "MR_DreadfulRing":
				val6.m_mods.Add(new DamageModPair
				{
					m_type = (DamageType)256,
					m_modifier = (DamageModifier)5
				});
				break;
			case "MR_WindMasterRing":
				val6.m_mods.Add(new DamageModPair
				{
					m_type = (DamageType)64,
					m_modifier = (DamageModifier)5
				});
				break;
			case "MR_LichKingRing":
				val6.m_mods.Add(new DamageModPair
				{
					m_type = (DamageType)32,
					m_modifier = (DamageModifier)5
				});
				break;
			}
			CustomStatusEffect val7 = new CustomStatusEffect((StatusEffect)(object)val6, false);
			ItemManager.Instance.AddStatusEffect(val7);
			component.m_itemData.m_shared.m_equipStatusEffect = val7.StatusEffect;
			break;
		}
		}
		ItemManager.Instance.AddItem(new CustomItem(val, false));
		DiagnosticLog(string.Concat("MasterRing item registered: ", prefabName, ", value=", component.m_itemData.m_shared.m_value, ", type=", component.m_itemData.m_shared.m_itemType, ", world model source=AmberPearl"));
		List<RequirementConfig> list = new List<RequirementConfig>();
		list.Add(r1);
		list.Add(r2);
		list.Add(r3);
		List<RequirementConfig> list2 = list;
		if (r4 != null)
		{
			list2.Add(r4);
		}
		ItemManager instance = ItemManager.Instance;
		RecipeConfig val8 = new RecipeConfig();
		val8.Name = "Recipe_" + prefabName;
		val8.Item = prefabName;
		val8.Amount = 1;
		val8.CraftingStation = "piece_workbench";
		val8.MinStationLevel = stationLevel;
		val8.Requirements = list2.ToArray();
		instance.AddRecipe(new CustomRecipe(val8));
	}

	private Sprite LoadEmbeddedIcon(string file)
	{
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Expected O, but got Unknown
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		if (Application.isBatchMode)
		{
			return null;
		}
		if (SpriteCache.TryGetValue(file, out var value))
		{
			return value;
		}
		string value2 = ".icons." + file;
		string text = null;
		string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
		foreach (string text2 in manifestResourceNames)
		{
			if (text2.EndsWith(value2, StringComparison.OrdinalIgnoreCase))
			{
				text = text2;
				break;
			}
		}
		if (text == null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Missing embedded icon: " + file));
			return null;
		}
		using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
		using MemoryStream memoryStream = new MemoryStream();
		stream.CopyTo(memoryStream);
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		ImageConversion.LoadImage(val, memoryStream.ToArray(), true);
		((Object)val).name = file;
		((Texture)val).filterMode = (FilterMode)(!file.EndsWith("Effect.png", StringComparison.OrdinalIgnoreCase));
		Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		SpriteCache[file] = val2;
		return val2;
	}

	internal static string PrefabNameOf(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return string.Empty;
		}
		string text = ((Object)go).name ?? string.Empty;
		if (text.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - "(Clone)".Length);
		}
		return text;
	}

	internal static void InvalidateLocalEquipmentCache(Player p)
	{
		if ((Object)(object)p == (Object)null || (Object)(object)p == (Object)(object)Player.m_localPlayer)
		{
			localRingCacheValid = false;
		}
	}

	internal static string EquippedMasterRing(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return null;
		}
		if ((Object)(object)p != (Object)(object)Player.m_localPlayer)
		{
			return RingPrefabOf(MasterRingExclusivity.FindEquippedRing(p));
		}
		if (!localRingCacheValid || (Object)(object)cachedLocalPlayer != (Object)(object)p)
		{
			cachedLocalPlayer = p;
			cachedLocalRing = RingPrefabOf(MasterRingExclusivity.FindEquippedRing(p));
			localRingCacheValid = true;
		}
		return cachedLocalRing;
	}

	internal static bool HasRing(Player p, string prefab)
	{
		return string.Equals(EquippedMasterRing(p), prefab, StringComparison.Ordinal);
	}

	internal static string RingPrefabOf(ItemData item)
	{
		if (item != null && !((Object)(object)item.m_dropPrefab == (Object)null))
		{
			return PrefabNameOf(item.m_dropPrefab);
		}
		return string.Empty;
	}

	internal static bool IsMasterRing(ItemData item)
	{
		return MasterRingPrefabs.Contains(RingPrefabOf(item));
	}

	internal static Biome Biome(Player p)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)p == (Object)null))
		{
			return p.GetCurrentBiome();
		}
		return (Biome)0;
	}

	internal static bool CorrectBiome(Player p, string ring)
	{
		//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_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Invalid comparison between Unknown and I4
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Invalid comparison between Unknown and I4
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Invalid comparison between Unknown and I4
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Invalid comparison between Unknown and I4
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Invalid comparison between Unknown and I4
		Biome val = Biome(p);
		if ((!(ring == "MR_MeadowsLordRing") || (int)val != 1) && (!(ring == "MR_SylvianRing") || (int)val != 8) && (!(ring == "MR_DreadfulRing") || (int)val != 2) && (!(ring == "MR_WindMasterRing") || (int)val != 4))
		{
			if (ring == "MR_LichKingRing")
			{
				return (int)val == 16;
			}
			return false;
		}
		return true;
	}

	internal static string EquippedBiomeRing(Player p)
	{
		string text = EquippedMasterRing(p);
		if (text == null || !CorrectBiome(p, text))
		{
			return null;
		}
		return text;
	}

	internal static bool OnConstructedOrPath(Player p)
	{
		if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
		{
			return cachedLocalConstructedOrPath;
		}
		return ComputeConstructedOrPath(p);
	}

	private static bool ComputeConstructedOrPath(Player p)
	{
		string surface;
		return ComputeConstructedOrPath(p, out surface);
	}

	private static bool ComputeConstructedOrPath(Player p, out string surface)
	{
		//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_0034: 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_0043: 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_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		surface = "Unknown";
		if ((Object)(object)p == (Object)null)
		{
			return false;
		}
		Collider val = ((Character)p).GetLastGroundCollider();
		Vector3 val2 = ((Component)p).transform.position;
		RaycastHit val3 = default(RaycastHit);
		if ((Object)(object)val == (Object)null && Physics.Raycast(((Component)p).transform.position + Vector3.up * 0.4f, Vector3.down, ref val3, 1.4f, -5, (QueryTriggerInteraction)1))
		{
			val = ((RaycastHit)(ref val3)).collider;
			val2 = ((RaycastHit)(ref val3)).point;
		}
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Piece componentInParent = ((Component)val).GetComponentInParent<Piece>();
		if ((Object)(object)componentInParent != (Object)null)
		{
			surface = "Built:" + PrefabNameOf(((Component)componentInParent).gameObject);
			return true;
		}
		Heightmap val4 = ((Component)val).GetComponent<Heightmap>();
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = ((Component)val).GetComponentInParent<Heightmap>();
		}
		if ((Object)(object)val4 == (Object)null)
		{
			surface = "Natural:" + ((Object)val).name;
			return false;
		}
		float num = 0f;
		float num2 = 0f;
		int num3 = 0;
		for (int i = -1; i <= 1; i++)
		{
			for (int j = -1; j <= 1; j++)
			{
				Color paintMask = val4.GetPaintMask(val2 + new Vector3((float)j, 0f, (float)i));
				num += paintMask.r;
				num2 += paintMask.b;
				num3++;
			}
		}
		num /= (float)num3;
		num2 /= (float)num3;
		if (num2 > 0.4f)
		{
			surface = "Paved";
			return true;
		}
		if (num > 0.4f)
		{
			surface = "DirtPath";
			return true;
		}
		surface = "Natural";
		return false;
	}

	private static MasterRingRuntimeCache CacheOf(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return null;
		}
		MasterRingRuntimeCache masterRingRuntimeCache = ((Component)c).GetComponent<MasterRingRuntimeCache>();
		if ((Object)(object)masterRingRuntimeCache == (Object)null)
		{
			masterRingRuntimeCache = ((Component)c).gameObject.AddComponent<MasterRingRuntimeCache>();
		}
		if (!masterRingRuntimeCache.KindInitialized)
		{
			string text = PrefabNameOf(((Component)c).gameObject).ToLowerInvariant();
			masterRingRuntimeCache.Greydwarf = text.Contains("greydwarf") || text.Contains("greyling");
			masterRingRuntimeCache.Skeleton = !text.Contains("brenna") && text.Contains("skeleton");
			masterRingRuntimeCache.KindInitialized = true;
		}
		return masterRingRuntimeCache;
	}

	internal static bool IsGreydwarf(Character c)
	{
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf(c);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			return masterRingRuntimeCache.Greydwarf;
		}
		return false;
	}

	internal static bool IsMeadowsAnimal(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return false;
		}
		string text = PrefabNameOf(((Component)c).gameObject).ToLowerInvariant();
		if (!text.Contains("deer") && !text.Contains("boar") && !text.Contains("neck"))
		{
			return text.Contains("greyling");
		}
		return true;
	}

	internal static bool IsSkeleton(Character c)
	{
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf(c);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			return masterRingRuntimeCache.Skeleton;
		}
		return false;
	}

	private static void CacheZdoMethods(object zdo)
	{
		if (zdo != null && !(cachedZdoType == zdo.GetType()))
		{
			cachedZdoType = zdo.GetType();
			zdoSetBool = AccessTools.Method(cachedZdoType, "Set", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, (Type[])null);
			zdoSetLong = AccessTools.Method(cachedZdoType, "Set", new Type[2]
			{
				typeof(string),
				typeof(long)
			}, (Type[])null);
			zdoSetFloat = AccessTools.Method(cachedZdoType, "Set", new Type[2]
			{
				typeof(string),
				typeof(float)
			}, (Type[])null);
			zdoGetBool = AccessTools.Method(cachedZdoType, "GetBool", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, (Type[])null);
			zdoGetLong = AccessTools.Method(cachedZdoType, "GetLong", new Type[2]
			{
				typeof(string),
				typeof(long)
			}, (Type[])null);
			zdoGetFloat = AccessTools.Method(cachedZdoType, "GetFloat", new Type[2]
			{
				typeof(string),
				typeof(float)
			}, (Type[])null);
		}
	}

	internal static object CharacterZdo(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return null;
		}
		try
		{
			object obj = ((CharacterNViewField == null) ? null : CharacterNViewField.GetValue(c));
			if (obj == null)
			{
				return null;
			}
			if (cachedViewType != obj.GetType())
			{
				cachedViewType = obj.GetType();
				getZdoMethod = AccessTools.Method(cachedViewType, "GetZDO", Type.EmptyTypes, (Type[])null);
			}
			return (getZdoMethod == null) ? null : getZdoMethod.Invoke(obj, null);
		}
		catch
		{
			return null;
		}
	}

	internal static void SetZdo(object zdo, string key, bool value)
	{
		CacheZdoMethods(zdo);
		if (zdoSetBool != null)
		{
			zdoSetBool.Invoke(zdo, new object[2] { key, value });
		}
	}

	internal static void SetZdo(object zdo, string key, long value)
	{
		CacheZdoMethods(zdo);
		if (zdoSetLong != null)
		{
			zdoSetLong.Invoke(zdo, new object[2] { key, value });
		}
	}

	internal static void SetZdo(object zdo, string key, float value)
	{
		CacheZdoMethods(zdo);
		if (zdoSetFloat != null)
		{
			zdoSetFloat.Invoke(zdo, new object[2] { key, value });
		}
	}

	internal static bool GetZdoBool(object zdo, string key, bool fallback)
	{
		CacheZdoMethods(zdo);
		if (!(zdoGetBool == null))
		{
			return (bool)zdoGetBool.Invoke(zdo, new object[2] { key, fallback });
		}
		return fallback;
	}

	internal static long GetZdoLong(object zdo, string key, long fallback)
	{
		CacheZdoMethods(zdo);
		if (!(zdoGetLong == null))
		{
			return (long)zdoGetLong.Invoke(zdo, new object[2] { key, fallback });
		}
		return fallback;
	}

	internal static float GetZdoFloat(object zdo, string key, float fallback)
	{
		CacheZdoMethods(zdo);
		if (!(zdoGetFloat == null))
		{
			return (float)zdoGetFloat.Invoke(zdo, new object[2] { key, fallback });
		}
		return fallback;
	}

	internal static bool IsPlayerOrTamed(Character c)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)c == (Object)null)
		{
			return false;
		}
		if (c is Player)
		{
			return true;
		}
		if ((int)c.GetFaction() == 0)
		{
			return true;
		}
		if (IsGreydwarf(c) && GreydwarfPeacePatch.SylvianAuraCovers(c))
		{
			return true;
		}
		return c.IsTamed();
	}

	internal static void SetBoundSkeletonNetworkFlag(Character c, bool value)
	{
		object zdo = CharacterZdo(c);
		SetZdo(zdo, "MR_BoundSkeleton", value);
	}

	internal static bool IsBoundSkeleton(Character c)
	{
		if ((Object)(object)c == (Object)null || !IsSkeleton(c))
		{
			return false;
		}
		if (BoundSkeletons.ContainsKey(((Object)c).GetInstanceID()))
		{
			return true;
		}
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf(c);
		if ((Object)(object)masterRingRuntimeCache != (Object)null && Time.time < masterRingRuntimeCache.BoundValidUntil)
		{
			return masterRingRuntimeCache.Bound;
		}
		object zdo = CharacterZdo(c);
		bool zdoBool = GetZdoBool(zdo, "MR_BoundSkeleton", fallback: false);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			masterRingRuntimeCache.Bound = zdoBool;
			masterRingRuntimeCache.BoundValidUntil = Time.time + 0.25f;
		}
		return zdoBool;
	}

	internal static bool IsLichSkeleton(Character c)
	{
		object zdo = CharacterZdo(c);
		if (IsSkeleton(c))
		{
			return GetZdoBool(zdo, "MR_LichSkeleton", fallback: false);
		}
		return false;
	}

	internal static long NetworkNowTicks()
	{
		if (!((Object)(object)ZNet.instance != (Object)null))
		{
			return DateTime.UtcNow.Ticks;
		}
		return ZNet.instance.GetTime().Ticks;
	}

	internal static void BindSkeleton(Character c, Player followPlayer, float duration, bool lichRaised, float lichDamage)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)c == (Object)null)
		{
			return;
		}
		c.m_faction = (Faction)0;
		object obj = CharacterZdo(c);
		long value = NetworkNowTicks() + TimeSpan.FromSeconds(duration).Ticks;
		if (obj != null)
		{
			SetZdo(obj, "MR_BoundSkeleton", value: true);
			SetZdo(obj, "MR_BoundSkeletonExpiry", value);
			SetZdo(obj, "MR_LichSkeleton", lichRaised);
			if (lichRaised)
			{
				SetZdo(obj, "MR_LichSkeletonDamage", lichDamage);
			}
		}
		BaseAI baseAI = c.GetBaseAI();
		if ((Object)(object)baseAI != (Object)null && (Object)(object)followPlayer != (Object)null)
		{
			MethodInfo methodInfo = AccessTools.Method(((object)baseAI).GetType(), "SetFollowTarget", new Type[1] { typeof(GameObject) }, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(baseAI, new object[1] { ((Component)followPlayer).gameObject });
			}
		}
		BoundSkeletons[((Object)c).GetInstanceID()] = Time.time + duration;
		BoundSkeletonCharacters[((Object)c).GetInstanceID()] = c;
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf(c);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			masterRingRuntimeCache.BoundValidUntil = 0f;
		}
	}

	internal static float LichSkeletonDamage(Character c)
	{
		object zdo = CharacterZdo(c);
		return GetZdoFloat(zdo, "MR_LichSkeletonDamage", 0f);
	}

	private static void SetBiomeStatusEffect(Player p, string ring, bool active)
	{
		if ((Object)(object)p == (Object)null || !BiomeEffects.ContainsKey(ring))
		{
			return;
		}
		StatusEffect val = BiomeEffects[ring];
		int num = val.NameHash();
		SEMan sEMan = ((Character)p).GetSEMan();
		if (sEMan == null)
		{
			return;
		}
		if (active)
		{
			if (sEMan.HaveStatusEffect(num))
			{
				return;
			}
			MethodInfo[] methods = typeof(SEMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "AddStatusEffect")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 0 || parameters[0].ParameterType != typeof(int))
				{
					continue;
				}
				object[] array = new object[parameters.Length];
				array[0] = num;
				for (int j = 1; j < parameters.Length; j++)
				{
					if (parameters[j].ParameterType == typeof(bool))
					{
						array[j] = false;
					}
					else if (parameters[j].ParameterType == typeof(int))
					{
						array[j] = 0;
					}
					else if (parameters[j].ParameterType == typeof(float))
					{
						array[j] = 0f;
					}
					else
					{
						array[j] = null;
					}
				}
				methodInfo.Invoke(sEMan, array);
				break;
			}
		}
		else if (sEMan.HaveStatusEffect(num))
		{
			sEMan.RemoveStatusEffect(num, false);
		}
	}

	private static void PublishSylvianAura(Player p)
	{
		if (!((Object)(object)p == (Object)null))
		{
			object zdo = CharacterZdo((Character)(object)p);
			SetZdo(zdo, "MR_SylvianAura", HasRing(p, "MR_SylvianRing"));
		}
	}

	private static void PublishLichEquipped(Player p)
	{
		object zdo = CharacterZdo((Character)(object)p);
		SetZdo(zdo, "MR_LichEquipped", HasRing(p, "MR_LichKingRing"));
	}

	internal static bool HasPublishedSylvianAura(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return false;
		}
		if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
		{
			return HasRing(p, "MR_SylvianRing");
		}
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf((Character)(object)p);
		if ((Object)(object)masterRingRuntimeCache != (Object)null && Time.time < masterRingRuntimeCache.AuraValidUntil)
		{
			return masterRingRuntimeCache.Aura;
		}
		bool zdoBool = GetZdoBool(CharacterZdo((Character)(object)p), "MR_SylvianAura", fallback: false);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			masterRingRuntimeCache.Aura = zdoBool;
			masterRingRuntimeCache.AuraValidUntil = Time.time + 0.2f;
		}
		return zdoBool;
	}

	internal static bool HasPublishedLichRing(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return false;
		}
		if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
		{
			return HasRing(p, "MR_LichKingRing");
		}
		MasterRingRuntimeCache masterRingRuntimeCache = CacheOf((Character)(object)p);
		if ((Object)(object)masterRingRuntimeCache != (Object)null && Time.time < masterRingRuntimeCache.LichRingValidUntil)
		{
			return masterRingRuntimeCache.LichRing;
		}
		bool zdoBool = GetZdoBool(CharacterZdo((Character)(object)p), "MR_LichEquipped", fallback: false);
		if ((Object)(object)masterRingRuntimeCache != (Object)null)
		{
			masterRingRuntimeCache.LichRing = zdoBool;
			masterRingRuntimeCache.LichRingValidUntil = Time.time + 0.2f;
		}
		return zdoBool;
	}

	private void UpdateBiomeEffects(Player p)
	{
		if (!((Object)(object)p == (Object)null))
		{
			string text = EquippedBiomeRing(p);
			SetBiomeStatusEffect(p, "MR_MeadowsLordRing", text == "MR_MeadowsLordRing");
			SetBiomeStatusEffect(p, "MR_SylvianRing", text == "MR_SylvianRing");
			SetBiomeStatusEffect(p, "MR_DreadfulRing", text == "MR_DreadfulRing");
			SetBiomeStatusEffect(p, "MR_WindMasterRing", text == "MR_WindMasterRing");
			SetBiomeStatusEffect(p, "MR_LichKingRing", text == "MR_LichKingRing");
		}
	}

	private void ProcessBoundSkeletonExpiry()
	{
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		long num = NetworkNowTicks();
		List<int> list = new List<int>(BoundSkeletonCharacters.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			int key = list[i];
			if (!BoundSkeletonCharacters.TryGetValue(key, out var value) || (Object)(object)value == (Object)null || value.IsDead())
			{
				BoundSkeletonCharacters.Remove(key);
				BoundSkeletons.Remove(key);
				continue;
			}
			object zdo = CharacterZdo(value);
			long zdoLong = GetZdoLong(zdo, "MR_BoundSkeletonExpiry", 0L);
			float value2;
			bool flag = BoundSkeletons.TryGetValue(key, out value2) && Time.time >= value2;
			if ((zdoLong <= 0 || num < zdoLong) && !flag)
			{
				continue;
			}
			BoundSkeletons.Remove(key);
			BoundSkeletonCharacters.Remove(key);
			MasterRingRuntimeCache masterRingRuntimeCache = CacheOf(value);
			if ((Object)(object)masterRingRuntimeCache != (Object)null)
			{
				masterRingRuntimeCache.Bound = false;
				masterRingRuntimeCache.BoundValidUntil = Time.time + 0.25f;
			}
			if (value.IsOwner() && !value.IsDead())
			{
				bool flag2 = IsLichSkeleton(value);
				HitData val = new HitData();
				val.m_damage.m_damage = 1000000f;
				val.m_point = ((Component)value).transform.position;
				value.Damage(val);
				if (flag2)
				{
					DiagnosticLog("Lich King: resurrected Skeleton expired after 30 seconds.");
				}
			}
		}
	}

	private void DiscoverBoundSkeletons()
	{
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if (!((Object)(object)allCharacter == (Object)null) && IsSkeleton(allCharacter) && IsBoundSkeleton(allCharacter))
			{
				BoundSkeletonCharacters[((Object)allCharacter).GetInstanceID()] = allCharacter;
			}
		}
	}

	private void Update()
	{
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: 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)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null && Time.time >= nextBiomeEffectCheck)
		{
			nextBiomeEffectCheck = Time.time + 0.2f;
			if (Localization.instance != null && !string.Equals(appliedLanguage, Localization.instance.GetSelectedLanguage(), StringComparison.OrdinalIgnoreCase))
			{
				ApplyLocalization();
			}
			InvalidateLocalEquipmentCache(localPlayer);
			EquippedMasterRing(localPlayer);
			string text = EquippedBiomeRing(localPlayer);
			string surface;
			if (text == null)
			{
				surface = "Inactive";
				cachedLocalConstructedOrPath = false;
			}
			else
			{
				cachedLocalConstructedOrPath = ComputeConstructedOrPath(localPlayer, out surface);
			}
			if (!string.Equals(cachedLocalSurface, surface, StringComparison.Ordinal))
			{
				cachedLocalSurface = surface;
				DiagnosticLog("[DIAG] GroundDetection surface=" + surface + " speedBonus=" + !cachedLocalConstructedOrPath + " ring=" + (EquippedMasterRing(localPlayer) ?? "none") + " biome=" + Biome(localPlayer));
			}
			PublishSylvianAura(localPlayer);
			PublishLichEquipped(localPlayer);
			UpdateBiomeEffects(localPlayer);
		}
		if (Time.time >= nextBoundDiscoveryScan)
		{
			nextBoundDiscoveryScan = Time.time + 1f;
			DiscoverBoundSkeletons();
		}
		if (Time.time >= nextBoundExpiryScan)
		{
			nextBoundExpiryScan = Time.time + 0.25f;
			ProcessBoundSkeletonExpiry();
		}
		if ((Object)(object)localPlayer != (Object)null && Time.time >= nextExclusivityCheck)
		{
			nextExclusivityCheck = Time.time + 0.5f;
			MasterRingExclusivity.Enforce(localPlayer);
		}
		if (Time.time >= nextNecromancyCleanup)
		{
			nextNecromancyCleanup = Time.time + 10f;
			LichNecromancy.CleanupExpired();
		}
		if ((Object)(object)localPlayer == (Object)null || !HasRing(localPlayer, "MR_DreadfulRing") || Time.time < nextSkeletonScan)
		{
			return;
		}
		nextSkeletonScan = Time.time + 0.5f;
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if ((Object)(object)allCharacter == (Object)null)
			{
				continue;
			}
			Vector3 val = ((Component)allCharacter).transform.position - ((Component)localPlayer).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 400f || !IsSkeleton(allCharacter))
			{
				continue;
			}
			((Object)allCharacter).GetInstanceID();
			if (!IsBoundSkeleton(allCharacter))
			{
				try
				{
					BindSkeleton(allCharacter, localPlayer, 30f, lichRaised: false, 0f);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Skeleton bind failed: " + ex.Message));
				}
			}
		}
	}

	internal static void ApplyLocalization()
	{
		if (Localization.instance == null)
		{
			return;
		}
		appliedLanguage = Localization.instance.GetSelectedLanguage();
		Dictionary<string, string> dictionary = (string.Equals(appliedLanguage, "French", StringComparison.OrdinalIgnoreCase) ? French : English);
		MethodInfo methodInfo = AccessTools.Method(typeof(Localization), "AddWord", new Type[2]
		{
			typeof(string),
			typeof(string)
		}, (Type[])null);
		if (methodInfo == null)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)"Localization.AddWord not found; Master Rings localization was not injected.");
			}
			return;
		}
		foreach (KeyValuePair<string, string> item in dictionary)
		{
			methodInfo.Invoke(Localization.instance, new object[2] { item.Key, item.Value });
		}
	}
}
internal static class MasterRingExclusivity
{
	private static readonly Dictionary<int, ItemData> LastRequested = new Dictionary<int, ItemData>();

	private static readonly Dictionary<int, List<ItemData>> KnownEquipped = new Dictionary<int, List<ItemData>>();

	private static bool changing;

	private static List<ItemData> GetCandidates(Player player)
	{
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData equippedItem in ((Humanoid)player).GetInventory().GetEquippedItems())
		{
			if (MasterRingsPlugin.IsMasterRing(equippedItem) && !list.Contains(equippedItem))
			{
				list.Add(equippedItem);
			}
		}
		if (KnownEquipped.TryGetValue(((Object)player).GetInstanceID(), out var value))
		{
			foreach (ItemData item in value)
			{
				if (item != null && ((Humanoid)player).IsItemEquiped(item) && MasterRingsPlugin.IsMasterRing(item) && !list.Contains(item))
				{
					list.Add(item);
				}
			}
		}
		return list;
	}

	internal static ItemData FindEquippedRing(Player player)
	{
		if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null)
		{
			return null;
		}
		List<ItemData> candidates = GetCandidates(player);
		if (candidates.Count == 0)
		{
			return null;
		}
		if (LastRequested.TryGetValue(((Object)player).GetInstanceID(), out var value) && candidates.Contains(value))
		{
			return value;
		}
		return candidates[candidates.Count - 1];
	}

	internal static void PrepareEquip(Player player, ItemData requested)
	{
		if (changing || (Object)(object)player == (Object)null || !MasterRingsPlugin.IsMasterRing(requested))
		{
			return;
		}
		MasterRingsPlugin.InvalidateLocalEquipmentCache(player);
		LastRequested[((Object)player).GetInstanceID()] = requested;
		MasterRingsPlugin.DiagnosticLog("MasterRing equip requested: " + MasterRingsPlugin.RingPrefabOf(requested));
		changing = true;
		try
		{
			List<ItemData> candidates = GetCandidates(player);
			foreach (ItemData item in candidates)
			{
				if (item != requested && MasterRingsPlugin.IsMasterRing(item))
				{
					((Humanoid)player).UnequipItem(item, false);
					MasterRingsPlugin.DiagnosticLog("MasterRing exclusivity: unequipped " + MasterRingsPlugin.RingPrefabOf(item));
				}
			}
		}
		finally
		{
			changing = false;
		}
	}

	internal static void RecordEquipped(Player player, ItemData item, bool succeeded)
	{
		if (!succeeded || (Object)(object)player == (Object)null || !MasterRingsPlugin.IsMasterRing(item))
		{
			return;
		}
		MasterRingsPlugin.InvalidateLocalEquipmentCache(player);
		if (string.Equals(MasterRingsPlugin.RingPrefabOf(item), "MR_DreadfulRing", StringComparison.Ordinal))
		{
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet))
			{
				sEMan.RemoveStatusEffect(SEMan.s_statusEffectWet, false);
			}
		}
		if (!KnownEquipped.TryGetValue(((Object)player).GetInstanceID(), out var value))
		{
			value = new List<ItemData>();
			KnownEquipped[((Object)player).GetInstanceID()] = value;
		}
		if (!value.Contains(item))
		{
			value.Add(item);
		}
	}

	internal static void RecordUnequipped(Player player, ItemData item)
	{
		if (!((Object)(object)player == (Object)null) && item != null)
		{
			MasterRingsPlugin.InvalidateLocalEquipmentCache(player);
			if (KnownEquipped.TryGetValue(((Object)player).GetInstanceID(), out var value))
			{
				value.Remove(item);
			}
		}
	}

	internal static void Enforce(Player player)
	{
		if (changing || (Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null)
		{
			return;
		}
		List<ItemData> candidates = GetCandidates(player);
		if (candidates.Count <= 1)
		{
			return;
		}
		ItemData value = null;
		LastRequested.TryGetValue(((Object)player).GetInstanceID(), out value);
		if (value == null || !candidates.Contains(value))
		{
			value = candidates[candidates.Count - 1];
		}
		changing = true;
		try
		{
			foreach (ItemData item in candidates)
			{
				if (item != value)
				{
					((Humanoid)player).UnequipItem(item, false);
					MasterRingsPlugin.DiagnosticLog("MasterRing invalid state repaired: unequipped " + MasterRingsPlugin.RingPrefabOf(item));
				}
			}
		}
		finally
		{
			changing = false;
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "EquipItem")]
internal static class MasterRingEquipPatch
{
	private static void Prefix(Humanoid __instance, ItemData item)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if ((Object)(object)val != (Object)null)
		{
			MasterRingExclusivity.PrepareEquip(val, item);
		}
	}

	private static void Postfix(Humanoid __instance, ItemData item, bool __result)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if ((Object)(object)val != (Object)null)
		{
			MasterRingExclusivity.RecordEquipped(val, item, __result);
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
internal static class MasterRingUnequipPatch
{
	private static void Postfix(Humanoid __instance, ItemData item)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if ((Object)(object)val != (Object)null)
		{
			MasterRingExclusivity.RecordUnequipped(val, item);
		}
	}
}
internal static class StaminaDiagnostics
{
	private static readonly Dictionary<string, float> NextLog = new Dictionary<string, float>();

	internal static void Log(string action, float baseCost, float finalCost, Player player)
	{
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)player == (Object)null) && !((Object)(object)MasterRingsPlugin.Instance == (Object)null) && (!NextLog.TryGetValue(action, out var value) || !(Time.time < value)))
		{
			NextLog[action] = Time.time + 2f;
			string text = MasterRingsPlugin.EquippedBiomeRing(player);
			MasterRingsPlugin.DiagnosticLog(string.Concat("[DIAG] STAMINA action=", action, " baseCost=", baseCost.ToString("0.###"), " finalCost=", finalCost.ToString("0.###"), " ring=", text ?? "none", " biome=", MasterRingsPlugin.Biome(player), " multiplier=0.90"));
		}
	}
}
[HarmonyPatch]
internal static class JogSpeedPatch
{
	private static float nextDiag;

	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(typeof(Player), "GetJogSpeedFactor", (Type[])null, (Type[])null);
	}

	private static void Postfix(Player __instance, ref float __result)
	{
		if (MasterRingsPlugin.EquippedBiomeRing(__instance) != null && !MasterRingsPlugin.OnConstructedOrPath(__instance))
		{
			float num = __result;
			__result *= 1.1f;
			if (Time.time >= nextDiag && (Object)(object)MasterRingsPlugin.Instance != (Object)null)
			{
				nextDiag = Time.time + 2f;
				MasterRingsPlugin.DiagnosticLog("[DIAG] Jog speed factor " + num.ToString("0.###") + " -> " + __result.ToString("0.###") + " (x1.10)");
			}
		}
	}
}
[HarmonyPatch]
internal static class RunSpeedPatch
{
	private static float nextDiag;

	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(typeof(Player), "GetRunSpeedFactor", (Type[])null, (Type[])null);
	}

	private static void Postfix(Player __instance, ref float __result)
	{
		if (MasterRingsPlugin.EquippedBiomeRing(__instance) != null && !MasterRingsPlugin.OnConstructedOrPath(__instance))
		{
			float num = __result;
			__result *= 1.1f;
			if (Time.time >= nextDiag && (Object)(object)MasterRingsPlugin.Instance != (Object)null)
			{
				nextDiag = Time.time + 2f;
				MasterRingsPlugin.DiagnosticLog("[DIAG] Run speed factor " + num.ToString("0.###") + " -> " + __result.ToString("0.###") + " (x1.10)");
			}
		}
	}
}
[HarmonyPatch(typeof(Skills), "GetSkillLevel")]
internal static class SkillPatch
{
	private static void Postfix(SkillType skillType, ref float __result)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Invalid comparison between Unknown and I4
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Invalid comparison between Unknown and I4
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			if ((int)skillType == 107 && MasterRingsPlugin.HasRing(localPlayer, "MR_MeadowsLordRing") && MasterRingsPlugin.CorrectBiome(localPlayer, "MR_MeadowsLordRing"))
			{
				__result += 20f;
			}
			if ((int)skillType == 106 && MasterRingsPlugin.HasRing(localPlayer, "MR_SylvianRing") && MasterRingsPlugin.CorrectBiome(localPlayer, "MR_SylvianRing"))
			{
				__result += 20f;
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class DamagePatch
{
	private static bool Prefix(Character __instance, HitData hit)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		if (hit == null)
		{
			return true;
		}
		Character attacker = hit.GetAttacker();
		if (MasterRingsPlugin.IsBoundSkeleton(attacker) && MasterRingsPlugin.IsPlayerOrTamed(__instance))
		{
			return false;
		}
		if (MasterRingsPlugin.IsLichSkeleton(attacker))
		{
			float num = MasterRingsPlugin.LichSkeletonDamage(attacker);
			if (num > 0f)
			{
				hit.m_damage = default(DamageTypes);
				hit.m_damage.m_damage = num;
			}
		}
		Player val = (Player)(object)((attacker is Player) ? attacker : null);
		if ((Object)(object)val != (Object)null && MasterRingsPlugin.HasRing(val, "MR_MeadowsLordRing") && MasterRingsPlugin.CorrectBiome(val, "MR_MeadowsLordRing") && MasterRingsPlugin.IsMeadowsAnimal(__instance))
		{
			((DamageTypes)(ref hit.m_damage)).Modify(1.2f);
		}
		return true;
	}
}
[HarmonyPatch]
internal static class LichTarSlowdownPatch
{
	private static float nextDiag;

	private static IEnumerable<MethodBase> TargetMethods()
	{
		MethodInfo baseMethod = AccessTools.Method(typeof(StatusEffect), "ModifySpeed", (Type[])null, (Type[])null);
		if (baseMethod != null)
		{
			yield return baseMethod;
		}
		MethodInfo statsMethod = AccessTools.Method(typeof(SE_Stats), "ModifySpeed", (Type[])null, (Type[])null);
		if (statsMethod != null)
		{
			yield return statsMethod;
		}
	}

	private static bool Prefix(StatusEffect __instance)
	{
		Character character = __instance.m_character;
		Player val = (Player)(object)((character is Player) ? character : null);
		if ((Object)(object)val == (Object)null || !MasterRingsPlugin.HasRing(val, "MR_LichKingRing") || !MasterRingsPlugin.CorrectBiome(val, "MR_LichKingRing"))
		{
			return true;
		}
		string text = (((Object)__instance).name ?? string.Empty).ToLowerInvariant();
		string text2 = (__instance.m_name ?? string.Empty).ToLowerInvariant();
		bool flag = text == "tared" || text2 == "$se_tared" || text.Contains("tared");
		if (flag && Time.time >= nextDiag)
		{
			nextDiag = Time.time + 2f;
			MasterRingsPlugin.DiagnosticLog("[DIAG] TARED attempt LichKing=true biome=Plains result=slowdown-neutralized");
		}
		return !flag;
	}
}
internal static class LichNecromancy
{
	private sealed class DeathContext
	{
		internal Player Killer;

		internal float VictimMaxHealth;

		internal Vector3 DeathPoint;

		internal string VictimPrefab;

		internal float CapturedAt;
	}

	private static readonly Dictionary<int, DeathContext> LastDamage = new Dictionary<int, DeathContext>();

	private static readonly HashSet<string> ResurrectionWhitelist = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
	{
		"Greyling", "Greydwarf", "Greydwarf_Elite", "Greydwarf_Shaman", "Draugr", "Draugr_Ranged", "Draugr_Elite", "Fenring", "Fenring_Cultist", "Goblin",
		"GoblinArcher", "GoblinShaman", "Dverger", "DvergerMage"
	};

	internal static void RecordDamage(Character victim, HitData hit)
	{
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)victim == (Object)null) && hit != null)
		{
			int instanceID = ((Object)victim).GetInstanceID();
			string text = MasterRingsPlugin.PrefabNameOf(((Component)victim).gameObject);
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (AbsoluteExclusion(text) || !ResurrectionWhitelist.Contains(text) || (Object)(object)val == (Object)null || !MasterRingsPlugin.HasPublishedLichRing(val))
			{
				LastDamage.Remove(instanceID);
				return;
			}
			LastDamage[instanceID] = new DeathContext
			{
				Killer = val,
				VictimMaxHealth = victim.GetMaxHealth(),
				DeathPoint = ((Component)victim).transform.position,
				VictimPrefab = text,
				CapturedAt = Time.time
			};
		}
	}

	internal static void CleanupExpired()
	{
		if (LastDamage.Count == 0)
		{
			return;
		}
		List<int> list = new List<int>();
		foreach (KeyValuePair<int, DeathContext> item in LastDamage)
		{
			if (Time.time - item.Value.CapturedAt > 30f || (Object)(object)item.Value.Killer == (Object)null)
			{
				list.Add(item.Key);
			}
		}
		for (int i = 0; i < list.Count; i++)
		{
			LastDamage.Remove(list[i]);
		}
	}

	private static bool AbsoluteExclusion(string prefab)
	{
		string text = (prefab ?? string.Empty).ToLowerInvariant();
		if (!text.Contains("skeleton") && !text.Contains("brenna") && !text.Contains("troll"))
		{
			return text.Contains("goblinbrute");
		}
		return true;
	}

	private static float DamageForBiome(Biome biome)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Invalid comparison between Unknown and I4
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Invalid comparison between Unknown and I4
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Invalid comparison between Unknown and I4
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Invalid comparison between Unknown and I4
		if ((int)biome == 8)
		{
			return 35f;
		}
		if ((int)biome == 2)
		{
			return 55f;
		}
		if ((int)biome == 4)
		{
			return 75f;
		}
		if ((int)biome == 16)
		{
			return 95f;
		}
		if ((int)biome == 512)
		{
			return 115f;
		}
		return 15f;
	}

	internal static void TryRaise(Character victim)
	{
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)victim == (Object)null || victim.GetHealth() > 0f || !victim.IsOwner() || !LastDamage.TryGetValue(((Object)victim).GetInstanceID(), out var value))
		{
			return;
		}
		LastDamage.Remove(((Object)victim).GetInstanceID());
		bool flag = AbsoluteExclusion(value.VictimPrefab);
		bool flag2 = !flag && ResurrectionWhitelist.Contains(value.VictimPrefab);
		string text = (((Object)(object)value.Killer == (Object)null) ? "none" : value.Killer.GetPlayerName());
		bool flag3 = (Object)(object)value.Killer != (Object)null && MasterRingsPlugin.HasPublishedLichRing(value.Killer);
		MasterRingsPlugin.DiagnosticLog("Lich King death: victim=" + value.VictimPrefab + ", whitelist=" + flag2 + ", excluded=" + flag + ", killer=" + text + ", ring=" + flag3);
		if (!flag2 || !flag3)
		{
			return;
		}
		object obj = MasterRingsPlugin.CharacterZdo(victim);
		if (obj == null || MasterRingsPlugin.GetZdoBool(obj, "MR_LichRaised", fallback: false))
		{
			return;
		}
		MasterRingsPlugin.SetZdo(obj, "MR_LichRaised", value: true);
		Biome val = Heightmap.FindBiome(value.DeathPoint);
		float lichDamage = DamageForBiome(val);
		GameObject val2 = (((Object)(object)ZNetScene.instance == (Object)null) ? null : ZNetScene.instance.GetPrefab("Skeleton"));
		if ((Object)(object)val2 == (Object)null)
		{
			MasterRingsPlugin.DiagnosticLog("Lich King spawn failed: vanilla prefab Skeleton was not found.");
			return;
		}
		GameObject val3 = Object.Instantiate<GameObject>(val2, value.DeathPoint + Vector3.up * 0.1f, Quaternion.identity);
		Character val4 = (((Object)(object)val3 == (Object)null) ? null : val3.GetComponent<Character>());
		if ((Object)(object)val4 == (Object)null)
		{
			MasterRingsPlugin.DiagnosticLog("Lich King spawn failed: spawned Skeleton has no Character component.");
			return;
		}
		float num = Mathf.Max(1f, value.VictimMaxHealth);
		val4.SetMaxHealth(num);
		val4.SetHealth(num);
		MasterRingsPlugin.BindSkeleton(val4, value.Killer, 30f, lichRaised: true, lichDamage);
		MasterRingsPlugin.DiagnosticLog(string.Concat("Lich King raised Skeleton: victim=", value.VictimPrefab, ", biome=", val, ", maxHP=", num.ToString("0.##"), ", damage=", lichDamage.ToString("0.##"), ", duration=30s"));
	}
}
[HarmonyPatch(typeof(Character), "ApplyDamage")]
internal static class LichFatalHitCapturePatch
{
	private static void Prefix(Character __instance, HitData hit)
	{
		LichNecromancy.RecordDamage(__instance, hit);
	}
}
[HarmonyPatch(typeof(Character), "CheckDeath")]
internal static class LichDeathPatch
{
	private static void Prefix(Character __instance)
	{
		LichNecromancy.TryRaise(__instance);
	}
}
internal static class DreadfulWetImmunityPatch
{
	private static readonly Dictionary<int, float> NextDiagnostic = new Dictionary<int, float>();

	internal static void Install(Harmony harmony)
	{
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Expected O, but got Unknown
		int num = 0;
		MethodInfo methodInfo = AccessTools.Method(typeof(DreadfulWetImmunityPatch), "Prefix", (Type[])null, (Type[])null);
		MethodInfo[] methods = typeof(SEMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo2 in methods)
		{
			if (methodInfo2.Name != "AddStatusEffect" || methodInfo2.ReturnType != typeof(StatusEffect))
			{
				continue;
			}
			ParameterInfo[] parameters = methodInfo2.GetParameters();
			if (parameters.Length == 0)
			{
				continue;
			}
			Type parameterType = parameters[0].ParameterType;
			if (!(parameterType != typeof(string)) || !(parameterType != typeof(int)))
			{
				try
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
				}
				catch (Exception ex)
				{
					MasterRingsPlugin.DiagnosticLog("Dreadful Wet immunity skipped incompatible overload: " + ex.Message);
				}
			}
		}
		MasterRingsPlugin.DiagnosticLog("Dreadful Wet immunity installed on " + num + " AddStatusEffect overload(s).");
	}

	private static bool Prefix(object[] __args, Character ___m_character, ref StatusEffect __result)
	{
		if (__args == null || __args.Length == 0)
		{
			return true;
		}
		object obj = __args[0];
		if (!((obj is int) ? ((int)obj == SEMan.s_statusEffectWet) : string.Equals(obj as string, "Wet", StringComparison.Ordinal)))
		{
			return true;
		}
		Player val = (Player)(object)((___m_character is Player) ? ___m_character : null);
		if ((Object)(object)val == (Object)null || !MasterRingsPlugin.HasRing(val, "MR_DreadfulRing"))
		{
			return true;
		}
		__result = null;
		int instanceID = ((Object)val).GetInstanceID();
		if (!NextDiagnostic.TryGetValue(instanceID, out var value) || Time.time >= value)
		{
			NextDiagnostic[instanceID] = Time.time + 10f;
			MasterRingsPlugin.DiagnosticLog("[DIAG] WET attempt Dreadful=true result=blocked");
		}
		return false;
	}
}
[HarmonyPatch]
internal static class GreydwarfPeacePatch
{
	private const float AuraRadius = 100f;

	private const float AuraRadiusSqr = 10000f;

	private static MethodBase TargetMethod()
	{
		MethodInfo[] methods = typeof(BaseAI).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (!(methodInfo.Name != "IsEnemy") && !(methodInfo.ReturnType != typeof(bool)))
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 2 && parameters[0].ParameterType == typeof(Character) && parameters[1].ParameterType == typeof(Character))
				{
					return methodInfo;
				}
			}
		}
		return null;
	}

	internal static bool SylvianAuraCovers(Character greydwarf)
	{
		//IL_001c: 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_0045: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)greydwarf == (Object)null)
		{
			return false;
		}
		List<Player> allPlayers = Player.GetAllPlayers();
		if (allPlayers == null)
		{
			return false;
		}
		Vector3 position = ((Component)greydwarf).transform.position;
		for (int i = 0; i < allPlayers.Count; i++)
		{
			Player val = allPlayers[i];
			if (!((Object)(object)val == (Object)null) && MasterRingsPlugin.HasPublishedSylvianAura(val))
			{
				Vector3 val2 = ((Component)val).transform.position - position;
				if (((Vector3)(ref val2)).sqrMagnitude <= 10000f)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static void Postfix(Character a, Character b, ref bool __result)
	{
		if (!__result || (Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
		{
			return;
		}
		bool flag = MasterRingsPlugin.IsGreydwarf(a);
		bool flag2 = !flag && MasterRingsPlugin.IsGreydwarf(b);
		Character val = (flag ? a : (flag2 ? b : null));
		Character c = (((Object)(object)val == (Object)(object)a) ? b : a);
		if ((Object)(object)val != (Object)null && MasterRingsPlugin.IsPlayerOrTamed(c) && SylvianAuraCovers(val))
		{
			__result = false;
			return;
		}
		Character val2 = (MasterRingsPlugin.IsBoundSkeleton(a) ? a : (MasterRingsPlugin.IsBoundSkeleton(b) ? b : null));
		Character c2 = (((Object)(object)val2 == (Object)(object)a) ? b : a);
		if ((Object)(object)val2 != (Object)null && MasterRingsPlugin.IsPlayerOrTamed(c2))
		{
			__result = false;
		}
	}
}
internal static class AlliedBuildingPeace
{
	internal static bool IsAlly(Character character)
	{
		if ((Object)(object)character != (Object)null)
		{
			if (!MasterRingsPlugin.IsBoundSkeleton(character))
			{
				if (MasterRingsPlugin.IsGreydwarf(character))
				{
					return GreydwarfPeacePatch.SylvianAuraCovers(character);
				}
				return false;
			}
			return true;
		}
		return false;
	}

	internal static bool IsPlayerBuilding(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		Piece componentInParent = component.GetComponentInParent<Piece>();
		if ((Object)(object)componentInParent != (Object)null)
		{
			return componentInParent.IsPlacedByPlayer();
		}
		return false;
	}

	internal static bool AllowDamage(WearNTear building, HitData hit)
	{
		if (hit == null || !IsAlly(hit.GetAttacker()))
		{
			return true;
		}
		return !IsPlayerBuilding((Component)(object)building);
	}
}
[HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(StaticTarget) })]
internal static class AlliedBuildingSelectionPatch
{
	private static bool Prefix(BaseAI __instance, StaticTarget __0, ref bool __result)
	{
		if (!AlliedBuildingPeace.IsAlly(((Component)__instance).GetComponent<Character>()) || !AlliedBuildingPeace.IsPlayerBuilding((Component)(object)__0))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
internal static class AlliedBuildingTargetPatch
{
	private static void Prefix(MonsterAI __instance, ref StaticTarget ___m_targetStatic)
	{
		if (AlliedBuildingPeace.IsAlly(((Component)__instance).GetComponent<Character>()) && AlliedBuildingPeace.IsPlayerBuilding((Component)(object)___m_targetStatic))
		{
			___m_targetStatic = null;
		}
	}
}
[HarmonyPatch(typeof(WearNTear), "Damage")]
internal static class AlliedBuildingDamagePatch
{
	private static bool Prefix(WearNTear __instance, HitData hit)
	{
		return AlliedBuildingPeace.AllowDamage(__instance, hit);
	}
}
[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
internal static class AlliedBuildingNetworkDamagePatch
{
	private static bool Prefix(WearNTear __instance, HitData hit)
	{
		return AlliedBuildingPeace.AllowDamage(__instance, hit);
	}
}
internal static class SylvianTreeGift
{
	private static readonly Dictionary<int, string> Pending = new Dictionary<int, string>();

	internal static string WantedSeedPrefab(TreeBase tree)
	{
		if ((Object)(object)tree == (Object)null)
		{
			return null;
		}
		string text = MasterRingsPlugin.PrefabNameOf(((Component)tree).gameObject).ToLowerInvariant();
		if (text.Contains("beech"))
		{
			return "BeechSeeds";
		}
		if (text.Contains("birch"))
		{
			return "BirchSeeds";
		}
		if (text.Contains("oak"))
		{
			return "Acorn";
		}
		if (text.Contains("fir"))
		{
			return "FirCone";
		}
		if (text.Contains("pine"))
		{
			return "PineCone";
		}
		return null;
	}

	internal static void BeginHit(TreeBase tree, HitData hit)
	{
		if ((Object)(object)tree == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)tree).GetInstanceID();
		Pending.Remove(instanceID);
		if (hit == null)
		{
			return;
		}
		string text = WantedSeedPrefab(tree);
		if (text != null)
		{
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (!((Object)(object)val == (Object)null) && MasterRingsPlugin.HasPublishedSylvianAura(val))
			{
				Pending[instanceID] = text;
			}
		}
	}

	internal static void EndHit(TreeBase tree)
	{
		if ((Object)(object)tree != (Object)null)
		{
			Pending.Remove(((Object)tree).GetInstanceID());
		}
	}

	internal static void OnSpawnLog(TreeBase tree)
	{
		//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_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: 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_0088: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)tree == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)tree).GetInstanceID();
		if (!Pending.TryGetValue(instanceID, out var value))
		{
			return;
		}
		Pending.Remove(instanceID);
		try
		{
			if (!((Object)(object)ZNetScene.instance == (Object)null))
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(value);
				if ((Object)(object)prefab == (Object)null)
				{
					MasterRingsPlugin.DiagnosticLog("Sylvian seed prefab not found: " + value);
					return;
				}
				Vector3 val = ((Component)tree).transform.position + Vector3.up * 0.5f;
				Object.Instantiate<GameObject>(prefab, val, Quaternion.identity);
				MasterRingsPlugin.DiagnosticLog("Sylvian tree gift on SpawnLog: " + value + " from " + MasterRingsPlugin.PrefabNameOf(((Component)tree).gameObject));
			}
		}
		catch (Exception ex)
		{
			MasterRingsPlugin.DiagnosticLog("Sylvian SpawnLog gift: " + ex.Message);
		}
	}
}
[HarmonyPatch(typeof(TreeBase), "RPC_Damage")]
internal static class SylvianTreeHitPatch
{
	private static void Prefix(TreeBase __instance, HitData __1)
	{
		SylvianTreeGift.BeginHit(__instance, __1);
	}

	private static void Postfix(TreeBase __instance)
	{
		SylvianTreeGift.EndHit(__instance);
	}
}
[HarmonyPatch(typeof(TreeBase), "SpawnLog")]
internal static class SylvianTreeSpawnLogPatch
{
	private static void Prefix(TreeBase __instance)
	{
		SylvianTreeGift.OnSpawnLog(__instance);
	}
}
[HarmonyPatch(typeof(EnvMan), "GetWindDir")]
internal static class WindPatch
{
	private static void Postfix(ref Vector3 __result)
	{
		//IL_0034: 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_008f: 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_009b: 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)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !MasterRingsPlugin.HasRing(localPlayer, "MR_WindMasterRing"))
		{
			return;
		}
		Ship controlledShip = localPlayer.GetControlledShip();
		if (!((Object)(object)controlledShip == (Object)null))
		{
			Vector3 forward = ((Component)controlledShip).transform.forward;
			forward.y = 0f;
			if (!(((Vector3)(ref forward)).sqrMagnitude < 0.01f))
			{
				float num = Mathf.Sin(Time.time * 0.12f) * 20f + Mathf.Sin(Time.time * 0.047f) * 10f;
				__result = Quaternion.Euler(0f, num, 0f) * ((Vector3)(ref forward)).normalized;
			}
		}
	}
}