Decompiled source of ForestGammeltroll v1.0.0

plugins\ForestGammeltroll.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
using UnityEngine.Rendering;

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

internal static class DamagePatches
{
	[HarmonyPatch(typeof(Attack), "ModifyDamage")]
	private static class Attack_ModifyDamage
	{
		private static void Postfix(HitData hitData, Humanoid ___m_character)
		{
			if (ForestTrollCreature.IsForestTroll((Character)(object)___m_character))
			{
				((DamageTypes)(ref hitData.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value);
			}
		}
	}

	[HarmonyPatch(typeof(Aoe), "Setup")]
	private static class Aoe_Setup
	{
		private static void Postfix(Aoe __instance, Character owner, HitData hitData)
		{
			if ((hitData == null || !__instance.m_useAttackSettings) && ForestTrollCreature.IsForestTroll(owner))
			{
				((DamageTypes)(ref __instance.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value);
			}
		}
	}

	[HarmonyPatch(typeof(Projectile), "Setup")]
	private static class Projectile_Setup
	{
		private static void Postfix(Projectile __instance, Character owner, HitData hitData)
		{
			if (hitData == null && ForestTrollCreature.IsForestTroll(owner))
			{
				((DamageTypes)(ref __instance.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value);
			}
		}
	}
}
[BepInPlugin("com.voxxsidus.forestgammeltroll", "ForestGammeltroll", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal class ForestGammeltroll : BaseUnityPlugin
{
	public const string PluginGUID = "com.voxxsidus.forestgammeltroll";

	public const string PluginName = "ForestGammeltroll";

	public const string PluginVersion = "1.0.0";

	public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

	public static ConfigEntry<float> SpawnChance;

	public static ConfigEntry<bool> AllowStars;

	public static ConfigEntry<float> Health;

	public static ConfigEntry<float> DamageMultiplier;

	public static ConfigEntry<float> ModelScale;

	public static ConfigEntry<float> ViewRange;

	public static ConfigEntry<float> AlertRange;

	public static ConfigEntry<float> MaxChaseDistance;

	public static ConfigEntry<float> CopperOreWeight;

	public static ConfigEntry<Color> MossTint;

	public static ConfigEntry<float> SnowToMossThreshold;

	private ConfigEntry<bool> _dumpPrefabs;

	private void Awake()
	{
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		BindConfig();
		CustomLocalization localization = Localization;
		string text = "English";
		string text2 = "$enemy_forestgammeltroll";
		localization.AddTranslation(ref text, ref text2, "Forest Gammeltroll");
		CustomLocalization localization2 = Localization;
		text = "English";
		text2 = "$piece_forestgammeltroll_petrified";
		localization2.AddTranslation(ref text, ref text2, "Petrified Forest Gammeltroll");
		PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
		CreatureManager.OnVanillaCreaturesAvailable += OnVanillaCreaturesAvailable;
		Harmony val = new Harmony("com.voxxsidus.forestgammeltroll");
		val.PatchAll();
		StarLevelSystemCompat.Apply(val);
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new TestSpawnCommand());
		Logger.LogInfo((object)"ForestGammeltroll has landed");
	}

	private void BindConfig()
	{
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Expected O, but got Unknown
		SpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "SpawnChance", 25f, Synced("Percent chance that an open-world Troll spawning in the Black Forest becomes a Forest Gammeltroll instead. Troll caves and raids are never affected.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
		AllowStars = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "AllowStars", true, Synced("Whether swapped-in Forest Gammeltrolls can spawn with stars, using the Troll's level-up chances (up to 2 stars).", null));
		Health = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "Health", 1500f, Synced("Base health (1 star). Regular Troll: 600, vanilla Gammeltroll: 3000. Applies to newly spawned trolls.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f)));
		DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "DamageMultiplier", 0.75f, Synced("Multiplier on the vanilla Gammeltroll's damage, applied to every hit (punches, ground slam shockwave, thrown rocks). Vanilla Gammeltroll hits ~3x as hard as a regular Troll, so 0.75 is ~2.2-2.75x a Troll.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f)));
		ModelScale = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "ModelScale", 1f, Synced("Size relative to the vanilla Gammeltroll (1 = vanilla, ~4x a regular Troll; 0.5 = ~2x a Troll).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1.5f)));
		ViewRange = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "ViewRange", 50f, Synced("How far it can see targets. Regular Troll: 30, vanilla Gammeltroll: 300.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f)));
		AlertRange = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "AlertRange", 30f, Synced("Radius in which it notices nearby targets. Regular Troll: 20, vanilla Gammeltroll: 90.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f)));
		MaxChaseDistance = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "MaxChaseDistance", 200f, Synced("How far from its spawn point it will chase before giving up. Regular Troll: 200, vanilla Gammeltroll: 500.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 1000f)));
		CopperOreWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Petrify", "CopperOreWeight", 0.5f, Synced("Relative chance of Copper Ore vs Stone (weight 1) for each drop roll when mining the petrified remains. Each of the rock's chunks rolls 2-3 times. 0.5 matches the vanilla Gammeltroll's Bloodgold ratio (~1/3 of drops). Applies to remains created after the change.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f)));
		MossTint = ((BaseUnityPlugin)this).Config.Bind<Color>("Visual", "MossTint", new Color(0.7f, 1f, 0.55f), "Tint applied to the moss that replaces the snow on its skin, hair, statue and rock. Updates live.");
		SnowToMossThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "SnowToMossThreshold", 0.48f, new ConfigDescription("Brightness above which the skin texture counts as snow and becomes moss. Lower = more moss. Updates live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 0.9f), Array.Empty<object>()));
		MossTint.SettingChanged += delegate
		{
			ForestVisuals.RegenerateSkin();
		};
		SnowToMossThreshold.SettingChanged += delegate
		{
			ForestVisuals.RegenerateSkin();
		};
		_dumpPrefabs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpPrefabs", false, "Write ForestGammeltroll_PrefabDump.txt to the BepInEx folder when vanilla prefabs load (main menu).");
		ConfigEntry<float>[] array = new ConfigEntry<float>[7] { Health, DamageMultiplier, ModelScale, ViewRange, AlertRange, MaxChaseDistance, CopperOreWeight };
		for (int num = 0; num < array.Length; num++)
		{
			array[num].SettingChanged += delegate
			{
				ForestTrollCreature.ApplySettings();
			};
		}
		SynchronizationManager.OnConfigurationSynchronized += delegate
		{
			ForestTrollCreature.ApplySettings();
		};
		static ConfigDescription Synced(string description, AcceptableValueBase range)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} });
		}
	}

	private void OnVanillaPrefabsAvailable()
	{
		PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		if (_dumpPrefabs.Value)
		{
			PrefabDumper.DumpTrolls();
		}
	}

	private void OnVanillaCreaturesAvailable()
	{
		CreatureManager.OnVanillaCreaturesAvailable -= OnVanillaCreaturesAvailable;
		ForestTrollCreature.Register();
	}
}
internal static class ForestTrollCreature
{
	public const string PrefabName = "ForestGammeltroll";

	public const string NameToken = "$enemy_forestgammeltroll";

	private const string BasePrefabName = "TrollFrost";

	private static GameObject s_prefab;

	private static Vector3 s_baseScale;

	public static GameObject Prefab => s_prefab;

	public static void Register()
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll", "TrollFrost");
		if (!Object.op_Implicit((Object)(object)val))
		{
			Logger.LogError((object)"Could not clone TrollFrost; ForestGammeltroll will not exist");
			return;
		}
		GameObject statue = PetrifiedRemains.Register();
		SetPetrifiedStatue(val.GetComponent<Character>(), statue);
		RemoveStarTint(val);
		ForestVisuals.Apply(val, statue, PetrifiedRemains.Rock);
		CreatureConfig val2 = new CreatureConfig
		{
			Name = "$enemy_forestgammeltroll",
			Faction = (Faction)2
		};
		CreatureManager.Instance.AddCreature(new CustomCreature(val, false, val2));
		s_prefab = val;
		s_baseScale = val.transform.localScale;
		ApplySettings();
		Logger.LogInfo((object)"Registered ForestGammeltroll (cloned from TrollFrost)");
	}

	public static bool IsForestTroll(Character character)
	{
		if (Object.op_Implicit((Object)(object)character))
		{
			return character.m_name == "$enemy_forestgammeltroll";
		}
		return false;
	}

	public static void ApplySettings()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		PetrifiedRemains.ApplySettings();
		if (!Object.op_Implicit((Object)(object)s_prefab))
		{
			return;
		}
		float num = s_prefab.transform.localScale.x / s_baseScale.x;
		float num2 = ForestGammeltroll.ModelScale.Value / num;
		s_prefab.GetComponent<Character>().m_health = ForestGammeltroll.Health.Value;
		s_prefab.transform.localScale = s_baseScale * ForestGammeltroll.ModelScale.Value;
		ApplyAI(s_prefab.GetComponent<MonsterAI>());
		foreach (Character item in Character.GetAllCharacters().Where(IsForestTroll))
		{
			if (!Mathf.Approximately(num2, 1f))
			{
				Transform transform = ((Component)item).transform;
				transform.localScale *= num2;
			}
			ApplyAI(((Component)item).GetComponent<MonsterAI>());
		}
	}

