Decompiled source of Afrek Expanded Skills v1.0.0

plugins/Afrek.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Afrek.Core;
using Afrek.Dev;
using Afrek.Feats;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Afrek
{
	public static class Cfg
	{
		public static ConfigEntry<float> GainRate;

		private static readonly Dictionary<SkillId, ConfigEntry<bool>> s_enabled = new Dictionary<SkillId, ConfigEntry<bool>>();

		public static void Bind(ConfigFile c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			GainRate = c.Bind<float>("1 - General", "SkillGainRate", 1f, new ConfigDescription("How fast all Afrek skills grow (1 = as designed, 0 = not at all). The world's own skill gain setting applies on top.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), new object[1] { val }));
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				s_enabled[skillDef.Id] = c.Bind<bool>("2 - Skills", skillDef.Id.ToString(), true, new ConfigDescription("The " + skillDef.NameEn + " skill. Off: it neither grows nor helps (the level stays in the save). Switch it off if another mod already adds such a skill.", (AcceptableValueBase)null, new object[1] { val }));
			}
		}

		public static bool Enabled(SkillId id)
		{
			if (s_enabled.TryGetValue(id, out var value))
			{
				return value.Value;
			}
			return false;
		}

		internal static void SetEnabledForTest(SkillId id, bool on)
		{
			if (s_enabled.TryGetValue(id, out var value))
			{
				value.Value = on;
			}
		}
	}
	public static class Lang
	{
		private static readonly (string key, string en, string de)[] Texts = new(string, string, string)[21]
		{
			("afrek_msg_thread_saved", "Cut thriftily: {0} {1} left over", "Sparsam zugeschnitten: {0} {1} übrig"),
			("afrek_weather_turns", "The weather is turning", "Das Wetter schlägt um"),
			("afrek_weather_soon", "Soon: {0}", "Bald: {0}"),
			("afrek_weather_stays", "Stays: {0}", "Bleibt: {0}"),
			("afrek_weather_then", "then {0}", "dann {0}"),
			("afrek_minutes", "{0} min", "{0} Min."),
			("afrek_weather_clear", "clear", "klar"),
			("afrek_weather_rain", "rain", "Regen"),
			("afrek_weather_lightrain", "drizzle", "Nieselregen"),
			("afrek_weather_swamprain", "swamp rain", "Sumpfregen"),
			("afrek_weather_mist", "mist", "Nebel"),
			("afrek_weather_forestmist", "forest mist", "Waldnebel"),
			("afrek_weather_haze", "haze", "Dunst"),
			("afrek_weather_thunder", "thunderstorm", "Gewitter"),
			("afrek_weather_snow", "snow", "Schnee"),
			("afrek_weather_snowstorm", "blizzard", "Schneesturm"),
			("afrek_weather_ashrain", "ash rain", "Ascheregen"),
			("afrek_weather_cinderrain", "cinder rain", "Glutregen"),
			("afrek_weather_ashstorm", "ash storm", "Aschesturm"),
			("afrek_weather_seastorm", "sea storm", "Seesturm"),
			("afrek_home", "Home: {0}", "Heimweg: {0}")
		};

		public static void Register()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
			(string, string, string)[] texts = Texts;
			for (int i = 0; i < texts.Length; i++)
			{
				(string, string, string) tuple = texts[i];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				string item3 = tuple.Item3;
				dictionary[item] = item2;
				dictionary2[item] = item3;
			}
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				dictionary[skillDef.Token] = skillDef.NameEn;
				dictionary2[skillDef.Token] = skillDef.NameDe;
				dictionary[skillDef.Token + "_desc"] = skillDef.DescEn;
				dictionary2[skillDef.Token + "_desc"] = skillDef.DescDe;
			}
			string text = "English";
			localization.AddTranslation(ref text, dictionary);
			text = "German";
			localization.AddTranslation(ref text, dictionary2);
		}

		public static string T(string token, params object[] args)
		{
			string text = ((Localization.instance != null) ? Localization.instance.Localize("$" + token) : token);
			if (args == null || args.Length == 0)
			{
				return text;
			}
			try
			{
				return string.Format(text, args);
			}
			catch (FormatException)
			{
				return text;
			}
		}
	}
	[BepInPlugin("zap.afrek", "Afrek", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class AfrekPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "zap.afrek";

		public const string PluginName = "Afrek";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		public static AfrekPlugin Instance { get; private set; }

		public static string PluginDir { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static string AssetPath(string fileName)
		{
			return Path.Combine(PluginDir ?? "", "Assets", fileName);
		}

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			PluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			Cfg.Bind(((BaseUnityPlugin)this).Config);
			Lang.Register();
			AfrekSkills.Register();
			Insight.Register();
			_harmony = new Harmony("zap.afrek");
			_harmony.PatchAll(typeof(AfrekPlugin).Assembly);
			SelfTest.TryStart(((Component)this).gameObject);
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace Afrek.Feats
{
	public static class AfrekSkills
	{
		private static readonly Dictionary<SkillId, SkillType> s_types = new Dictionary<SkillId, SkillType>();

		private static readonly Dictionary<SkillId, SkillConfig> s_configs = new Dictionary<SkillId, SkillConfig>();

		public static void Register()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				SkillConfig val = new SkillConfig
				{
					Identifier = skillDef.Identifier,
					Name = "$" + skillDef.Token,
					Description = "$" + skillDef.Token + "_desc",
					IncreaseStep = 1f
				};
				s_types[skillDef.Id] = SkillManager.Instance.AddSkill(val);
				s_configs[skillDef.Id] = val;
			}
			PrefabManager.OnVanillaPrefabsAvailable += SetIcons;
		}

		private static void SetIcons()
		{
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				Sprite val = null;
				string[] icon = skillDef.Icon;
				foreach (string text in icon)
				{
					GameObject prefab = PrefabManager.Instance.GetPrefab(text);
					if (!((Object)(object)prefab == (Object)null))
					{
						ItemDrop component = prefab.GetComponent<ItemDrop>();
						if ((Object)(object)component != (Object)null && component.m_itemData.m_shared.m_icons != null && component.m_itemData.m_shared.m_icons.Length != 0)
						{
							val = component.m_itemData.m_shared.m_icons[0];
						}
						else if ((Object)(object)prefab.GetComponent<Piece>() != (Object)null)
						{
							val = prefab.GetComponent<Piece>().m_icon;
						}
						if ((Object)(object)val != (Object)null)
						{
							break;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					AfrekPlugin.Log.LogWarning((object)("no icon for skill " + skillDef.Key + " (" + string.Join(", ", skillDef.Icon) + ")"));
				}
				s_configs[skillDef.Id].Icon = val;
			}
		}

		public static Sprite Icon(SkillId id)
		{
			if (!s_configs.TryGetValue(id, out var value))
			{
				return null;
			}
			return value.Icon;
		}

		public static SkillType Type(SkillId id)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!s_types.TryGetValue(id, out var value))
			{
				return (SkillType)0;
			}
			return value;
		}

		public static bool Enabled(SkillId id)
		{
			return Cfg.Enabled(id);
		}

		public static float Factor(Player p, SkillId id)
		{
			//IL_0018: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null || !Enabled(id))
			{
				return 0f;
			}
			SkillType val = Type(id);
			if ((int)val != 0)
			{
				return ((Character)p).GetSkillFactor(val);
			}
			return 0f;
		}

		public static float LocalFactor(SkillId id)
		{
			return Factor(Player.m_localPlayer, id);
		}

		public static void Raise(Player p, SkillId id, float points)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			if ((Object)(object)p == (Object)null || !Enabled(id))
			{
				return;
			}
			SkillType val = Type(id);
			float num = points * Cfg.GainRate.Value;
			if ((int)val != 0 && !(num <= 0f))
			{
				int num2 = 0;
				while (num > 0f && num2 < 1000)
				{
					float num3 = Mathf.Min(num, 0.5f);
					((Character)p).RaiseSkill(val, num3);
					num -= num3;
					num2++;
				}
			}
		}

		public static void RaiseLocal(SkillId id, float points)
		{
			Raise(Player.m_localPlayer, id, points);
		}

		public static float Level(Player p, SkillId id)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			SkillType val = Type(id);
			if (!((Object)(object)p == (Object)null) && (int)val != 0)
			{
				return ((Character)p).GetSkills().GetSkillLevel(val);
			}
			return 0f;
		}
	}
	internal static class Animals
	{
		[HarmonyPatch(typeof(Tameable), "DecreaseRemainingTime")]
		private static class TameFaster
		{
			private static void Prefix(Tameable __instance, ref float time)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: 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)
				if (Cfg.Enabled(SkillId.AnimalHandling) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsOwner())
				{
					Vector3 position = ((Component)__instance).transform.position;
					time *= 1f + 1f * Shared.Best(position, 60f, SkillId.AnimalHandling);
					Shared.RaiseNearby(position, 60f, SkillId.AnimalHandling, 0.15f);
				}
			}
		}

		[HarmonyPatch(typeof(Tameable), "Tame")]
		private static class TameDone
		{
			private static void Prefix(Tameable __instance, out bool __state)
			{
				__state = (Object)(object)__instance.m_character != (Object)null && !__instance.m_character.IsTamed();
			}

			private static void Postfix(Tameable __instance, bool __state)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				if (__state && !((Object)(object)__instance.m_character == (Object)null) && __instance.m_character.IsTamed())
				{
					Shared.Raise(Player.GetClosestPlayer(((Component)__instance).transform.position, 30f), SkillId.AnimalHandling, 10f);
				}
			}
		}

		[HarmonyPatch(typeof(Tameable), "Interact")]
		private static class Pet
		{
			private static void Postfix(Tameable __instance, Humanoid user, bool hold, bool alt)
			{
				//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_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				if (hold || alt || (Object)(object)user != (Object)(object)Player.m_localPlayer || (Object)(object)__instance.m_character == (Object)null || !__instance.m_character.IsTamed())
				{
					return;
				}
				ZDOID zDOID = __instance.m_character.GetZDOID();
				if (!s_lastPet.TryGetValue(zDOID, out var value) || !(Time.time - value < 60f))
				{
					s_lastPet[zDOID] = Time.time;
					if (Time.time - s_lastPetPoints >= 30f)
					{
						s_lastPetPoints = Time.time;
						AfrekSkills.Raise(Player.m_localPlayer, SkillId.AnimalHandling, 0.5f);
					}
					float num = __instance.m_character.GetMaxHealth() * Tuning.Chance(0.1f, AfrekSkills.LocalFactor(SkillId.AnimalHandling));
					Character character = __instance.m_character;
					if (num >= 1f && character.GetHealth() < character.GetMaxHealth())
					{
						character.Heal(num, true);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Procreation), "Procreate")]
		private static class Breed
		{
			private struct State
			{
				public float Chance;

				public float Duration;

				public float Skill;

				public bool Due;
			}

			private static void Prefix(Procreation __instance, out State __state)
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				__state = new State
				{
					Chance = __instance.m_pregnancyChance,
					Duration = __instance.m_pregnancyDuration
				};
				if (!((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner() && Cfg.Enabled(SkillId.Breeding))
				{
					float num = (__state.Skill = Shared.Best(((Component)__instance).transform.position, 30f, SkillId.Breeding));
					__instance.m_pregnancyChance = __state.Chance * (1f - 0.5f * num);
					__instance.m_pregnancyDuration = Tuning.Shorter(__state.Duration, 0.4f, num);
					__state.Due = __instance.IsPregnant() && __instance.IsDue();
				}
			}

			private static void Postfix(Procreation __instance, State __state)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				if (__state.Due && !__instance.IsPregnant())
				{
					Vector3 position = ((Component)__instance).transform.position;
					if ((Object)(object)__instance.m_offspring != (Object)null && (Object)(object)__instance.m_offspring.GetComponent<Character>() != (Object)null)
					{
						Shared.RaiseNearby(position, 30f, SkillId.Breeding, 5f);
					}
					ZDO zDO = __instance.m_nview.GetZDO();
					if (zDO.GetBool(KeyTwin, false))
					{
						zDO.Set(KeyTwin, false);
					}
					else if (!(Random.value >= Tuning.Chance(0.15f, __state.Skill)) && SpawnSystem.GetNrOfInstances(__instance.m_myPrefab, position, __instance.m_totalCheckRange, false, false) + SpawnSystem.GetNrOfInstances(__instance.m_offspringPrefab, position, __instance.m_totalCheckRange, false, false) < __instance.m_maxCreatures)
					{
						zDO.Set(KeyTwin, true);
						long ticks = ZNet.instance.GetTime().AddSeconds(0f - __state.Duration - 1f).Ticks;
						zDO.Set(ZDOVars.s_pregnant, ticks);
					}
				}
			}

			private static void Finalizer(Procreation __instance, State __state)
			{
				__instance.m_pregnancyChance = __state.Chance;
				__instance.m_pregnancyDuration = __state.Duration;
			}
		}

		[HarmonyPatch(typeof(Growup), "GrowUpdate")]
		private static class GrowFaster
		{
			private static void Prefix(Growup __instance, out float __state)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: 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_008f: Unknown result type (might be due to invalid IL or missing references)
				__state = __instance.m_growTime;
				if (Cfg.Enabled(SkillId.Breeding) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner())
				{
					Vector3 position = ((Component)__instance).transform.position;
					float f = Shared.Best(position, 30f, SkillId.Breeding);
					__instance.m_growTime = Tuning.Shorter(__state, 0.3f, f);
					if ((Object)(object)__instance.m_baseAI != (Object)null && __instance.m_baseAI.GetTimeSinceSpawned().TotalSeconds > (double)__instance.m_growTime)
					{
						Shared.RaiseNearby(position, 30f, SkillId.Breeding, 2f);
					}
				}
			}

			private static void Finalizer(Growup __instance, float __state)
			{
				__instance.m_growTime = __state;
			}
		}

		[HarmonyPatch(typeof(EggGrow), "GrowUpdate")]
		private static class HatchFaster
		{
			private static void Prefix(EggGrow __instance, out float __state)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
				__state = __instance.m_growTime;
				if (Cfg.Enabled(SkillId.Breeding) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner())
				{
					Vector3 position = ((Component)__instance).transform.position;
					float f = Shared.Best(position, 30f, SkillId.Breeding);
					__instance.m_growTime = Tuning.Shorter(__state, 0.3f, f);
					float num = __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_growStart, 0f);
					if (num > 0f && ZNet.instance.GetTimeSeconds() > (double)(num + __instance.m_growTime) && __instance.CanGrow() && (Object)(object)__instance.m_item != (Object)null && __instance.m_item.m_itemData.m_stack == 1)
					{
						Shared.RaiseNearby(position, 30f, SkillId.Breeding, 3f);
					}
				}
			}

			private static void Finalizer(EggGrow __instance, float __state)
			{
				__instance.m_growTime = __state;
			}
		}

		[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
		private static class MoreMeat
		{
			private static void Postfix(CharacterDrop __instance, List<KeyValuePair<GameObject, int>> __result)
			{
				Character character = __instance.m_character;
				if (__result == null || (Object)(object)character == (Object)null || !Cfg.Enabled(SkillId.Butchery) || character.m_lastHit == null)
				{
					return;
				}
				Character attacker = character.m_lastHit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				float f = Shared.Factor(val, SkillId.Butchery);
				bool flag = false;
				for (int i = 0; i < __result.Count; i++)
				{
					KeyValuePair<GameObject, int> keyValuePair = __result[i];
					if (!((Object)(object)keyValuePair.Key == (Object)null) && IsButcherable(((Object)keyValuePair.Key).name))
					{
						flag = true;
						int num = Tuning.MoreAmount(keyValuePair.Value, 0.3f, f, Random.value);
						if (num != keyValuePair.Value)
						{
							__result[i] = new KeyValuePair<GameObject, int>(keyValuePair.Key, num);
						}
					}
				}
				if (flag)
				{
					Shared.Raise(val, SkillId.Butchery, 2f * (float)Mathf.Max(1, character.GetLevel()));
				}
			}
		}

		private const float TameRange = 60f;

		private static readonly Dictionary<ZDOID, float> s_lastPet = new Dictionary<ZDOID, float>();

		private static float s_lastPetPoints = -1000f;

		private static readonly int KeyTwin = StringExtensionMethods.GetStableHashCode("afrek_twin");

		private static readonly HashSet<string> Butcherable = new HashSet<string>
		{
			"RawMeat", "DeerMeat", "NeckTail", "WolfMeat", "LoxMeat", "HareMeat", "ChickenMeat", "SerpentMeat", "BugMeat", "AsksvinMeat",
			"VoltureMeat", "BjornMeat", "MooseMeat", "SealBlubber", "BoneMawSerpentMeat", "LeatherScraps", "DeerHide", "TrollHide", "WolfPelt", "LoxPelt",
			"ScaleHide", "AskHide", "BjornHide", "MooseHide", "SealHide", "SerpentScale", "Feathers"
		};

		internal static bool IsButcherable(string prefab)
		{
			if (prefab != null)
			{
				return Butcherable.Contains(prefab);
			}
			return false;
		}
	}
	internal static class Crafting
	{
		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		private static class Craft
		{
			private static void Prefix(InventoryGui __instance)
			{
				s_recipe = __instance.m_craftRecipe;
				s_multi = ((!__instance.m_multiCrafting) ? 1 : __instance.m_multiCraftAmount);
				s_consumed = false;
			}

			private static void Postfix(Player player)
			{
				Recipe s_recipe = Crafting.s_recipe;
				if (!((Object)(object)s_recipe == (Object)null) && !((Object)(object)s_recipe.m_item == (Object)null) && s_consumed && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && IsMeadBase(((Object)s_recipe.m_item).name))
				{
					AfrekSkills.Raise(player, SkillId.Brewing, 3f * (float)s_multi);
				}
			}

			private static void Finalizer()
			{
				s_recipe = null;
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static class Thrifty
		{
			private static void Postfix(Player __instance, Requirement[] requirements, int qualityLevel, int multiplier)
			{
				if ((Object)(object)s_recipe == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				s_consumed = true;
				float f = AfrekSkills.Factor(__instance, SkillId.Spinning);
				bool flag = false;
				foreach (Requirement val in requirements)
				{
					if ((Object)(object)val.m_resItem == (Object)null || !IsCloth(((Object)val.m_resItem).name))
					{
						continue;
					}
					int num = val.GetAmount(qualityLevel) * Mathf.Max(1, multiplier);
					if (num > 0)
					{
						flag = true;
						int num2 = Tuning.MoreAmount(num, 0.25f, f, Random.value) - num;
						if (num2 > 0)
						{
							((Humanoid)__instance).GetInventory().AddItem(((Component)val.m_resItem).gameObject, num2);
							((Character)__instance).Message((MessageType)1, Lang.T("afrek_msg_thread_saved", num2, Localization.instance.Localize(val.m_resItem.m_itemData.m_shared.m_name)), 0, (Sprite)null, false);
						}
					}
				}
				if (flag)
				{
					AfrekSkills.Raise(__instance, SkillId.Spinning, 3f * (float)Mathf.Max(1, multiplier));
				}
			}
		}

		private static Recipe s_recipe;

		private static int s_multi;

		private static bool s_consumed;

		internal static bool IsMeadBase(string prefab)
		{
			if (prefab != null)
			{
				if (!prefab.StartsWith("MeadBase"))
				{
					return prefab == "BarleyWineBase";
				}
				return true;
			}
			return false;
		}

		internal static bool IsCloth(string prefab)
		{
			if (!(prefab == "LinenThread"))
			{
				return prefab?.StartsWith("Jute") ?? false;
			}
			return true;
		}
	}
	internal static class Insight
	{
		public enum Kind
		{
			Weather,
			Home
		}

		public class SE_AfrekInsight : StatusEffect
		{
			public Kind m_kind;

			public override void UpdateStatusEffect(float dt)
			{
				((StatusEffect)this).UpdateStatusEffect(dt);
				base.m_name = Label(m_kind);
			}

			public override string GetIconText()
			{
				return Detail(m_kind);
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Keep
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)s_weather == (Object)null))
				{
					Insight.s_timer += Time.deltaTime;
					if (!(Insight.s_timer < 1f))
					{
						float s_timer = Insight.s_timer;
						Insight.s_timer = 0f;
						UpdateWeather(__instance, AfrekSkills.Factor(__instance, SkillId.WeatherLore), s_timer);
						UpdateHome(__instance, AfrekSkills.Factor(__instance, SkillId.Navigation));
						Show(__instance, s_weather, s_weatherLabel.Length > 0, SkillId.WeatherLore);
						Show(__instance, s_home, s_homeLabel.Length > 0, SkillId.Navigation);
					}
				}
			}
		}

		private static SE_AfrekInsight s_weather;

		private static SE_AfrekInsight s_home;

		private static string s_weatherLabel = "";

		private static string s_weatherDetail = "";

		private static string s_homeLabel = "";

		private static string s_homeDetail = "";

		private static readonly Dictionary<string, string> WeatherTokens = new Dictionary<string, string>
		{
			{ "Clear", "clear" },
			{ "Heath clear", "clear" },
			{ "Mistlands_clear", "clear" },
			{ "Twilight_Clear", "clear" },
			{ "Rain", "rain" },
			{ "Mistlands_rain", "rain" },
			{ "LightRain", "lightrain" },
			{ "SwampRain", "swamprain" },
			{ "Misty", "mist" },
			{ "DeepForest Mist", "forestmist" },
			{ "Ashlands_misty", "haze" },
			{ "ThunderStorm", "thunder" },
			{ "Mistlands_thunder", "thunder" },
			{ "Snow", "snow" },
			{ "Twilight_Snow", "snow" },
			{ "SnowStorm", "snowstorm" },
			{ "Twilight_SnowStorm", "snowstorm" },
			{ "Ashlands_ashrain", "ashrain" },
			{ "Ashlands_CinderRain", "cinderrain" },
			{ "Ashlands_storm", "ashstorm" },
			{ "Ashlands_SeaStorm", "seastorm" }
		};

		private static long s_lastPeriod = -1L;

		private static string s_lastEnv;

		private static readonly string[] CompassEn = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" };

		private static readonly string[] CompassDe = new string[8] { "N", "NO", "O", "SO", "S", "SW", "W", "NW" };

		private static float s_timer;

		public static void Register()
		{
			s_weather = Make(Kind.Weather, "AfrekWeatherSense");
			s_home = Make(Kind.Home, "AfrekHomeSense");
		}

		private static SE_AfrekInsight Make(Kind kind, string name)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			SE_AfrekInsight sE_AfrekInsight = ScriptableObject.CreateInstance<SE_AfrekInsight>();
			((Object)sE_AfrekInsight).name = name;
			sE_AfrekInsight.m_kind = kind;
			((StatusEffect)sE_AfrekInsight).m_name = name;
			((StatusEffect)sE_AfrekInsight).m_ttl = 0f;
			ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)sE_AfrekInsight, false));
			return sE_AfrekInsight;
		}

		private static string Label(Kind k)
		{
			if (k != Kind.Weather)
			{
				return s_homeLabel;
			}
			return s_weatherLabel;
		}

		private static string Detail(Kind k)
		{
			if (k != Kind.Weather)
			{
				return s_homeDetail;
			}
			return s_weatherDetail;
		}

		internal static EnvSetup Predict(long period, BiomeSector biome, Vector3 at)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			EnvMan instance = EnvMan.instance;
			State state = Random.state;
			try
			{
				Random.InitState((int)period);
				List<EnvEntry> availableEnvironments = instance.GetAvailableEnvironments(biome);
				if (availableEnvironments == null || availableEnvironments.Count == 0)
				{
					return null;
				}
				availableEnvironments = new List<EnvEntry>(availableEnvironments);
				EnvSetup result = instance.SelectWeightedEnvironment(availableEnvironments);
				bool flag = WorldGenerator.IsAshlands(at.x, at.z);
				bool flag2 = WorldGenerator.IsDeepnorth(at.x, at.y);
				foreach (EnvEntry item in availableEnvironments)
				{
					if (item.m_ashlandsOverride && flag)
					{
						result = item.m_env;
					}
					if (item.m_deepnorthOverride && flag2)
					{
						result = item.m_env;
					}
				}
				return result;
			}
			finally
			{
				Random.state = state;
			}
		}

		internal static string WeatherName(EnvSetup e)
		{
			if (e == null)
			{
				return "?";
			}
			if (!WeatherTokens.TryGetValue(e.m_name, out var value))
			{
				return e.m_name.Replace('_', ' ');
			}
			return Lang.T("afrek_weather_" + value);
		}

		private static void UpdateWeather(Player p, float f, float dt)
		{
			//IL_0076: 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_007b: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			s_weatherLabel = (s_weatherDetail = "");
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || instance.GetEnvironmentOverride() != null)
			{
				return;
			}
			long num = (long)ZNet.instance.GetTimeSeconds();
			long environmentDuration = instance.m_environmentDuration;
			if (environmentDuration <= 0)
			{
				return;
			}
			long num2 = num / environmentDuration;
			Vector3 at = (((Object)(object)Utils.GetMainCamera() != (Object)null) ? ((Component)Utils.GetMainCamera()).transform.position : ((Component)p).transform.position);
			BiomeSector currentBiome = instance.m_currentBiome;
			EnvSetup val = Predict(num2, currentBiome, at);
			EnvSetup val2 = Predict(num2 + 1, currentBiome, at);
			bool flag = !p.InShelter() && !((Character)p).InInterior();
			if (flag)
			{
				AfrekSkills.Raise(p, SkillId.WeatherLore, 0.025f * dt);
			}
			if (s_lastPeriod >= 0 && num2 != s_lastPeriod && flag && val != null && val.m_name != s_lastEnv)
			{
				AfrekSkills.Raise(p, SkillId.WeatherLore, 3f);
			}
			s_lastPeriod = num2;
			s_lastEnv = val?.m_name;
			float num3 = (num2 + 1) * environmentDuration - num;
			if (f <= 0f || val2 == null || num3 > Tuning.ForecastLead(f))
			{
				return;
			}
			bool flag2 = val == null || val.m_name != val2.m_name;
			int num4 = Mathf.Max(1, Mathf.CeilToInt(num3 / 60f));
			if (f < 0.2f)
			{
				if (flag2)
				{
					s_weatherLabel = Lang.T("afrek_weather_turns");
				}
				return;
			}
			s_weatherLabel = Lang.T(flag2 ? "afrek_weather_soon" : "afrek_weather_stays", WeatherName(val2));
			s_weatherDetail = Lang.T("afrek_minutes", num4);
			if (f >= 0.75f)
			{
				EnvSetup val3 = Predict(num2 + 2, currentBiome, at);
				if (val3 != null && val3.m_name != val2.m_name)
				{
					s_weatherLabel = s_weatherLabel + " · " + Lang.T("afrek_weather_then", WeatherName(val3));
				}
			}
		}

		internal static bool Home(out Vector3 home)
		{
			//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_0033: 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)
			home = Vector3.zero;
			PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
			if (val != null && val.HaveCustomSpawnPoint())
			{
				home = val.GetCustomSpawnPoint();
				return true;
			}
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				return ZoneSystem.instance.GetLocationIcon(Game.instance.m_StartLocation, ref home);
			}
			return false;
		}

		private static void UpdateHome(Player p, float f)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			s_homeLabel = (s_homeDetail = "");
			if (f <= 0f || (Object)(object)Ship.GetLocalShip() == (Object)null || !Home(out var home))
			{
				return;
			}
			Vector3 val = home - ((Component)p).transform.position;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (!(magnitude < 50f))
			{
				float num = (Mathf.Atan2(val.x, val.z) * 57.29578f + 360f) % 360f;
				string text = ((Localization.instance != null && Localization.instance.GetSelectedLanguage() == "German") ? CompassDe : CompassEn)[Mathf.RoundToInt(num / 45f) % 8];
				if (f >= 0.75f)
				{
					s_homeLabel = Lang.T("afrek_home", $"{text} {Mathf.RoundToInt(num)}°");
				}
				else
				{
					s_homeLabel = Lang.T("afrek_home", text);
				}
				if (f >= 0.75f)
				{
					s_homeDetail = (magnitude / 1000f).ToString("0.0") + " km";
				}
				else if (f >= 0.4f)
				{
					s_homeDetail = "~" + Mathf.Max(1, Mathf.RoundToInt(magnitude / 1000f)) + " km";
				}
			}
		}

		private static void Show(Player p, SE_AfrekInsight se, bool on, SkillId icon)
		{
			SEMan sEMan = ((Character)p).GetSEMan();
			bool flag = sEMan.HaveStatusEffect(((StatusEffect)se).NameHash());
			if (on && !flag)
			{
				((StatusEffect)se).m_icon = AfrekSkills.Icon(icon);
				sEMan.AddStatusEffect((StatusEffect)(object)se, false, 0, 0f, (short)(-1));
			}
			else if (!on && flag)
			{
				sEMan.RemoveStatusEffect(((StatusEffect)se).NameHash(), true);
			}
		}
	}
	internal static class Living
	{
		[HarmonyPatch(typeof(Player), "AddKnownText")]
		private static class NewLore
		{
			private static void Prefix(Player __instance, string label, out bool __state)
			{
				__state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !__instance.m_knownTexts.ContainsKey(label);
			}

			private static void Postfix(Player __instance, bool __state)
			{
				if (__state)
				{
					AfrekSkills.Raise(__instance, SkillId.RuneLore, 15f);
				}
			}
		}

		[HarmonyPatch(typeof(RuneStone), "Interact")]
		private static class ReadStone
		{
			private static void Postfix(RuneStone __instance, Humanoid character, bool hold)
			{
				//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_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: 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_0067: 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)
				Player val = (Player)(object)((character is Player) ? character : null);
				if (!hold && !((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !string.IsNullOrEmpty(__instance.m_label))
				{
					Vector3 position = ((Component)__instance).transform.position;
					Vector3Int key = default(Vector3Int);
					((Vector3Int)(ref key))..ctor(Mathf.RoundToInt(position.x), Mathf.RoundToInt(position.y), Mathf.RoundToInt(position.z));
					if (!s_lastRead.TryGetValue(key, out var value) || !(Time.time - value < 600f))
					{
						s_lastRead[key] = Time.time;
						AfrekSkills.Raise(val, SkillId.RuneLore, 2f);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Vegvisir), "Interact")]
		private static class ReadVegvisir
		{
			private static void Postfix(Vegvisir __instance, Humanoid character, bool hold)
			{
				//IL_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				Player val = (Player)(object)((character is Player) ? character : null);
				if (!hold && !((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					Vector3 position = ((Component)__instance).transform.position;
					string text = Mathf.RoundToInt(position.x) + "," + Mathf.RoundToInt(position.z);
					val.m_customData.TryGetValue("afrek_vegvisirs", out var value);
					value = value ?? "";
					if (!value.Split(new char[1] { ';' }).Contains(text))
					{
						val.m_customData["afrek_vegvisirs"] = ((value.Length == 0) ? text : (value + ";" + text));
						AfrekSkills.Raise(val, SkillId.RuneLore, 10f);
					}
				}
			}
		}

		[HarmonyPatch(typeof(SleepText), "ShowDreamText")]
		private static class Dream
		{
			private static void Postfix(SleepText __instance)
			{
				if ((Object)(object)__instance.m_dreamField != (Object)null && ((Behaviour)__instance.m_dreamField).enabled && !string.IsNullOrEmpty(__instance.m_dreamField.text))
				{
					AfrekSkills.RaiseLocal(SkillId.RuneLore, 5f);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "RaiseSkill")]
		private static class LearnFaster
		{
			private static void Prefix(Player __instance, ref float value)
			{
				if (s_raising || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				s_raising = true;
				try
				{
					value *= 1f + 0.1f * AfrekSkills.Factor(__instance, SkillId.RuneLore);
				}
				finally
				{
					s_raising = false;
				}
			}
		}

		[HarmonyPatch(typeof(SE_Rested), "UpdateTTL")]
		private static class LongerRested
		{
			private static void Prefix(SE_Rested __instance, out float __state)
			{
				__state = ((StatusEffect)__instance).m_ttl;
			}

			private static void Postfix(SE_Rested __instance, float __state)
			{
				if (!((Object)(object)((StatusEffect)__instance).m_character != (Object)(object)Player.m_localPlayer) && !Mathf.Approximately(((StatusEffect)__instance).m_ttl, __state))
				{
					((StatusEffect)__instance).m_ttl = ((StatusEffect)__instance).m_ttl * (1f + 0.4f * AfrekSkills.LocalFactor(SkillId.CampLife));
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SetSleeping")]
		private static class Slept
		{
			private static void Prefix(Player __instance, bool sleep, out bool __state)
			{
				__state = __instance.m_sleeping && !sleep;
			}

			private static void Postfix(Player __instance, bool __state)
			{
				if (__state && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					AfrekSkills.Raise(__instance, SkillId.CampLife, 5f);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Resting
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				Living.s_restTimer += Time.deltaTime;
				if (!(Living.s_restTimer < 5f))
				{
					float s_restTimer = Living.s_restTimer;
					Living.s_restTimer = 0f;
					if (((Character)__instance).GetSEMan().HaveStatusEffect(SEMan.s_statusEffectResting))
					{
						AfrekSkills.Raise(__instance, SkillId.CampLife, 1f / 60f * s_restTimer);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeItem")]
		private static class Drink
		{
			private static void Prefix(Player __instance, ItemData item, out int __state)
			{
				__state = -1;
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && item != null)
				{
					if ((Object)(object)item.m_shared.m_consumeStatusEffect != (Object)null && item.m_shared.m_food <= 0f && IsMead(item))
					{
						s_drinking = item;
					}
					__state = ((Humanoid)__instance).GetInventory().CountItems(item.m_shared.m_name, -1, true);
				}
			}

			private static void Postfix(Player __instance, ItemData item, bool __result, int __state)
			{
				bool flag = s_drinking == item;
				s_drinking = null;
				if (__result && __state >= 0 && item != null && flag && item.m_shared.m_consumeStatusEffect.m_ttl >= 60f)
				{
					AfrekSkills.Raise(__instance, SkillId.Drinking, 3f);
				}
			}
		}

		[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
		{
			typeof(StatusEffect),
			typeof(bool),
			typeof(int),
			typeof(float),
			typeof(short)
		})]
		private static class MeadTime
		{
			private static void Postfix(SEMan __instance, StatusEffect __result)
			{
				if (s_drinking == null || (Object)(object)__result == (Object)null || (Object)(object)__instance.m_character != (Object)(object)Player.m_localPlayer || __result.m_ttl < 60f)
				{
					return;
				}
				float num = AfrekSkills.LocalFactor(SkillId.Drinking);
				if (!(num <= 0f))
				{
					if (IsDraught(__result))
					{
						__result.m_ttl *= 1f - 0.3f * num;
					}
					else
					{
						__result.m_ttl *= 1f + 0.3f * num;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "EatFood")]
		private static class Eat
		{
			private static void Postfix(Player __instance, ItemData item, bool __result)
			{
				if (!__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || item == null)
				{
					return;
				}
				FoodKind foodKind = KindOf(item);
				if (foodKind == FoodKind.None)
				{
					return;
				}
				float num = LoverFactor(__instance, foodKind);
				foreach (Food food in __instance.m_foods)
				{
					if (food.m_item != null && food.m_item.m_shared.m_name == item.m_shared.m_name && num > 0f)
					{
						food.m_time = item.m_shared.m_foodBurnTime * (1f + 0.25f * num);
					}
				}
				SharedData shared = item.m_shared;
				float points = Tuning.MealPoints(shared.m_food, shared.m_foodStamina, shared.m_foodEitr, FoodKinds.Count(foodKind));
				FoodKind[] singles = Singles;
				foreach (FoodKind foodKind2 in singles)
				{
					if ((foodKind & foodKind2) != FoodKind.None)
					{
						AfrekSkills.Raise(__instance, SkillOf(foodKind2), points);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static class MoreFromFood
		{
			private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
			{
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				foreach (Food food in __instance.m_foods)
				{
					if (food.m_item != null)
					{
						float num = 0.1f * LoverFactor(__instance, KindOf(food.m_item));
						if (!(num <= 0f))
						{
							hp += food.m_health * num;
							stamina += food.m_stamina * num;
							eitr += food.m_eitr * num;
						}
					}
				}
			}
		}

		private static readonly Dictionary<Vector3Int, float> s_lastRead = new Dictionary<Vector3Int, float>();

		private const string VegvisirKey = "afrek_vegvisirs";

		private static bool s_raising;

		private static float s_restTimer;

		private static ItemData s_drinking;

		private static readonly Dictionary<string, FoodKind> s_kinds = new Dictionary<string, FoodKind>();

		private static readonly FoodKind[] Singles = new FoodKind[5]
		{
			FoodKind.Meat,
			FoodKind.Fish,
			FoodKind.Greens,
			FoodKind.Bread,
			FoodKind.Stew
		};

		internal static bool IsMead(ItemData item)
		{
			string text = (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "");
			if (!text.StartsWith("Mead"))
			{
				return text.StartsWith("BarleyWine");
			}
			return true;
		}

		internal static bool IsDraught(StatusEffect se)
		{
			SE_Stats val = (SE_Stats)(object)((se is SE_Stats) ? se : null);
			if (val != null && !string.IsNullOrEmpty(se.m_category))
			{
				if (!(val.m_healthOverTime > 0f) && !(val.m_staminaOverTime > 0f))
				{
					return val.m_eitrOverTime > 0f;
				}
				return true;
			}
			return false;
		}

		internal static FoodKind KindOf(ItemData item)
		{
			if (item == null)
			{
				return FoodKind.None;
			}
			string token = item.m_shared.m_name;
			if (s_kinds.TryGetValue(token, out var value))
			{
				return value;
			}
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null);
			if (text == null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				GameObject? obj = ((IEnumerable<GameObject>)ObjectDB.instance.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => (Object)(object)g != (Object)null && g.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name == token));
				text = ((obj != null) ? ((Object)obj).name : null);
			}
			if (text == null)
			{
				return FoodKind.None;
			}
			value = FoodKinds.Of(text, (from q in (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetRecipe(item) : null)?.m_resources
				where (Object)(object)q.m_resItem != (Object)null
				select ((Object)q.m_resItem).name));
			s_kinds[token] = value;
			return value;
		}

		internal static SkillId SkillOf(FoodKind single)
		{
			return single switch
			{
				FoodKind.Meat => SkillId.MeatLover, 
				FoodKind.Fish => SkillId.FishLover, 
				FoodKind.Bread => SkillId.BreadLover, 
				FoodKind.Stew => SkillId.StewLover, 
				_ => SkillId.GreensLover, 
			};
		}

		internal static float LoverFactor(Player p, FoodKind kind)
		{
			float num = 0f;
			FoodKind[] singles = Singles;
			foreach (FoodKind foodKind in singles)
			{
				if ((kind & foodKind) != FoodKind.None)
				{
					num = Mathf.Max(num, AfrekSkills.Factor(p, SkillOf(foodKind)));
				}
			}
			return num;
		}
	}
	internal static class Sea
	{
		[HarmonyPatch(typeof(Ship), "GetSailForce")]
		private static class SailForce
		{
			private static void Postfix(Ship __instance, ref Vector3 __result)
			{
				//IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references)
				float num = Shared.Factor(Captain(__instance), SkillId.Seamanship);
				if (num > 0f)
				{
					__result *= 1f + 0.15f * num;
				}
			}
		}

		[HarmonyPatch(typeof(Ship), "CustomFixedUpdate")]
		private static class Oars
		{
			private static void Prefix(Ship __instance, out float __state)
			{
				__state = __instance.m_backwardForce;
				if (!((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsOwner())
				{
					float num = Shared.Factor(Captain(__instance), SkillId.Seamanship);
					if (num > 0f)
					{
						__instance.m_backwardForce = __state * (1f + 0.25f * num);
					}
				}
			}

			private static void Finalizer(Ship __instance, float __state)
			{
				__instance.m_backwardForce = __state;
			}
		}

		[HarmonyPatch(typeof(Ship), "ApplyControlls")]
		private static class Rudder
		{
			private static void Prefix(Ship __instance, out float __state)
			{
				__state = __instance.m_rudderSpeed;
				float num = AfrekSkills.LocalFactor(SkillId.Seamanship);
				if (num > 0f)
				{
					__instance.m_rudderSpeed = __state * (1f + 0.3f * num);
				}
			}

			private static void Finalizer(Ship __instance, float __state)
			{
				__instance.m_rudderSpeed = __state;
			}
		}

		[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
		private static class Hull
		{
			private static void Prefix(WearNTear __instance, HitData hit)
			{
				if (hit == null || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsOwner())
				{
					return;
				}
				Ship component = ((Component)__instance).GetComponent<Ship>();
				if (!((Object)(object)component == (Object)null))
				{
					float num = Shared.Factor(Captain(component), SkillId.Seamanship);
					if (num > 0f)
					{
						((DamageTypes)(ref hit.m_damage)).Modify(1f - 0.35f * num);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Ship), "GetWindAngleFactor")]
		private static class WindAngle
		{
			private static bool Prefix(Ship __instance, ref float __result)
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)EnvMan.instance == (Object)null)
				{
					return true;
				}
				Player val = Captain(__instance);
				float num = (((Object)(object)val == (Object)(object)Player.m_localPlayer) ? AfrekSkills.LocalFactor(SkillId.Navigation) : Shared.Factor(val, SkillId.Navigation));
				if (num <= 0f)
				{
					return true;
				}
				float dotWindBow = Vector3.Dot(EnvMan.instance.GetWindDir(), -((Component)__instance).transform.forward);
				__result = Tuning.WindAngleFactor(dotWindBow, num);
				return false;
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Helm
		{
			private static void Postfix(Player __instance)
			{
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				Ship controlledShip = __instance.GetControlledShip();
				if ((Object)(object)controlledShip == (Object)null)
				{
					Sea.s_helmTimer = 0f;
					return;
				}
				Sea.s_helmTimer += Time.deltaTime;
				if (Sea.s_helmTimer < 1f)
				{
					return;
				}
				float s_helmTimer = Sea.s_helmTimer;
				Sea.s_helmTimer = 0f;
				float num = Mathf.Abs(controlledShip.GetSpeed());
				if (controlledShip.IsSailUp() && num > 1f)
				{
					AfrekSkills.Raise(__instance, SkillId.Seamanship, 0.08f * Mathf.Min(1f, num / 6f) * s_helmTimer);
					if (Vector3.Dot(EnvMan.instance.GetWindDir(), -((Component)controlledShip).transform.forward) > 0.5f && controlledShip.GetWindAngleFactor() > 0.05f)
					{
						AfrekSkills.Raise(__instance, SkillId.Navigation, 0.05f * s_helmTimer);
					}
				}
				else if (num > 0.5f)
				{
					AfrekSkills.Raise(__instance, SkillId.Seamanship, 0.04f * s_helmTimer);
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
		private static class Sight
		{
			private static void Prefix(Minimap __instance, Player player, out float __state)
			{
				__state = __instance.m_exploreRadius;
				s_newPixels = 0;
				s_exploring = (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer;
				if (s_exploring)
				{
					bool flag = (Object)(object)Ship.GetLocalShip() != (Object)null;
					float num = AfrekSkills.Factor(player, flag ? SkillId.Navigation : SkillId.Cartography);
					if (num > 0f)
					{
						__instance.m_exploreRadius = __state * (1f + (flag ? 0.5f : 0.5f) * num);
					}
				}
			}

			private static void Finalizer(Minimap __instance, float __state)
			{
				__instance.m_exploreRadius = __state;
			}

			private static void Postfix(Minimap __instance, Player player, float __state)
			{
				bool s_exploring = Sea.s_exploring;
				Sea.s_exploring = false;
				if (s_exploring && s_newPixels != 0)
				{
					bool flag = (Object)(object)Ship.GetLocalShip() != (Object)null;
					AfrekSkills.Raise(player, flag ? SkillId.Navigation : SkillId.Cartography, (float)s_newPixels * (flag ? 0.01f : 0.03f));
					s_newPixels = 0;
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
		{
			typeof(int),
			typeof(int)
		})]
		private static class NewPixel
		{
			private static void Postfix(bool __result)
			{
				if (__result && s_exploring)
				{
					s_newPixels++;
				}
			}
		}

		private static float s_helmTimer;

		private static int s_newPixels;

		private static bool s_exploring;

		internal static Player Captain(Ship s)
		{
			ShipControlls val = (((Object)(object)s != (Object)null) ? s.m_shipControlls : null);
			if (!((Object)(object)val != (Object)null) || !val.HaveValidUser())
			{
				return null;
			}
			return Player.GetPlayer(val.GetUser());
		}
	}
	public static class Shared
	{
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static class RegisterRpc
		{
			private static void Postfix()
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.Register<int, float>("Afrek_Raise", (Action<long, int, float>)RPC_Raise);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class PublishSkills
		{
			private static void Postfix(Player __instance)
			{
				Publish(__instance, force: false);
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class PublishOnSpawn
		{
			private static void Postfix(Player __instance)
			{
				Publish(__instance, force: true);
			}
		}

		public const string RaiseRpc = "Afrek_Raise";

		private static int[] s_keys;

		private static readonly float[] s_sent = new float[SkillTable.All.Length];

		private static float s_nextPublish;

		private static int Key(SkillId id)
		{
			if (s_keys == null)
			{
				s_keys = new int[SkillTable.All.Length];
				SkillDef[] all = SkillTable.All;
				foreach (SkillDef skillDef in all)
				{
					s_keys[(int)skillDef.Id] = StringExtensionMethods.GetStableHashCode("afrek_" + skillDef.Key);
				}
			}
			return s_keys[(int)id];
		}

		public static float Factor(Player p, SkillId id)
		{
			if ((Object)(object)p == (Object)null || !Cfg.Enabled(id))
			{
				return 0f;
			}
			if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				return AfrekSkills.Factor(p, id);
			}
			ZDO val = (((Object)(object)((Character)p).m_nview != (Object)null && ((Character)p).m_nview.IsValid()) ? ((Character)p).m_nview.GetZDO() : null);
			if (val == null)
			{
				return 0f;
			}
			return Mathf.Clamp01(val.GetFloat(Key(id), 0f));
		}

		public static float Best(Vector3 at, float range, SkillId id, out Player who)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			who = null;
			float num = 0f;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead() && !(Vector3.Distance(((Component)allPlayer).transform.position, at) > range))
				{
					float num2 = Factor(allPlayer, id);
					if ((Object)(object)who == (Object)null || num2 > num)
					{
						num = num2;
						who = allPlayer;
					}
				}
			}
			return num;
		}

		public static float Best(Vector3 at, float range, SkillId id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Player who;
			return Best(at, range, id, out who);
		}

		public static Player PlayerOf(long peer)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && (Object)(object)((Character)allPlayer).m_nview != (Object)null && ((Character)allPlayer).m_nview.IsValid() && ((Character)allPlayer).m_nview.GetZDO().GetOwner() == peer)
				{
					return allPlayer;
				}
			}
			return null;
		}

		public static void Raise(Player p, SkillId id, float points)
		{
			if ((Object)(object)p == (Object)null || points <= 0f || !Cfg.Enabled(id))
			{
				return;
			}
			if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				AfrekSkills.Raise(p, id, points);
				return;
			}
			long num = (((Object)(object)((Character)p).m_nview != (Object)null && ((Character)p).m_nview.IsValid()) ? ((Character)p).m_nview.GetZDO().GetOwner() : 0);
			if (num != 0L)
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(num, "Afrek_Raise", new object[2]
					{
						(int)id,
						points
					});
				}
			}
		}

		public static void RaiseNearby(Vector3 at, float range, SkillId id, float points)
		{
			//IL_002c: 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)
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && !((Character)allPlayer).IsDead() && Vector3.Distance(((Component)allPlayer).transform.position, at) <= range)
				{
					Raise(allPlayer, id, points);
				}
			}
		}

		private static void RPC_Raise(long sender, int id, float points)
		{
			if (id >= 0 && id < SkillTable.All.Length && !(points <= 0f) && !(points > 50f))
			{
				AfrekSkills.Raise(Player.m_localPlayer, (SkillId)id, points);
			}
		}

		internal static void Publish(Player p, bool force)
		{
			if ((Object)(object)p == (Object)null || (Object)(object)p != (Object)(object)Player.m_localPlayer || (Object)(object)((Character)p).m_nview == (Object)null || !((Character)p).m_nview.IsValid() || (!force && Time.time < s_nextPublish))
			{
				return;
			}
			s_nextPublish = Time.time + 5f;
			ZDO zDO = ((Character)p).m_nview.GetZDO();
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				float num = AfrekSkills.Factor(p, skillDef.Id);
				if (force || !Mathf.Approximately(num, s_sent[(int)skillDef.Id]))
				{
					s_sent[(int)skillDef.Id] = num;
					zDO.Set(Key(skillDef.Id), num);
				}
			}
		}
	}
	public enum SkillId
	{
		Brewing,
		Smelting,
		Spinning,
		AnimalHandling,
		Breeding,
		Beekeeping,
		Butchery,
		Seamanship,
		Navigation,
		Cartography,
		WeatherLore,
		Trading,
		RuneLore,
		CampLife,
		Drinking,
		MeatLover,
		FishLover,
		GreensLover,
		BreadLover,
		StewLover
	}
	public sealed class SkillDef
	{
		public SkillId Id;

		public string Key;

		public string NameEn;

		public string NameDe;

		public string DescEn;

		public string DescDe;

		public string[] Icon;

		public string Identifier => "zap.afrek." + Key;

		public string Token => "afrek_skill_" + Key;
	}
	public static class SkillTable
	{
		public static readonly SkillDef[] All = new SkillDef[20]
		{
			new SkillDef
			{
				Id = SkillId.Brewing,
				Key = "brewing",
				NameEn = "Brewing",
				NameDe = "Brauen",
				DescEn = "Mead bases at the cauldron, barrels in the fermenter. Faster fermenting, now and then a bottle more.",
				DescDe = "Metgrundlagen am Kessel, Fässer im Gärbottich. Schneller gären, ab und zu eine Flasche mehr.",
				Icon = new string[2] { "fermenter", "MeadTasty" }
			},
			new SkillDef
			{
				Id = SkillId.Smelting,
				Key = "smelting",
				NameEn = "Smelting",
				NameDe = "Hüttenkunde",
				DescEn = "Smelter, charcoal kiln, blast furnace and eitr refinery. Faster work, less fuel, now and then a bar more.",
				DescDe = "Schmelzofen, Meiler, Hochofen und Eitr-Raffinerie. Schneller, weniger Brennstoff, ab und zu ein Barren mehr.",
				Icon = new string[2] { "Iron", "Copper" }
			},
			new SkillDef
			{
				Id = SkillId.Spinning,
				Key = "spinning",
				NameEn = "Spinning & Weaving",
				NameDe = "Spinnen & Weben",
				DescEn = "The spinning wheel and everything sewn from linen and jute. Faster spinning, a thread more now and then, thrifty weaving.",
				DescDe = "Das Spinnrad und alles aus Leinen und Jute. Schneller spinnen, ab und zu ein Faden mehr, sparsam weben.",
				Icon = new string[2] { "LinenThread", "piece_spinningwheel" }
			},
			new SkillDef
			{
				Id = SkillId.AnimalHandling,
				Key = "animalhandling",
				NameEn = "Animal Handling",
				NameDe = "Tierkunde",
				DescEn = "Taming wild beasts and keeping tame ones. Faster taming, and a pat soothes their wounds.",
				DescDe = "Wilde Tiere zähmen und zahme halten. Schneller zähmen, und Streicheln lindert ihre Wunden.",
				Icon = new string[1] { "TrophyBoar" }
			},
			new SkillDef
			{
				Id = SkillId.Breeding,
				Key = "breeding",
				NameEn = "Breeding",
				NameDe = "Züchter",
				DescEn = "Raising young from your tame animals. More matings, shorter pregnancies, quicker growth, now and then twins.",
				DescDe = "Nachwuchs von deinen zahmen Tieren. Mehr Paarungen, kürzere Trächtigkeit, schnelleres Wachsen, ab und zu Zwillinge.",
				Icon = new string[2] { "ChickenEgg", "TrophyHare" }
			},
			new SkillDef
			{
				Id = SkillId.Beekeeping,
				Key = "beekeeping",
				NameEn = "Beekeeping",
				NameDe = "Imkerei",
				DescEn = "Keeping bees. Busier hives and now and then a honey more at the harvest.",
				DescDe = "Bienen halten. Fleißigere Stöcke und bei der Ernte ab und zu ein Honig mehr.",
				Icon = new string[2] { "QueenBee", "Honey" }
			},
			new SkillDef
			{
				Id = SkillId.Butchery,
				Key = "butchery",
				NameEn = "Butchery & Tanning",
				NameDe = "Schlachten & Gerben",
				DescEn = "Cutting up game and taking its hide. More meat, hides and pelts from what you kill.",
				DescDe = "Wild zerlegen und das Fell nehmen. Mehr Fleisch, Häute und Felle von deiner Beute.",
				Icon = new string[2] { "DeerHide", "LeatherScraps" }
			},
			new SkillDef
			{
				Id = SkillId.Seamanship,
				Key = "seamanship",
				NameEn = "Seamanship",
				NameDe = "Seemannschaft",
				DescEn = "Handling a ship at the helm. More speed under sail and oar, a quicker rudder, a hull that takes less damage.",
				DescDe = "Ein Schiff am Ruder führen. Mehr Fahrt unter Segel und Ruder, ein schnelleres Ruder, ein Rumpf, der weniger Schaden nimmt.",
				Icon = new string[2] { "Karve", "VikingShip" }
			},
			new SkillDef
			{
				Id = SkillId.Navigation,
				Key = "navigation",
				NameEn = "Navigation",
				NameDe = "Navigation",
				DescEn = "Reading wind and sea. Sail closer to the wind, see further at sea, and feel the way home.",
				DescDe = "Wind und See lesen. Höher am Wind segeln, auf See weiter sehen und den Weg nach Hause spüren.",
				Icon = new string[2] { "Wishbone", "YagluthDrop" }
			},
			new SkillDef
			{
				Id = SkillId.Cartography,
				Key = "cartography",
				NameEn = "Cartography",
				NameDe = "Kartografie",
				DescEn = "Mapping the land as you walk it. The map uncovers more around you.",
				DescDe = "Das Land kartieren, während du es durchwanderst. Die Karte deckt mehr um dich herum auf.",
				Icon = new string[1] { "piece_cartographytable" }
			},
			new SkillDef
			{
				Id = SkillId.WeatherLore,
				Key = "weatherlore",
				NameEn = "Weather Lore",
				NameDe = "Wetterkunde",
				DescEn = "Reading the sky. You sense what weather comes next, earlier and more surely.",
				DescDe = "Den Himmel lesen. Du ahnst, welches Wetter kommt, früher und sicherer.",
				Icon = new string[2] { "Feathers", "FeatherCape" }
			},
			new SkillDef
			{
				Id = SkillId.Trading,
				Key = "trading",
				NameEn = "Trading",
				NameDe = "Handel",
				DescEn = "Bargaining with traders. Lower prices when you buy, more coins when you sell.",
				DescDe = "Mit Händlern feilschen. Niedrigere Preise beim Kaufen, mehr Münzen beim Verkaufen.",
				Icon = new string[1] { "Coins" }
			},
			new SkillDef
			{
				Id = SkillId.RuneLore,
				Key = "runelore",
				NameEn = "Rune Lore",
				NameDe = "Runenkunde",
				DescEn = "Reading runestones, ravens and dreams. Whoever knows the old lore learns everything a little faster.",
				DescDe = "Runensteine, Raben und Träume lesen. Wer die alte Kunde kennt, lernt alles etwas schneller.",
				Icon = new string[3] { "Vegvisir", "TrophyDraugr", "BoneFragments" }
			},
			new SkillDef
			{
				Id = SkillId.CampLife,
				Key = "camplife",
				NameEn = "Camp Life",
				NameDe = "Lagerleben",
				DescEn = "Resting by the fire and sleeping well. Longer rested, fires that burn longer on your wood.",
				DescDe = "Am Feuer rasten und gut schlafen. Länger ausgeruht, Feuer brennen mit deinem Holz länger.",
				Icon = new string[2] { "fire_pit", "piece_campfire" }
			},
			new SkillDef
			{
				Id = SkillId.Drinking,
				Key = "drinking",
				NameEn = "Hard Drinking",
				NameDe = "Trinkfestigkeit",
				DescEn = "Drinking mead. Lasting meads work longer, healing draughts come back sooner.",
				DescDe = "Met trinken. Anhaltende Mete wirken länger, heilende Tränke sind früher wieder bereit.",
				Icon = new string[2] { "MeadTasty", "MeadHealthMinor" }
			},
			new SkillDef
			{
				Id = SkillId.MeatLover,
				Key = "meatlover",
				NameEn = "Meat Gourmet",
				NameDe = "Fleischgourmet",
				DescEn = "Eating meat dishes. They keep you going longer and give a little more.",
				DescDe = "Fleischgerichte essen. Sie halten länger vor und geben etwas mehr.",
				Icon = new string[1] { "CookedMeat" }
			},
			new SkillDef
			{
				Id = SkillId.FishLover,
				Key = "fishlover",
				NameEn = "Fish Lover",
				NameDe = "Fischliebhaber",
				DescEn = "Eating fish and seafood. They keep you going longer and give a little more.",
				DescDe = "Fisch und Meeresfrüchte essen. Sie halten länger vor und geben etwas mehr.",
				Icon = new string[1] { "FishCooked" }
			},
			new SkillDef
			{
				Id = SkillId.GreensLover,
				Key = "greenslover",
				NameEn = "Fruit & Greens Lover",
				NameDe = "Früchte- & Kräuterfreund",
				DescEn = "Eating berries, mushrooms, roots and salads. They keep you going longer and give a little more.",
				DescDe = "Beeren, Pilze, Wurzeln und Salate essen. Sie halten länger vor und geben etwas mehr.",
				Icon = new string[2] { "Raspberry", "Blueberries" }
			},
			new SkillDef
			{
				Id = SkillId.BreadLover,
				Key = "breadlover",
				NameEn = "Bread & Pastry Lover",
				NameDe = "Brot- & Backwarenliebhaber",
				DescEn = "Eating bread, flatbread, pies and cakes. They keep you going longer and give a little more.",
				DescDe = "Brot, Fladenbrot, Pasteten und Kuchen essen. Sie halten länger vor und geben etwas mehr.",
				Icon = new string[1] { "Bread" }
			},
			new SkillDef
			{
				Id = SkillId.StewLover,
				Key = "stewlover",
				NameEn = "Soup & Stew Lover",
				NameDe = "Suppen- & Eintopfliebhaber",
				DescEn = "Eating soups, stews and porridges. They keep you going longer and give a little more.",
				DescDe = "Suppen, Eintöpfe und Breie essen. Sie halten länger vor und geben etwas mehr.",
				Icon = new string[2] { "TurnipStew", "CarrotSoup" }
			}
		};

		public static SkillDef Get(SkillId id)
		{
			return All[(int)id];
		}
	}
	internal static class Stations
	{
		[HarmonyPatch(typeof(Fermenter), "RPC_AddItem")]
		private static class BrewFill
		{
			private static void Prefix(Fermenter __instance, out bool __state)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Invalid comparison between Unknown and I4
				__state = (int)__instance.GetStatus() == 0;
			}

			private static void Postfix(Fermenter __instance, long sender, bool __state)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				if (__state && __instance.m_nview.IsOwner() && (int)__instance.GetStatus() != 0)
				{
					Player p = Shared.PlayerOf(sender);
					SetStationSkill(__instance.m_nview, Shared.Factor(p, SkillId.Brewing));
				}
			}
		}

		[HarmonyPatch(typeof(Fermenter), "GetFermentationTime")]
		private static class BrewFaster
		{
			private static void Postfix(Fermenter __instance, ref double __result)
			{
				if (!(__result <= 0.0) && Cfg.Enabled(SkillId.Brewing))
				{
					float num = StationSkill(__instance.m_nview);
					if (num > 0f)
					{
						__result /= Tuning.Shorter(1f, 0.3f, num);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Fermenter), "RPC_Tap")]
		private static class BrewTap
		{
			private static void Prefix(Fermenter __instance, out bool __state)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Invalid comparison between Unknown and I4
				__state = __instance.m_nview.IsOwner() && (int)__instance.GetStatus() == 3;
			}

			private static void Postfix(Fermenter __instance, long sender, bool __state)
			{
				if (__state)
				{
					Player p = Shared.PlayerOf(sender);
					float f = Shared.Factor(p, SkillId.Brewing);
					s_extraBottles[__instance] = ((Random.value < Tuning.Chance(0.5f, f)) ? 1 : 0);
					ExtraPlanned += s_extraBottles[__instance];
					SetStationSkill(__instance.m_nview, 0f);
					Shared.Raise(p, SkillId.Brewing, 7f);
				}
			}
		}

		[HarmonyPatch(typeof(Fermenter), "DelayedTap")]
		private static class BrewExtraBottle
		{
			private static void Postfix(Fermenter __instance)
			{
				//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)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				if (!s_extraBottles.TryGetValue(__instance, out var value))
				{
					return;
				}
				s_extraBottles.Remove(__instance);
				ItemConversion itemConversion = __instance.GetItemConversion(__instance.m_delayedTapItem);
				if (itemConversion != null && !((Object)(object)itemConversion.m_to == (Object)null))
				{
					for (int i = 0; i < value; i++)
					{
						ItemDrop.OnCreateNew(Object.Instantiate<ItemDrop>(itemConversion.m_to, __instance.m_outputPoint.position + Vector3.up * 0.5f, Quaternion.identity), false);
						ExtraSpawned++;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Smelter), "RPC_AddOre")]
		private static class SmeltAddOre
		{
			private static void Prefix(Smelter __instance, out int __state)
			{
				__state = (__instance.m_nview.IsOwner() ? __instance.GetQueueSize() : (-1));
			}

			private static void Postfix(Smelter __instance, long sender, int __state)
			{
				if (__state >= 0 && __instance.GetQueueSize() > __state)
				{
					SkillId? skillId = SkillOf(__instance);
					if (skillId.HasValue)
					{
						Player p = Shared.PlayerOf(sender);
						SetStationSkill(__instance.m_nview, Shared.Factor(p, skillId.Value));
						SetFiller(__instance.m_nview, p);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Smelter), "RPC_AddFuel")]
		private static class SmeltAddFuel
		{
			private static void Prefix(Smelter __instance, out float __state)
			{
				__state = (__instance.m_nview.IsOwner() ? __instance.GetFuel() : float.MaxValue);
			}

			private static void Postfix(Smelter __instance, long sender, float __state)
			{
				if (!(__instance.GetFuel() <= __state) && SkillOf(__instance) == SkillId.Smelting && __instance.m_maxOre <= 0)
				{
					Player p = Shared.PlayerOf(sender);
					SetStationSkill(__instance.m_nview, Shared.Factor(p, SkillId.Smelting));
					SetFiller(__instance.m_nview, p);
				}
			}
		}

		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		private static class SmeltFaster
		{
			private static void Prefix(Smelter __instance, out Vector3 __state)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				__state = new Vector3(__instance.m_secPerProduct, 0f, 0f);
				if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
				{
					return;
				}
				SkillId? skillId = SkillOf(__instance);
				if (skillId.HasValue && Cfg.Enabled(skillId.Value))
				{
					float num = StationSkill(__instance.m_nview);
					if (!(num <= 0f))
					{
						__state = new Vector3(__state.x, __instance.GetFuel(), num);
						float cutAt = ((skillId == SkillId.Spinning) ? 0.3f : 0.3f);
						__instance.m_secPerProduct = Tuning.Shorter(__state.x, cutAt, num);
					}
				}
			}

			private static void Postfix(Smelter __instance, Vector3 __state)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				if (!(__state.z <= 0f) && __instance.m_maxFuel > 0)
				{
					float num = __state.y - __instance.GetFuel();
					if (num > 0f)
					{
						__instance.SetFuel(__instance.GetFuel() + num * 0.25f * __state.z);
					}
				}
			}

			private static void Finalizer(Smelter __instance, Vector3 __state)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				__instance.m_secPerProduct = __state.x;
			}
		}

		[HarmonyPatch(typeof(Smelter), "QueueProcessed")]
		private static class SmeltExtra
		{
			private static void Postfix(Smelter __instance, string ore)
			{
				if (s_inExtra)
				{
					return;
				}
				SkillId? skillId = SkillOf(__instance);
				if (!skillId.HasValue || !Cfg.Enabled(skillId.Value))
				{
					return;
				}
				long num = __instance.m_nview.GetZDO().GetLong(KeyFiller, 0L);
				if (num != 0L)
				{
					Shared.Raise(Player.GetPlayer(num), skillId.Value, PointsPerProduct(__instance));
				}
				float num2 = Tuning.Chance((skillId == SkillId.Spinning) ? 0.2f : 0.15f, StationSkill(__instance.m_nview));
				if (Random.value >= num2)
				{
					return;
				}
				s_inExtra = true;
				try
				{
					__instance.QueueProcessed(ore);
				}
				finally
				{
					s_inExtra = false;
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "RPC_Extract")]
		private static class BeeHarvest
		{
			private static void Prefix(Beehive __instance, out int __state)
			{
				__state = ((__instance.m_nview.IsOwner() && IsHive(__instance)) ? __instance.GetHoneyLevel() : 0);
			}

			private static void Postfix(Beehive __instance, long caller, int __state)
			{
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: 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_0077: 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_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				if (__state <= 0)
				{
					return;
				}
				Player p = Shared.PlayerOf(caller);
				float f = Shared.Factor(p, SkillId.Beekeeping);
				SetStationSkill(__instance.m_nview, f);
				Shared.Raise(p, SkillId.Beekeeping, 2f * (float)__state);
				int num = 0;
				for (int i = 0; i < __state; i++)
				{
					if (Random.value < Tuning.Chance(0.4f, f))
					{
						num++;
					}
				}
				for (int j = 0; j < num; j++)
				{
					Vector2 val = Random.insideUnitCircle * 0.5f;
					ItemDrop component = ((Component)Object.Instantiate<ItemDrop>(__instance.m_honeyItem, __instance.m_spawnPoint.position + new Vector3(val.x, 0.25f * (float)(__state + j), val.y), Quaternion.identity)).GetComponent<ItemDrop>();
					if (component != null)
					{
						component.SetStack(Game.instance.ScaleDrops(__instance.m_honeyItem.m_itemData, 1));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "UpdateBees")]
		private static class BeesFaster
		{
			private static void Prefix(Beehive __instance, out float __state)
			{
				__state = __instance.m_secPerUnit;
				if (Cfg.Enabled(SkillId.Beekeeping) && IsHive(__instance))
				{
					float num = StationSkill(__instance.m_nview);
					if (num > 0f)
					{
						__instance.m_secPerUnit = Tuning.Shorter(__state, 0.3f, num);
					}
				}
			}

			private static void Finalizer(Beehive __instance, float __state)
			{
				__instance.m_secPerUnit = __state;
			}
		}

		[HarmonyPatch(typeof(Fireplace), "RPC_AddFuel")]
		private static class FireFuel
		{
			private static void Prefix(Fireplace __instance, out float __state)
			{
				__state = (__instance.m_nview.IsOwner() ? __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f) : float.MaxValue);
			}

			private static void Postfix(Fireplace __instance, long sender, float __state)
			{
				ZDO zDO = __instance.m_nview.GetZDO();
				if (zDO != null && !(zDO.GetFloat(ZDOVars.s_fuel, 0f) <= __state))
				{
					Player p = Shared.PlayerOf(sender);
					Shared.Raise(p, SkillId.CampLife, 0.1f);
					float num = 0.5f * Shared.Factor(p, SkillId.CampLife);
					if (num > 0f)
					{
						zDO.Set(ZDOVars.s_fuel, Mathf.Min(zDO.GetFloat(ZDOVars.s_fuel, 0f) + num, __instance.m_maxFuel));
					}
				}
			}
		}

		private static readonly int KeySkill = StringExtensionMethods.GetStableHashCode("afrek_station_skill");

		private static readonly Dictionary<Fermenter, int> s_extraBottles = new Dictionary<Fermenter, int>();

		internal static int ExtraPlanned;

		internal static int ExtraSpawned;

		private static readonly int KeyFiller = StringExtensionMethods.GetStableHashCode("afrek_station_filler");

		private static bool s_inExtra;

		private static float StationSkill(ZNetView nview)
		{
			if (!((Object)(object)nview != (Object)null) || !nview.IsValid())
			{
				return 0f;
			}
			return Mathf.Clamp01(nview.GetZDO().GetFloat(KeySkill, 0f));
		}

		private static void SetStationSkill(ZNetView nview, float f)
		{
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner() && !Mathf.Approximately(nview.GetZDO().GetFloat(KeySkill, 0f), f))
			{
				nview.GetZDO().Set(KeySkill, f);
			}
		}

		internal static SkillId? SkillOf(Smelter s)
		{
			switch (Utils.GetPrefabName(((Component)s).gameObject))
			{
			case "piece_spinningwheel":
				return SkillId.Spinning;
			case "smelter":
			case "charcoal_kiln":
			case "blastfurnace":
			case "eitrrefinery":
			case "piece_FrostKiln":
				return SkillId.Smelting;
			default:
				return null;
			}
		}

		private static void SetFiller(ZNetView nview, Player p)
		{
			if ((Object)(object)p != (Object)null && (Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner())
			{
				nview.GetZDO().Set(KeyFiller, p.GetPlayerID());
			}
		}

		internal static float PointsPerProduct(Smelter s)
		{
			return Utils.GetPrefabName(((Component)s).gameObject) switch
			{
				"piece_spinningwheel" => 0.4f, 
				"charcoal_kiln" => 0.3f, 
				"piece_FrostKiln" => 0.5f, 
				_ => 0.8f, 
			};
		}

		internal static bool IsHive(Beehive b)
		{
			return Utils.GetPrefabName(((Component)b).gameObject) != "piece_birdnest";
		}
	}
	internal static class Trade
	{
		[HarmonyPatch(typeof(StoreGui), "FillList")]
		private static class PricesInList
		{
			private static void Prefix(StoreGui __instance)
			{
				Enter(__instance);
			}

			private static void Finalizer()
			{
				Exit();
			}
		}

		[HarmonyPatch(typeof(StoreGui), "UpdateBuyButton")]
		private static class PricesForButton
		{
			private static void Prefix(StoreGui __instance)
			{
				Enter(__instance);
			}

			private static void Finalizer()
			{
				Exit();
			}
		}

		[HarmonyPatch(typeof(StoreGui), "BuySelectedItem")]
		private static class Buy
		{
			private static void Prefix(StoreGui __instance, out int __state)
			{
				__state = __instance.GetPlayerCoins();
				Enter(__instance);
			}

			private static void Finalizer()
			{
				Exit();
			}

			private static void Postfix(StoreGui __instance, int __state)
			{
				int num = __state - __instance.GetPlayerCoins();
				if (num > 0)
				{
					AfrekSkills.RaiseLocal(SkillId.Trading, (float)num * 0.1f);
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "SellItem")]
		private static class Sell
		{
			private static void Prefix(StoreGui __instance, out int __state)
			{
				__state = __instance.GetPlayerCoins();
			}

			private static void Postfix(StoreGui __instance, int __state)
			{
				Player localPlayer = Player.m_localPlayer;
				int num = __instance.GetPlayerCoins() - __state;
				if (!((Object)(object)localPlayer == (Object)null) && num > 0)
				{
					int num2 = Tuning.MoreAmount(num, 0.15f, AfrekSkills.LocalFactor(SkillId.Trading), Random.value) - num;
					if (num2 > 0 && (Object)(object)__instance.m_coinPrefab != (Object)null)
					{
						((Humanoid)localPlayer).GetInventory().AddItem(((Component)__instance.m_coinPrefab).gameObject, num2);
					}
					AfrekSkills.RaiseLocal(SkillId.Trading, (float)(num + num2) * 0.1f);
				}
			}
		}

		private static int s_depth;

		private static readonly List<int> s_prices = new List<int>();

		private static Trader s_trader;

		internal static int Discounted(int price, float f)
		{
			if (price > 1)
			{
				return Mathf.Max(1, Mathf.RoundToInt((float)price * (1f - 0.15f * Mathf.Clamp01(f))));
			}
			return price;
		}

		private static void Enter(StoreGui gui)
		{
			if (s_depth++ > 0 || (Object)(object)gui == (Object)null || (Object)(object)gui.m_trader == (Object)null)
			{
				return;
			}
			float num = AfrekSkills.LocalFactor(SkillId.Trading);
			if (num <= 0f)
			{
				return;
			}
			s_trader = gui.m_trader;
			s_prices.Clear();
			foreach (TradeItem item in s_trader.m_items)
			{
				s_prices.Add(item.m_price);
				item.m_price = Discounted(item.m_price, num);
			}
		}

		private static void Exit()
		{
			if (--s_depth <= 0 && !((Object)(object)s_trader == (Object)null))
			{
				for (int i = 0; i < s_trader.m_items.Count && i < s_prices.Count; i++)
				{
					s_trader.m_items[i].m_price = s_prices[i];
				}
				s_trader = null;
				s_prices.Clear();
			}
		}
	}
}
namespace Afrek.Dev
{
	public class SelfTest : MonoBehaviour
	{
		private string _out;

		private readonly List<string> _report = new List<string>();

		private int _pass;

		private int _fail;

		private Vector3 _home;

		public static void TryStart(GameObject host)
		{
			string environmentVariable = Environment.GetEnvironmentVariable("AFREK_SELFTEST");
			if (string.IsNullOrEmpty(environmentVariable))
			{
				return;
			}
			Application.runInBackground = true;
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			bool flag = false;
			for (int i = 0; i < commandLineArgs.Length - 1; i++)
			{
				if (commandLineArgs[i] == "-savedir" && !string.IsNullOrEmpty(commandLineArgs[i + 1]))
				{
					Directory.CreateDirectory(commandLineArgs[i + 1]);
					Utils.SetSaveDataPath(commandLineArgs[i + 1]);
					flag = true;
				}
			}
			if (!flag)
			{
				AfrekPlugin.Log.LogError((object)"Self test needs -savedir <scratch folder>; not starting it.");
			}
			else
			{
				host.AddComponent<SelfTest>()._out = environmentVariable;
			}
		}

		private static bool Flag(string name)
		{
			return (Environment.GetEnvironmentVariable("AFREK_SELFTEST_" + name) ?? "") == "1";
		}

		private static string Var(string name)
		{
			return Environment.GetEnvironmentVariable("AFREK_SELFTEST_" + name) ?? "";
		}

		private void Start()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			Directory.CreateDirectory(_out);
			Application.logMessageReceived += new LogCallback(OnLog);
			((MonoBehaviour)this).StartCoroutine(Run());
		}

		private void OnLog(string condition, string stackTrace, LogType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 4 || (int)type == 0)
			{
				_report.Add($"[{type}] {condition}\n{stackTrace}");
			}
		}

		private IEnumerator Run()
		{
			float timeout = Time.realtimeSinceStartup + 600f;
			while (((Object)(object)FejdStartup.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) && Time.realtimeSinceStartup < timeout)
			{
				yield return null;
			}
			yield return (object)new WaitForSecondsRealtime(4f);
			string text = Var("JOIN");
			if (!string.IsNullOrEmpty(text))
			{
				yield return ((MonoBehaviour)this).StartCoroutine(Safe(EnterServer(text)));
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(Safe(Multiplayer()));
				}
			}
			else if (Flag("WORLD"))
			{
				yield return ((MonoBehaviour)this).StartCoroutine(Safe(EnterWorld()));
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(Safe(WorldTest()));
				}
			}
			_report.Add($"RESULT pass {_pass} fail {_fail}");
			Flush();
			Application.logMessageReceived -= new LogCallback(OnLog);
			yield return (object)new WaitForSecondsRealtime(0.5f);
			Application.Quit();
		}

		private IEnumerator Safe(IEnumerator inner)
		{
			while (true)
			{
				object current;
				try
				{
					if (!inner.MoveNext())
					{
						break;
					}
					current = inner.Current;
				}
				catch (Exception ex)
				{
					_report.Add("step failed: " + ex);
					_fail++;
					break;
				}
				yield return current;
			}
		}

		private void Flush()
		{
			Directory.CreateDirectory(_out);
			File.WriteAllLines(Path.Combine(_out, "report.txt"), _report);
		}

		private void Check(bool ok, string what)
		{
			if (ok)
			{
				_pass++;
			}
			else
			{
				_fail++;
			}
			_report.Add((ok ? "PASS " : "FAIL ") + what);
		}

		private IEnumerator EnterWorld()
		{
			FejdStartup instance = FejdStartup.instance;
			if ((Object)(object)instance == (Object)null)
			{
				_report.Add("world: no FejdStartup");
				yield break;
			}
			PlayerProfile val = new PlayerProfile("afrektester", (FileSource)2);
			val.SetName("Afreker");
			val.m_firstSpawn = false;
			val.Save();
			Game.SetProfile("afrektester", (FileSource)2);
			World val2 = new World("AfrekTest", "HQ7GnTiegh")
			{
				m_fileSource = (FileSource)2
			};
			val2.SaveWorldFWLData(DateTime.Now);
			instance.m_world = val2;
			instance.m_startingWorld = true;
			ZNet.SetServer(true, false, false, val2.m_name, "", val2);
			ZNet.ResetServerHost();
			instance.TransitionToMainScene();
			_report.Add("world: loading " + val2.m_name + " seed " + val2.m_seedName);
			float timeout = Time.realtimeSinceStartup + 300f;
			while (((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ((Character)Player.m_localPlayer).IsTeleporting()) && Time.realtimeSinceStartup < timeout)
			{
				yield return null;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				_report.Add("world: player never spawned");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(6f);
			_report.Add("world: spawned at " + ((object)((Component)Player.m_localPlayer).transform.position/*cast due to .constrained prefix*/).ToString());
		}

		private IEnumerator EnterServer(string address)
		{
			FejdStartup instance = FejdStartup.instance;
			if ((Object)(object)instance == (Object)null)
			{
				_report.Add("join: no FejdStartup");
				yield break;
			}
			PlayerProfile val = new PlayerProfile("afrekmp", (FileSource)2);
			val.SetName("AfrekerMP");
			val.m_firstSpawn = false;
			val.Save();
			Game.SetProfile("afrekmp", (FileSource)2);
			instance.SetServerToJoin(new ServerJoinData(new ServerJoinDataDedicated(address)));
			instance.JoinServer();
			_report.Add("join: connecting to " + address);
			float timeout = Time.realtimeSinceStartup + 240f;
			while (((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ((Character)Player.m_localPlayer).IsTeleporting()) && Time.realtimeSinceStartup < timeout)
			{
				yield return null;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				_report.Add("join: player never spawned");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(8f);
			_report.Add($"join: spawned at {((Component)Player.m_localPlayer).transform.position}, server {ZNet.instance.IsServer()}, peers {ZNet.instance.GetPeers().Count}");
		}

		private IEnumerator Multiplayer()
		{
			yield return ((MonoBehaviour)this).StartCoroutine(Safe(MpScenes()));
		}

		private IEnumerator WorldTest()
		{
			if (Flag("RESEARCH"))
			{
				yield return ((MonoBehaviour)this).StartCoroutine(Safe(Research()));
			}
			else
			{
				yield return ((MonoBehaviour)this).StartCoroutine(Safe(Scenes()));
			}
		}

		private static void Stand(Player p, Vector3 at)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			at.y = ZoneSystem.instance.GetGroundHeight(at) + 0.1f;
			((Component)p).transform.position = at;
			((Character)p).m_body.position = at;
			((Character)p).m_body.linearVelocity = Vector3.zero;
		}

		private IEnumerator Travel(Player p, Vector3 at)
		{
			//IL_000e: 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)
			((Character)p).TeleportTo(at + Vector3.up * 2f, ((Component)p).transform.rotation, true);
			float limit = Time.realtimeSinceStartup + 90f;
			while ((((Character)p).IsTeleporting() || !ZoneSystem.instance.IsZoneLoaded(at)) && Time.realtimeSinceStartup < limit)
			{
				yield return null;
			}
			yield return (object)new WaitForSecondsRealtime(3f);
			Stand(p, at);
			yield return (object)new WaitForSecondsRealtime(1f);
		}

		private void ClearArea(Vector3 c, float r)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0);
			foreach (ZNetView val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.IsValid() && !((Object)(object)((Component)val).GetComponent<Player>() != (Object)null) && !(Utils.DistanceXZ(((Component)val).transform.position, c) > r) && (Object.op_Implicit((Object)(object)((Component)val).GetComponent<TreeBase>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponent<TreeLog>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponent<Destructible>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponent<MineRock>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponent<MineRock5>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponent<Pickable>()) || (Object.op_Implicit((Object)(object)((Component)val).GetComponent<Character>()) && !((Component)val).GetComponent<Character>().IsTamed())))
				{
					val.Destroy();
					num++;
				}
			}
			_report.Add("scene: cleared " + num + " objects");
		}

		private static Pose Look(Vector3 target, float bearing, float dist, float height)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0026: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = target + Quaternion.Euler(0f, bearing, 0f) * Vector3.forward * dist + Vector3.up * height;
			return new Pose(val, Quaternion.LookRotation(target - val));
		}

		private IEnumerator MainShot(string name, Pose pose)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Utils.GetMainCamera();
			GameCamera gc = GameCamera.instance;
			if ((Object)(object)main == (Object)null)
			{
				_report.Add("mainshot: no camera");
				yield break;
			}
			if ((Object)(object)gc != (Object)null)
			{
				((Behaviour)gc).enabled = false;
			}
			if ((Object)(object)Hud.instance != (Object)null)
			{
				Hud.instance.m_userHidden = true;
			}
			((Component)main).transform.SetPositionAndRotation(pose.position, pose.rotation);
			float fov = main.fieldOfView;
			main.fieldOfView = 50f;
			yield return null;
			yield return null;
			yield return (object)new WaitForEndOfFrame();
			Directory.CreateDirectory(_out);
			ScreenCapture.CaptureScreenshot(Path.Combine(_out, name + ".png"));
			yield return null;
			yield return null;
			main.fieldOfView = fov;
			if ((Object)(object)gc != (Object)null)
			{
				((Behaviour)gc).enabled = true;
			}
			if ((Object)(object)Hud.instance != (Object)null)
			{
				Hud.instance.m_userHidden = false;
			}
		}

		private IEnumerator Shot(string name)
		{
			yield return (object)new WaitForEndOfFrame();
			Directory.CreateDirectory(_out);
			ScreenCapture.CaptureScreenshot(Path.Combine(_out, name + ".png"));
			yield return null;
			yield return null;
		}

		private static string Flat(string s)
		{
			if (s != null)
			{
				return s.Replace('\n', '|');
			}
			return "null";
		}

		private static Bounds RendererBounds(GameObject go)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Bounds result = default(Bounds);
			bool flag = false;
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>();
			foreach (Renderer val in componentsInChildren)
			{
				if (!(val is ParticleSystemRenderer) && val.enabled)
				{
					if (!flag)
					{
						result = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref result)).Encapsulate(val.bounds);
					}
				}
			}
			return result;
		}

		private static Skill Data(Player p, SkillId id)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return ((Character)p).GetSkills().GetSkill(AfrekSkills.Type(id));
		}

		private static void SetLevel(Player p, SkillId id, float level)
		{
			Skill obj = Data(p, id);
			obj.m_level = level;
			obj.m_accumulator = 0f;
			Shared.Publish(p, force: true);
		}

		private static void ResetAll(Player p)
		{
			SkillDef[] all = SkillTable.All;
			foreach (SkillDef skillDef in all)
			{
				SetLevel(p, skillDef.Id, 0f);
			}
		}

		private static float Points(Player p, SkillId id)
		{
			Skill val = Data(p, id);
			float num = 0f;
			for (int i = 0; i < (int)val.m_level; i++)
			{
				num += (float)(Math.Pow(i + 1, 1.5) * 0.5 + 0.5);
			}
			return num + val.m_accumulator;
		}

		private static GameObject SpawnAt(string prefab, Vector3 at, float yaw = 0f)
		{
			//IL_0018: 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)
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(prefab2, at, Quaternion.Euler(0f, yaw, 0f));
			long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
			ZNetView component = obj.GetComponent<ZNetView>();
			if (component != null)
			{
				ZDO zDO = component.GetZDO();
				if (zDO != null)
				{
					zDO.Set(ZDOVars.s_creator, playerID);
				}
			}
			Piece component2 = obj.GetComponent<Piece>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_creator = playerID;
			}
			return obj;
		}

		private static void Remove(Component c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				ZNetView component = c.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid())
				{
					component.Destroy();
				}
			}
		}

		private static int CountDrops(string prefab, Vector3 at, float r)
		{
			//IL_0033: 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)
			int num = 0;
			ItemDrop[] array = Object.FindObjectsByType<ItemDrop>((FindObjectsSortMode)0);
			foreach (ItemDrop val in array)
			{
				if ((Object)(object)val != (Object)null && Utils.GetPrefabName(((Component)val).gameObject) == prefab && Vector3.Distance(((Component)val).transform.position, at) < r)
				{
					num += val.m_itemData.m_stack;
				}
			}
			return num;
		}

		private static void ClearDrops(Vector3 at, float r)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			ItemDrop[] array = Object.FindObjectsByType<ItemDrop>((FindObjectsSortMode)0);
			foreach (ItemDrop val in array)
			{
				if ((Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, at) < r)
				{
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					if (component != null)
					{
						component.Destroy();
					}
				}
			}
		}

		private static Vector3 FlatSpot(Vector3 c, float r)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or