	private static void ApplyAI(MonsterAI ai)
	{
		if (Object.op_Implicit((Object)(object)ai))
		{
			((BaseAI)ai).m_viewRange = ForestGammeltroll.ViewRange.Value;
			ai.m_alertRange = ForestGammeltroll.AlertRange.Value;
			ai.m_maxChaseDistance = ForestGammeltroll.MaxChaseDistance.Value;
		}
	}

	private static void RemoveStarTint(GameObject prefab)
	{
		LevelEffects[] componentsInChildren = prefab.GetComponentsInChildren<LevelEffects>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			foreach (LevelSetup levelSetup in componentsInChildren[i].m_levelSetups)
			{
				levelSetup.m_hue = 0f;
				levelSetup.m_saturation = 0f;
				levelSetup.m_value = 0f;
				levelSetup.m_setEmissiveColor = false;
			}
		}
	}

	private static void SetPetrifiedStatue(Character character, GameObject statue)
	{
		bool flag = false;
		List<EffectData> list = character.m_deathEffects.m_effectPrefabs.ToList();
		for (int num = list.Count - 1; num >= 0; num--)
		{
			if (Object.op_Implicit((Object)(object)list[num].m_prefab) && !(((Object)list[num].m_prefab).name != "TrollFrost_Dead"))
			{
				flag = true;
				if (Object.op_Implicit((Object)(object)statue))
				{
					list[num].m_prefab = statue;
				}
				else
				{
					list.RemoveAt(num);
				}
			}
		}
		character.m_deathEffects.m_effectPrefabs = list.ToArray();
		if (!flag)
		{
			Logger.LogWarning((object)"TrollFrost_Dead not found in TrollFrost death effects; it will not turn to stone");
		}
	}
}
internal static class ForestVisuals
{
	private const string SkinMaterialName = "FrostTrollmat";

	private const string BackTreesMaterialName = "Fir_Snow_Troll_mat";

	private const string BloodgoldVeinMaterialName = "FrostTrollBloodGold_mat";

	private const string GreenFirPrefabName = "FirTree_small";

	private const string GreenFirMaterialName = "Pine_tree_small";

	private const string CopperRockPrefabName = "rock4_copper";

	private const string CopperRockMaterialName = "rock1_copper";

	private const string CopperRockMossProperty = "_MossTex";

	private const string NormalMapProperty = "_BumpMap";

	private const string MossAlphaProperty = "_MossAlpha";

	private const string MossBlendProperty = "_MossBlend";

	private const string CopperFracPrefabName = "rock4_copper_frac";

	private const string CopperVeinMaterialName = "rock_copper_internal";

	private static readonly Dictionary<string, string> EffectReplacements = new Dictionary<string, string>
	{
		{ "vfx_firetreecut_snow_FrostTrollDeath", "vfx_firetreecut" },
		{ "vfx_frostarrow_hit", "vfx_foresttroll_hit" }
	};

	private static readonly Rect HairBlock = new Rect(0.58f, 0f, 0.42f, 0.36f);

	private const float MossTiling = 2f;

	private const float MossGain = 1.35f;

	private const float SnowFeather = 0.27f;

	private static Texture2D s_snowySkin;

	private static Texture2D s_moss;

	private static Material s_skinMaterial;

	private static Texture2D s_generatedSkin;

	public static void Apply(GameObject creature, GameObject statue, GameObject rock)
	{
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Expected O, but got Unknown
		List<Renderer> list = ((IEnumerable<GameObject>)(object)new GameObject[3] { creature, statue, rock }).Where((GameObject go) => Object.op_Implicit((Object)(object)go)).SelectMany((GameObject go) => go.GetComponentsInChildren<Renderer>(true)).ToList();
		Dictionary<string, Material> replacements = new Dictionary<string, Material>();
		Material val = FindMaterial(list, "FrostTrollmat");
		Texture mossTexture = GetMossTexture();
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)mossTexture))
		{
			s_snowySkin = ReadPixels(val.mainTexture);
			s_moss = ReadPixels(mossTexture);
			s_skinMaterial = new Material(val)
			{
				name = "ForestGammeltroll_mat"
			};
			RegenerateSkin();
			replacements["FrostTrollmat"] = s_skinMaterial;
		}
		Material val2 = FindMaterial(list, "Fir_Snow_Troll_mat");
		Material materialFromPrefab = GetMaterialFromPrefab("FirTree_small", "Pine_tree_small");
		if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)materialFromPrefab))
		{
			Material val3 = new Material(val2)
			{
				name = "ForestGammeltroll_Fir_mat"
			};
			val3.mainTexture = materialFromPrefab.mainTexture;
			val3.SetTexture("_BumpMap", materialFromPrefab.GetTexture("_BumpMap"));
			val3.SetFloat("_MossAlpha", materialFromPrefab.GetFloat("_MossAlpha"));
			val3.SetFloat("_MossBlend", materialFromPrefab.GetFloat("_MossBlend"));
			replacements["Fir_Snow_Troll_mat"] = val3;
		}
		Material materialFromPrefab2 = GetMaterialFromPrefab("rock4_copper_frac", "rock_copper_internal");
		if (Object.op_Implicit((Object)(object)materialFromPrefab2))
		{
			replacements["FrostTrollBloodGold_mat"] = materialFromPrefab2;
		}
		foreach (Renderer item in list)
		{
			item.sharedMaterials = item.sharedMaterials.Select((Material m) => (!Object.op_Implicit((Object)(object)m) || !replacements.TryGetValue(((Object)m).name, out var value)) ? m : value).ToArray();
		}
		ReplaceEffects(creature.GetComponent<Character>());
		Logger.LogInfo((object)("Forest visuals applied: " + string.Join(", ", replacements.Keys)));
	}

	public static void RegenerateSkin()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)s_skinMaterial))
		{
			return;
		}
		Texture2D val = s_generatedSkin;
		s_generatedSkin = BuildMossySkin(s_snowySkin, s_moss, ForestGammeltroll.MossTint.Value, ForestGammeltroll.SnowToMossThreshold.Value);
		s_skinMaterial.mainTexture = (Texture)(object)s_generatedSkin;
		if (AccessTools.Field(typeof(LevelEffects), "m_materials")?.GetValue(null) is Dictionary<string, Material> source)
		{
			foreach (KeyValuePair<string, Material> item in source.Where((KeyValuePair<string, Material> e) => e.Key.StartsWith("ForestGammeltroll") && Object.op_Implicit((Object)(object)e.Value)))
			{
				item.Value.mainTexture = (Texture)(object)s_generatedSkin;
			}
		}
		if (Object.op_Implicit((Object)(object)val))
		{
			Object.Destroy((Object)(object)val);
		}
	}

	private static Texture2D BuildMossySkin(Texture2D snowy, Texture2D moss, Color tint, float threshold)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		int width = ((Texture)snowy).width;
		int height = ((Texture)snowy).height;
		Color[] pixels = snowy.GetPixels();
		Color[] array = (Color[])(object)new Color[pixels.Length];
		Color val = default(Color);
		((Color)(ref val))..ctor(tint.r * 1.35f, tint.g * 1.35f, tint.b * 1.35f);
		for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				int num = i * width + j;
				Color val2 = pixels[num];
				float num2 = ((float)j + 0.5f) / (float)width;
				float num3 = ((float)i + 0.5f) / (float)height;
				float num4 = val2.r * 0.299f + val2.g * 0.587f + val2.b * 0.114f;
				Color val3 = moss.GetPixelBilinear(num2 * 2f, num3 * 2f) * val;
				Rect hairBlock = HairBlock;
				Color val4;
				if (((Rect)(ref hairBlock)).Contains(new Vector2(num2, num3)))
				{
					val4 = val3 * (0.3f + 0.9f * num4);
				}
				else
				{
					float num5 = Mathf.Max(val2.r, Mathf.Max(val2.g, val2.b));
					float num6 = Mathf.Min(val2.r, Mathf.Min(val2.g, val2.b));
					float x = ((num5 > 0f) ? ((num5 - num6) / num5) : 0f);
					float num7 = SmoothStep(threshold, threshold + 0.27f, num4) * (1f - SmoothStep(0.18f, 0.35f, x));
					float num8 = 0.55f + 0.9f * (num4 - 0.5f);
					val4 = Color.Lerp(val2, val3 * num8, num7);
				}
				val4.a = val2.a;
				array[num] = val4;
			}
		}
		return CreateTexture((Texture)(object)snowy, width, height, array, "ForestGammeltroll_d");
	}

	private static void ReplaceEffects(Character character)
	{
		EffectList[] array = (EffectList[])(object)new EffectList[3] { character.m_deathEffects, character.m_hitEffects, character.m_critHitEffects };
		for (int i = 0; i < array.Length; i++)
		{
			EffectData[] effectPrefabs = array[i].m_effectPrefabs;
			foreach (EffectData val in effectPrefabs)
			{
				if (Object.op_Implicit((Object)(object)val.m_prefab) && EffectReplacements.TryGetValue(((Object)val.m_prefab).name, out var value))
				{
					GameObject prefab = Cache.GetPrefab<GameObject>(value);
					if (Object.op_Implicit((Object)(object)prefab))
					{
						val.m_prefab = prefab;
					}
					else
					{
						Logger.LogWarning((object)("Effect " + value + " not found; keeping " + ((Object)val.m_prefab).name));
					}
				}
			}
		}
	}

	private static Texture GetMossTexture()
	{
		Material materialFromPrefab = GetMaterialFromPrefab("rock4_copper", "rock1_copper");
		Texture obj = ((Object.op_Implicit((Object)(object)materialFromPrefab) && materialFromPrefab.HasProperty("_MossTex")) ? materialFromPrefab.GetTexture("_MossTex") : null);
		if (!Object.op_Implicit((Object)(object)obj))
		{
			Logger.LogWarning((object)"No _MossTex on rock1_copper; skin stays snowy");
		}
		return obj;
	}

	private static Material GetMaterialFromPrefab(string prefabName, string materialName)
	{
		GameObject prefab = Cache.GetPrefab<GameObject>(prefabName);
		Material obj = (Object.op_Implicit((Object)(object)prefab) ? FindMaterial(prefab.GetComponentsInChildren<Renderer>(true), materialName) : null);
		if (!Object.op_Implicit((Object)(object)obj))
		{
			Logger.LogWarning((object)("Material " + materialName + " not found on " + prefabName));
		}
		return obj;
	}

	private static Material FindMaterial(IEnumerable<Renderer> renderers, string name)
	{
		return renderers.SelectMany((Renderer r) => r.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && ((Object)m).name == name));
	}

	private static Texture2D ReadPixels(Texture source)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: 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_007a: Expected O, but got Unknown
		RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		Graphics.Blit(source, temporary);
		RenderTexture.active = temporary;
		Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, false);
		val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0);
		val.Apply();
		RenderTexture.active = active;
		RenderTexture.ReleaseTemporary(temporary);
		((Texture)val).wrapMode = (TextureWrapMode)0;
		return val;
	}

	private static Texture2D CreateTexture(Texture template, int w, int h, Color[] pixels, string name)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		Texture2D val = new Texture2D(w, h, (TextureFormat)4, true)
		{
			name = name,
			filterMode = template.filterMode,
			wrapMode = template.wrapMode,
			anisoLevel = template.anisoLevel
		};
		val.SetPixels(pixels);
		val.Apply(true);
		return val;
	}

	private static float SmoothStep(float a, float b, float x)
	{
		float num = Mathf.Clamp01((x - a) / (b - a));
		return num * num * (3f - 2f * num);
	}
}
internal static class PetrifiedRemains
{
	public const string StatuePrefabName = "ForestGammeltroll_Dead";

	public const string RockPrefabName = "ForestGammeltroll_Frac";

	public const string NameToken = "$piece_forestgammeltroll_petrified";

	public const string VanillaStatuePrefabName = "TrollFrost_Dead";

	private const string VanillaRockPrefabName = "TrollFrost_Frac";

	private const string VanillaRareOreName = "GoldOre";

	private const string CopperOreName = "CopperOre";

	private const string MinimumPickaxeName = "PickaxeAntler";

	private static GameObject s_statue;

	private static GameObject s_rock;

	private static int s_copperDropIndex = -1;

	public static GameObject Rock => s_rock;

	public static GameObject Register()
	{
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		int minimumToolTier = GetMinimumToolTier();
		if (minimumToolTier < 0)
		{
			return null;
		}
		GameObject prefab = Cache.GetPrefab<GameObject>("CopperOre");
		if (!Object.op_Implicit((Object)(object)prefab))
		{
			Logger.LogError((object)"Could not find CopperOre; it will not turn to stone");
			return null;
		}
		GameObject val = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll_Frac", "TrollFrost_Frac");
		GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll_Dead", "TrollFrost_Dead");
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
		{
			Logger.LogError((object)"Could not clone TrollFrost_Frac/TrollFrost_Dead; it will not turn to stone");
			return null;
		}
		MineRock5 component = val.GetComponent<MineRock5>();
		component.m_name = "$piece_forestgammeltroll_petrified";
		component.m_minToolTier = minimumToolTier;
		List<DropData> drops = component.m_dropItems.m_drops;
		for (int i = 0; i < drops.Count; i++)
		{
			if (Object.op_Implicit((Object)(object)drops[i].m_item) && ((Object)drops[i].m_item).name == "GoldOre")
			{
				DropData value = drops[i];
				value.m_item = prefab;
				drops[i] = value;
				s_copperDropIndex = i;
			}
		}
		if (s_copperDropIndex < 0)
		{
			Logger.LogWarning((object)"GoldOre not found in TrollFrost_Frac drops; rock will drop no copper");
		}
		Destructible component2 = val2.GetComponent<Destructible>();
		component2.m_minToolTier = minimumToolTier;
		component2.m_spawnWhenDestroyed = val;
		HoverText component3 = val2.GetComponent<HoverText>();
		if (Object.op_Implicit((Object)(object)component3))
		{
			component3.m_text = "$piece_forestgammeltroll_petrified";
		}
		PrefabManager.Instance.AddPrefab(val);
		PrefabManager.Instance.AddPrefab(val2);
		s_rock = val;
		s_statue = val2;
		ApplySettings();
		Logger.LogInfo((object)string.Format("Registered {0} and {1} (min tool tier {2}, from {3})", "ForestGammeltroll_Dead", "ForestGammeltroll_Frac", minimumToolTier, "PickaxeAntler"));
		return val2;
	}

	public static void ApplySettings()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)s_statue))
		{
			s_statue.transform.localScale = Vector3.one * ForestGammeltroll.ModelScale.Value;
			if (s_copperDropIndex >= 0)
			{
				List<DropData> drops = s_rock.GetComponent<MineRock5>().m_dropItems.m_drops;
				DropData value = drops[s_copperDropIndex];
				value.m_weight = ForestGammeltroll.CopperOreWeight.Value;
				drops[s_copperDropIndex] = value;
			}
		}
	}

	private static int GetMinimumToolTier()
	{
		GameObject prefab = Cache.GetPrefab<GameObject>("PickaxeAntler");
		ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null);
		if (!Object.op_Implicit((Object)(object)val))
		{
			Logger.LogError((object)"Could not find PickaxeAntler; it will not turn to stone");
			return -1;
		}
		return val.m_itemData.m_shared.m_toolTier;
	}
}
internal static class PrefabDumper
{
	private class DumpContext
	{
		public readonly StringBuilder Sb = new StringBuilder();

		public readonly Queue<(GameObject prefab, string via, int depth)> LinkedQueue = new Queue<(GameObject, string, int)>();

		public readonly HashSet<GameObject> Dumped = new HashSet<GameObject>();

		public GameObject CurrentRoot;

		public int CurrentLinkDepth;
	}

	public const string DumpFileName = "ForestGammeltroll_PrefabDump.txt";

	private const int MaxFieldDepth = 7;

	private const int MaxListElements = 64;

	private const int MaxLinkedPrefabDepth = 3;

	private static readonly string[] DeathChainFieldHints = new string[5] { "death", "ragdoll", "destroy", "remove", "petrif" };

	private static readonly CultureInfo Inv = CultureInfo.InvariantCulture;

	public static void DumpTrolls()
	{
		try
		{
			DumpContext dumpContext = new DumpContext();
			StringBuilder sb = dumpContext.Sb;
			sb.AppendLine($"ForestGammeltroll prefab dump - Valheim {GameVersionString()} - {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
			sb.AppendLine();
			List<GameObject> list = (from go in (from c in Cache.GetPrefabs(typeof(Character)).Values.OfType<Character>()
					select ((Component)c).gameObject into go
					where (Object)(object)go.transform.parent == (Object)null
					select go).Distinct().OrderBy<GameObject, string>((GameObject go) => ((Object)go).name, StringComparer.OrdinalIgnoreCase).ToList()
				where IsGammel(go) || ContainsCI(((Object)go).name, "troll") || ContainsCI(DisplayName(go), "troll")
				select go).ToList();
			Section(sb, "CANDIDATE PREFABS (Character prefabs with 'gammel' or 'troll' in the prefab or display name)");
			foreach (GameObject item in list)
			{
				Character component = item.GetComponent<Character>();
				sb.AppendLine("  " + ((Object)item).name + "  m_name=\"" + component.m_name + "\" display=\"" + DisplayName(item) + "\"  [" + string.Join(", ", from c in item.GetComponents<Component>()
					where Object.op_Implicit((Object)(object)c)
					select ((object)c).GetType().Name) + "]");
			}
			sb.AppendLine();
			DumpSpawnReferences(sb);
			List<GameObject> list2 = list.Where(IsGammel).ToList();
			GameObject val = ((IEnumerable<GameObject>)list).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => ((Object)go).name == "Troll"));
			if (list2.Count == 0)
			{
				sb.AppendLine("!!! No prefab containing 'gammel' was found.");
			}
			foreach (GameObject item2 in list2)
			{
				Section(sb, "FULL DUMP: " + ((Object)item2).name);
				DumpPrefab(dumpContext, item2, includeRenderers: true);
				DumpHumanoidItems(dumpContext, item2);
			}
			if (dumpContext.LinkedQueue.Count > 0)
			{
				Section(sb, "DEATH CHAIN: prefabs referenced from death/ragdoll/destroy/remove fields");
				while (dumpContext.LinkedQueue.Count > 0)
				{
					var (val2, text, currentLinkDepth) = dumpContext.LinkedQueue.Dequeue();
					if (!dumpContext.Dumped.Contains(val2))
					{
						sb.AppendLine();
						sb.AppendLine("----- Linked prefab: " + ((Object)val2).name + "  (via " + text + ") -----");
						dumpContext.CurrentLinkDepth = currentLinkDepth;
						DumpPrefab(dumpContext, val2, includeRenderers: true);
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				Section(sb, "COMPARISON: regular Troll (components and stats, no materials)");
				dumpContext.CurrentLinkDepth = 3;
				DumpPrefab(dumpContext, val, includeRenderers: false);
				DumpHumanoidItems(dumpContext, val);
			}
			else
			{
				sb.AppendLine("!!! No prefab named exactly 'Troll' was found.");
			}
			string text2 = Path.Combine(Paths.BepInExRootPath, "ForestGammeltroll_PrefabDump.txt");
			File.WriteAllText(text2, sb.ToString());
			Logger.LogInfo((object)$"Prefab dump written to {text2} ({list2.Count} gammel prefab(s), troll found: {Object.op_Implicit((Object)(object)val)})");
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"Prefab dump failed: {arg}");
		}
		static bool IsGammel(GameObject go)
		{
			if (!ContainsCI(((Object)go).name, "gammel"))
			{
				return ContainsCI(DisplayName(go), "gammel");
			}
			return true;
		}
	}

	private static void DumpSpawnReferences(StringBuilder sb)
	{
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		Section(sb, "SPAWN REFERENCES (loaded SpawnSystemList / CreatureSpawner entries for trolls)");
		SpawnSystemList[] array = Resources.FindObjectsOfTypeAll<SpawnSystemList>();
		foreach (SpawnSystemList val in array)
		{
			foreach (SpawnData spawner in val.m_spawners)
			{
				if (Object.op_Implicit((Object)(object)spawner.m_prefab) && (ContainsCI(((Object)spawner.m_prefab).name, "troll") || ContainsCI(((Object)spawner.m_prefab).name, "gammel")))
				{
					sb.AppendLine($"  SpawnSystemList '{((Object)val).name}': name='{spawner.m_name}' prefab={((Object)spawner.m_prefab).name} biome={spawner.m_biome} area={spawner.m_biomeArea} " + $"enabled={spawner.m_enabled} chance={F(spawner.m_spawnChance)} interval={F(spawner.m_spawnInterval)} maxSpawned={spawner.m_maxSpawned} " + $"group={spawner.m_groupSizeMin}-{spawner.m_groupSizeMax} night={spawner.m_spawnAtNight} day={spawner.m_spawnAtDay} " + $"levels={spawner.m_minLevel}-{spawner.m_maxLevel} globalKey='{spawner.m_requiredGlobalKey}' huntPlayer={spawner.m_huntPlayer}");
				}
			}
		}
		CreatureSpawner[] array2 = Resources.FindObjectsOfTypeAll<CreatureSpawner>();
		foreach (CreatureSpawner val2 in array2)
		{
			if (Object.op_Implicit((Object)(object)val2.m_creaturePrefab) && (ContainsCI(((Object)val2.m_creaturePrefab).name, "troll") || ContainsCI(((Object)val2.m_creaturePrefab).name, "gammel")))
			{
				sb.AppendLine($"  CreatureSpawner on '{GetPath(((Component)val2).transform)}': prefab={((Object)val2.m_creaturePrefab).name} levels={val2.m_minLevel}-{val2.m_maxLevel}");
			}
		}
		sb.AppendLine("  (Location prefabs are soft-referenced and usually not loaded at the main menu, so CreatureSpawners in locations may be missing here.)");
		sb.AppendLine();
	}

	private static void DumpPrefab(DumpContext ctx, GameObject prefab, bool includeRenderers)
	{
		ctx.Dumped.Add(prefab);
		GameObject currentRoot = ctx.CurrentRoot;
		ctx.CurrentRoot = prefab;
		DumpGameObject(ctx, prefab.transform, 0, includeRenderers);
		ctx.CurrentRoot = currentRoot;
	}

	private static void DumpGameObject(DumpContext ctx, Transform t, int indent, bool includeRenderers)
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Expected O, but got Unknown
		StringBuilder sb = ctx.Sb;
		string text = new string(' ', indent * 2);
		GameObject gameObject = ((Component)t).gameObject;
		sb.AppendLine($"{text}+ {((Object)gameObject).name}  (activeSelf={gameObject.activeSelf}, layer={LayerMask.LayerToName(gameObject.layer)}({gameObject.layer}), tag={gameObject.tag})");
		sb.AppendLine(text + "    localPos=" + V(t.localPosition) + " localRot=" + V(t.localEulerAngles) + " localScale=" + V(t.localScale));
		Component[] components = gameObject.GetComponents<Component>();
		foreach (Component val in components)
		{
			if (!Object.op_Implicit((Object)(object)val))
			{
				sb.AppendLine(text + "  * <missing script>");
			}
			else if (!(val is Transform))
			{
				sb.AppendLine(text + "  * " + ((object)val).GetType().FullName);
				string pad = text + "      ";
				DumpBuiltinComponent(ctx, val, pad, includeRenderers);
				if (val is MonoBehaviour)
				{
					DumpFields(ctx, val, ((object)val).GetType(), pad, 0, follow: false, "");
				}
			}
		}
		foreach (Transform item in t)
		{
			Transform t2 = item;
			DumpGameObject(ctx, t2, indent + 1, includeRenderers);
		}
	}

	private static void DumpBuiltinComponent(DumpContext ctx, Component c, string pad, bool includeRenderers)
	{
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0472: Unknown result type (might be due to invalid IL or missing references)
		//IL_0477: Unknown result type (might be due to invalid IL or missing references)
		//IL_0487: Unknown result type (might be due to invalid IL or missing references)
		//IL_048c: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder sb = ctx.Sb;
		SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((c is SkinnedMeshRenderer) ? c : null);
		if (val == null)
		{
			MeshRenderer val2 = (MeshRenderer)(object)((c is MeshRenderer) ? c : null);
			if (val2 == null)
			{
				Renderer val3 = (Renderer)(object)((c is Renderer) ? c : null);
				if (val3 == null)
				{
					MeshFilter val4 = (MeshFilter)(object)((c is MeshFilter) ? c : null);
					if (val4 == null)
					{
						CapsuleCollider val5 = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null);
						if (val5 == null)
						{
							SphereCollider val6 = (SphereCollider)(object)((c is SphereCollider) ? c : null);
							if (val6 == null)
							{
								BoxCollider val7 = (BoxCollider)(object)((c is BoxCollider) ? c : null);
								if (val7 == null)
								{
									MeshCollider val8 = (MeshCollider)(object)((c is MeshCollider) ? c : null);
									if (val8 == null)
									{
										Rigidbody val9 = (Rigidbody)(object)((c is Rigidbody) ? c : null);
										if (val9 == null)
										{
											Animator val10 = (Animator)(object)((c is Animator) ? c : null);
											if (val10 == null)
											{
												LODGroup val11 = (LODGroup)(object)((c is LODGroup) ? c : null);
												if (val11 == null)
												{
													ParticleSystem val12 = (ParticleSystem)(object)((c is ParticleSystem) ? c : null);
													if (val12 != null)
													{
														MainModule main = val12.main;
														object arg = ((MainModule)(ref main)).playOnAwake;
														main = val12.main;
														sb.AppendLine($"{pad}playOnAwake={arg} loop={((MainModule)(ref main)).loop}");
													}
													return;
												}
												LOD[] lODs = val11.GetLODs();
												for (int i = 0; i < lODs.Length; i++)
												{
													sb.AppendLine(string.Format("{0}LOD{1}: screenHeight={2} renderers=[{3}]", pad, i, F(lODs[i].screenRelativeTransitionHeight), string.Join(", ", lODs[i].renderers.Select(Name))));
												}
											}
											else
											{
												sb.AppendLine($"{pad}controller={Name((Object)(object)val10.runtimeAnimatorController)} avatar={Name((Object)(object)val10.avatar)} applyRootMotion={val10.applyRootMotion}");
											}
										}
										else
										{
											sb.AppendLine($"{pad}mass={F(val9.mass)} kinematic={val9.isKinematic} gravity={val9.useGravity}");
										}
									}
									else
									{
										sb.AppendLine($"{pad}trigger={((Collider)val8).isTrigger} convex={val8.convex} mesh={Name((Object)(object)val8.sharedMesh)}");
									}
								}
								else
								{
									sb.AppendLine($"{pad}trigger={((Collider)val7).isTrigger} center={V(val7.center)} size={V(val7.size)}");
								}
							}
							else
							{
								sb.AppendLine($"{pad}trigger={((Collider)val6).isTrigger} center={V(val6.center)} radius={F(val6.radius)}");
							}
						}
						else
						{
							sb.AppendLine($"{pad}trigger={((Collider)val5).isTrigger} center={V(val5.center)} radius={F(val5.radius)} height={F(val5.height)} dir={val5.direction}");
						}
					}
					else
					{
						sb.AppendLine($"{pad}mesh={Name((Object)(object)val4.sharedMesh)} verts={(Object.op_Implicit((Object)(object)val4.sharedMesh) ? val4.sharedMesh.vertexCount : 0)}");
					}
				}
				else
				{
					sb.AppendLine($"{pad}enabled={val3.enabled}");
					if (includeRenderers)
					{
						DumpMaterials(sb, val3, pad);
					}
				}
			}
			else
			{
				sb.AppendLine($"{pad}enabled={((Renderer)val2).enabled} shadowCasting={((Renderer)val2).shadowCastingMode}");
				if (includeRenderers)
				{
					DumpMaterials(sb, (Renderer)(object)val2, pad);
				}
			}
		}
		else
		{
			string text = $"{pad}enabled={((Renderer)val).enabled} mesh={Name((Object)(object)val.sharedMesh)} verts={(Object.op_Implicit((Object)(object)val.sharedMesh) ? val.sharedMesh.vertexCount : 0)} ";
			object arg2 = (Object.op_Implicit((Object)(object)val.sharedMesh) ? val.sharedMesh.subMeshCount : 0);
			string arg3 = Name((Object)(object)val.rootBone);
			Transform[] bones = val.bones;
			sb.AppendLine(text + $"subMeshes={arg2} rootBone={arg3} bones={((bones != null) ? bones.Length : 0)}");
			if (includeRenderers)
			{
				DumpMaterials(sb, (Renderer)(object)val, pad);
			}
		}
	}

	private static void DumpMaterials(StringBuilder sb, Renderer r, string pad)
	{
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Expected I4, but got Unknown
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		Material[] sharedMaterials = r.sharedMaterials;
		for (int i = 0; i < sharedMaterials.Length; i++)
		{
			Material val = sharedMaterials[i];
			if (!Object.op_Implicit((Object)(object)val))
			{
				sb.AppendLine($"{pad}material[{i}] = null");
				continue;
			}
			Shader shader = val.shader;
			sb.AppendLine(string.Format("{0}material[{1}] = '{2}' shader='{3}' renderQueue={4}", pad, i, ((Object)val).name, Object.op_Implicit((Object)(object)shader) ? ((Object)shader).name : "null", val.renderQueue));
			sb.AppendLine(pad + "  keywords=[" + string.Join(", ", val.shaderKeywords) + "]");
			if (!Object.op_Implicit((Object)(object)shader))
			{
				continue;
			}
			int propertyCount = shader.GetPropertyCount();
			for (int j = 0; j < propertyCount; j++)
			{
				string propertyName = shader.GetPropertyName(j);
				int propertyNameId = shader.GetPropertyNameId(j);
				ShaderPropertyType propertyType = shader.GetPropertyType(j);
				string text;
				switch ((int)propertyType)
				{
				case 0:
					text = ((object)val.GetColor(propertyNameId)/*cast due to .constrained prefix*/).ToString();
					break;
				case 1:
					text = ((object)val.GetVector(propertyNameId)/*cast due to .constrained prefix*/).ToString();
					break;
				case 4:
				{
					Texture texture = val.GetTexture(propertyNameId);
					text = (Object.op_Implicit((Object)(object)texture) ? $"'{((Object)texture).name}' ({texture.width}x{texture.height}) scale={val.GetTextureScale(propertyNameId)} offset={val.GetTextureOffset(propertyNameId)}" : "null");
					break;
				}
				case 5:
					text = val.GetInteger(propertyNameId).ToString(Inv);
					break;
				default:
					text = F(val.GetFloat(propertyNameId));
					break;
				}
				sb.AppendLine($"{pad}  {propertyName} ({propertyType}, \"{shader.GetPropertyDescription(j)}\") = {text}");
			}
		}
	}

	private static void DumpHumanoidItems(DumpContext ctx, GameObject go)
	{
		Humanoid component = go.GetComponent<Humanoid>();
		if (!Object.op_Implicit((Object)(object)component))
		{
			return;
		}
		List<(string field, GameObject item)> items = new List<(string, GameObject)>();
		Add("m_defaultItems", component.m_defaultItems);
		Add("m_randomWeapon", component.m_randomWeapon);
		Add("m_randomArmor", component.m_randomArmor);
		Add("m_randomShield", component.m_randomShield);
		if (component.m_randomSets != null)
		{
			for (int i = 0; i < component.m_randomSets.Length; i++)
			{
				Add($"m_randomSets[{i}]", component.m_randomSets[i]?.m_items);
			}
		}
		ctx.Sb.AppendLine();
		ctx.Sb.AppendLine("----- Humanoid items of " + ((Object)go).name + " (attacks/damage live here) -----");
		foreach (var (text, val) in items)
		{
			ctx.Sb.AppendLine("  [" + text + "] " + ((Object)val).name);
			ItemDrop component2 = val.GetComponent<ItemDrop>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				DumpFields(ctx, component2, ((object)component2).GetType(), "      ", 0, follow: false, "");
			}
		}
		void Add(string field, IEnumerable<GameObject> list)
		{
			if (list != null)
			{
				items.AddRange(from item in list
					where Object.op_Implicit((Object)(object)item)
					select (field: field, i: item));
			}
		}
	}

	private static void DumpFields(DumpContext ctx, object obj, Type type, string pad, int depth, bool follow, string path)
	{
		foreach (FieldInfo field in GetSerializedFields(type))
		{
			object value;
			try
			{
				value = field.GetValue(obj);
			}
			catch (Exception ex)
			{
				ctx.Sb.AppendLine(pad + field.Name + " = <error " + ex.GetType().Name + ">");
				continue;
			}
			bool follow2 = follow || DeathChainFieldHints.Any((string h) => ContainsCI(field.Name, h));
			DumpValue(ctx, field.Name, value, field.FieldType, pad, depth, follow2, path + "." + field.Name);
		}
	}

	private static void DumpValue(DumpContext ctx, string label, object value, Type declaredType, string pad, int depth, bool follow, string path)
	{
		StringBuilder sb = ctx.Sb;
		if (value == null)
		{
			sb.AppendLine(pad + label + " = null");
			return;
		}
		Object val = (Object)((value is Object) ? value : null);
		if (val != null)
		{
			if (!Object.op_Implicit(val))
			{
				sb.AppendLine(pad + label + " = null");
				return;
			}
			sb.AppendLine(pad + label + " = " + Name(val) + " (" + ((object)val).GetType().Name + ")");
			if (follow)
			{
				EnqueueLinked(ctx, val, path);
			}
			return;
		}
		Type type = value.GetType();
		if (type.IsPrimitive || type.IsEnum || value is string || value is decimal)
		{
			sb.AppendLine(pad + label + " = " + FormatScalar(value));
		}
		else if (type.Namespace == "UnityEngine")
		{
			sb.AppendLine($"{pad}{label} = {value}");
		}
		else if (value is IList list)
		{
			sb.AppendLine($"{pad}{label} = [{list.Count}]");
			if (depth < 7)
			{
				for (int i = 0; i < list.Count && i < 64; i++)
				{
					DumpValue(ctx, $"[{i}]", list[i], null, pad + "  ", depth + 1, follow, $"{path}[{i}]");
				}
				if (list.Count > 64)
				{
					sb.AppendLine($"{pad}  ... {list.Count - 64} more");
				}
			}
		}
		else if (depth >= 7)
		{
			sb.AppendLine(pad + label + " = " + type.Name + " {...}");
		}
		else
		{
			sb.AppendLine(pad + label + " = " + type.Name);
			DumpFields(ctx, value, type, pad + "  ", depth + 1, follow, path);
		}
	}

	private static void EnqueueLinked(DumpContext ctx, Object uo, string path)
	{
		object obj = ((uo is GameObject) ? uo : null);
		if (obj == null)
		{
			Object obj2 = ((uo is Component) ? uo : null);
			obj = ((obj2 != null) ? ((Component)obj2).gameObject : null);
		}
		GameObject val = (GameObject)obj;
		if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val.transform.parent != (Object)null) && !((Object)(object)val == (Object)(object)ctx.CurrentRoot) && !ctx.Dumped.Contains(val) && ctx.CurrentLinkDepth < 3)
		{
			ctx.LinkedQueue.Enqueue((val, ((Object)ctx.CurrentRoot).name + path, ctx.CurrentLinkDepth + 1));
		}
	}

	private static IEnumerable<FieldInfo> GetSerializedFields(Type type)
	{
		List<Type> list = new List<Type>();
		Type type2 = type;
		while (type2 != null && type2 != typeof(MonoBehaviour) && type2 != typeof(object))
		{
			list.Add(type2);
			type2 = type2.BaseType;
		}
		list.Reverse();
		foreach (Type item in list)
		{
			FieldInfo[] fields = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsDefined(typeof(NonSerializedAttribute), inherit: false) && !fieldInfo.Name.Contains("<") && (fieldInfo.IsPublic || fieldInfo.IsDefined(typeof(SerializeField), inherit: false)))
				{
					yield return fieldInfo;
				}
			}
		}
	}

	private static void Section(StringBuilder sb, string title)
	{
		sb.AppendLine(new string('=', 100));
		sb.AppendLine(title);
		sb.AppendLine(new string('=', 100));
	}

	private static string GetPath(Transform t)
	{
		List<string> list = new List<string>();
		while (Object.op_Implicit((Object)(object)t))
		{
			list.Add(((Object)t).name);
			t = t.parent;
		}
		list.Reverse();
		return string.Join("/", list);
	}

	private static string GameVersionString()
	{
		return Version.GetVersionString(false);
	}

	private static string DisplayName(GameObject go)
	{
		Character component = go.GetComponent<Character>();
		if (!Object.op_Implicit((Object)(object)component) || Localization.instance == null)
		{
			return "";
		}
		return Localization.instance.Localize(component.m_name);
	}

	private static bool ContainsCI(string s, string sub)
	{
		if (s != null)
		{
			return s.IndexOf(sub, StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}

	private static string Name(Object o)
	{
		if (!Object.op_Implicit(o))
		{
			return "null";
		}
		return "'" + o.name + "'";
	}

	private static string F(float f)
	{
		return f.ToString("0.####", Inv);
	}

	private static string V(Vector3 v)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		return "(" + F(v.x) + ", " + F(v.y) + ", " + F(v.z) + ")";
	}

	private static string FormatScalar(object value)
	{
		if (!(value is float f))
		{
			if (!(value is string text))
			{
				return Convert.ToString(value, Inv);
			}
			return "\"" + text + "\"";
		}
		return F(f);
	}
}
internal static class SpawnPatches
{
	[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
	private static class SpawnSystem_Spawn
	{
		private static void Prefix(ref SpawnData critter, Vector3 spawnPoint, bool eventSpawner)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			LastSpawnSwapped = false;
			if (eventSpawner || !Object.op_Implicit((Object)(object)critter.m_prefab) || ((Object)critter.m_prefab).name != "Troll" || (int)Heightmap.FindBiome(spawnPoint) != 8)
			{
				return;
			}
			GameObject prefab = ForestTrollCreature.Prefab;
			if (Object.op_Implicit((Object)(object)prefab) && !(Random.Range(0f, 100f) >= ForestGammeltroll.SpawnChance.Value))
			{
				SpawnData val = critter.Clone();
				val.m_prefab = prefab;
				if (!ForestGammeltroll.AllowStars.Value)
				{
					val.m_maxLevel = 1;
				}
				critter = val;
				LastSpawnSwapped = true;
				Logger.LogInfo((object)($"Spawn swap: Troll -> {((Object)prefab).name} at {spawnPoint:F0} " + $"(zone {ZoneSystem.GetZone(spawnPoint)}, chance {ForestGammeltroll.SpawnChance.Value}%)"));
			}
		}
	}

	private const string TrollPrefabName = "Troll";

	public static bool LastSpawnSwapped { get; private set; }
}
internal static class StarLevelSystemCompat
{
	public const string PluginGUID = "MidnightsFX.StarLevelSystem";

	private const string ColorizeMethod = "StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects";

	public static void Apply(Harmony harmony)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Expected O, but got Unknown
		if (Chainloader.PluginInfos.ContainsKey("MidnightsFX.StarLevelSystem"))
		{
			MethodInfo methodInfo = AccessTools.Method("StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Logger.LogWarning((object)"Star Level System is installed but StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects was not found; starred Forest Gammeltrolls may be recoloured");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(StarLevelSystemCompat), "SkipForestTroll", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Logger.LogInfo((object)"Star Level System detected: starred Forest Gammeltrolls keep their normal colours");
		}
	}

	private static bool SkipForestTroll(GameObject cgo)
	{
		if (Object.op_Implicit((Object)(object)cgo))
		{
			return !ForestTrollCreature.IsForestTroll(cgo.GetComponent<Character>());
		}
		return true;
	}
}
internal class TestSpawnCommand : ConsoleCommand
{
	private const int MaxCount = 50;

	public override string Name => "fgt_testspawn";

	public override string Help => $"[count] Spawn Trolls through the Black Forest open-world spawn path (max {50}); each rolls the swap chance";

	public override bool IsCheat => true;

	public override void Run(string[] args, Terminal context)
	{
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: 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_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Invalid comparison between Unknown and I4
		Player player = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		int result;
		int num = ((args.Length == 0 || !int.TryParse(args[0], out result)) ? 1 : Mathf.Clamp(result, 1, 50));
		SpawnSystem val = (from s in (AccessTools.Field(typeof(SpawnSystem), "m_instances")?.GetValue(null) as List<SpawnSystem>)?.Where((SpawnSystem s) => Object.op_Implicit((Object)(object)s))
			orderby Vector3.Distance(((Component)s).transform.position, ((Component)player).transform.position)
			select s).FirstOrDefault();
		SpawnData val2 = val?.m_spawnLists.SelectMany((SpawnSystemList l) => l.m_spawners).FirstOrDefault((Func<SpawnData, bool>)((SpawnData s) => Object.op_Implicit((Object)(object)s.m_prefab) && ((Object)s.m_prefab).name == "Troll"));
		if (val2 == null)
		{
			if (context != null)
			{
				context.AddString("No SpawnSystem with a Troll entry found near you");
			}
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(SpawnSystem), "Spawn", (Type[])null, (Type[])null);
		int num2 = 0;
		for (int num3 = 0; num3 < num; num3++)
		{
			Vector2 val3 = Random.insideUnitCircle * 10f;
			Vector3 val4 = ((Component)player).transform.position + ((Component)player).transform.forward * 30f + new Vector3(val3.x, 0f, val3.y);
			val4.y = ZoneSystem.instance.GetGroundHeight(val4) + 0.5f;
			methodInfo.Invoke(val, new object[3] { val2, val4, false });
			Biome val5 = Heightmap.FindBiome(val4);
			if (SpawnPatches.LastSpawnSwapped)
			{
				num2++;
			}
			if (context != null)
			{
				context.AddString($"  #{num3 + 1} at {val4:F0} in {val5}: " + (SpawnPatches.LastSpawnSwapped ? "Forest Gammeltroll" : "Troll") + (((int)val5 != 8) ? " (not Black Forest, never swapped)" : ""));
			}
		}
		if (context != null)
		{
			context.AddString($"Ran {num} Troll spawn(s) through SpawnSystem.Spawn: {num2} swapped " + $"(SpawnChance {ForestGammeltroll.SpawnChance.Value}%)");
		}
	}
}