Decompiled source of HatHunt v6.4.2

HatHunt.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HatHunt;

public enum AnimeBase : byte
{
	None,
	Headband,
	Maid,
	Hachimaki,
	Kasa,
	Kabuto
}
public enum BandStyle : byte
{
	None,
	Thin,
	Thick,
	Double
}
public enum BrimStyle : byte
{
	None,
	Flat,
	Wide,
	Upturned,
	Drooping,
	Visor,
	Tricorn,
	Rolled,
	Sloped
}
public class CharacterPuppet
{
	public Transform Root;

	private PlayerControllerB player;

	private readonly List<Transform> src = new List<Transform>();

	private readonly List<Transform> dst = new List<Transform>();

	private readonly Dictionary<Transform, Transform> map = new Dictionary<Transform, Transform>();

	private GameObject hatObj;

	private Hat hatShown;

	private int hatVersion = -1;

	public Vector3 HeadPoint
	{
		get
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)player != (Object)null && (Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : (((Object)(object)player != (Object)null) ? (((Component)player).transform.position + Vector3.up * 2f) : Vector3.zero));
			return ((Object)(object)player != (Object)null) ? ((Component)player).transform.InverseTransformPoint(val) : (Vector3.up * 2f);
		}
	}

	public GameObject Hat => hatObj;

	public static CharacterPuppet Build(PlayerControllerB p, Transform parent)
	{
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0272: Expected O, but got Unknown
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		SkinnedMeshRenderer thisPlayerModel = p.thisPlayerModel;
		if ((Object)(object)thisPlayerModel == (Object)null || (Object)(object)thisPlayerModel.sharedMesh == (Object)null || thisPlayerModel.bones == null || thisPlayerModel.bones.Length == 0)
		{
			return null;
		}
		CharacterPuppet characterPuppet = new CharacterPuppet();
		characterPuppet.player = p;
		CharacterPuppet characterPuppet2 = characterPuppet;
		characterPuppet2.Root = new GameObject("puppet").transform;
		characterPuppet2.Root.SetParent(parent, false);
		characterPuppet2.Root.localScale = ((Component)p).transform.lossyScale;
		HashSet<Transform> need = new HashSet<Transform>();
		Action<Transform> action = delegate(Transform t)
		{
			while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)((Component)p).transform && need.Add(t))
			{
				t = t.parent;
			}
		};
		Transform[] bones = thisPlayerModel.bones;
		foreach (Transform obj in bones)
		{
			action(obj);
		}
		action(thisPlayerModel.rootBone);
		action(p.headCostumeContainer);
		action(p.playerGlobalHead);
		action(((Component)thisPlayerModel).transform);
		List<Transform> list = new List<Transform>(need);
		list.Sort((Transform a, Transform b) => Depth(a, ((Component)p).transform).CompareTo(Depth(b, ((Component)p).transform)));
		foreach (Transform item in list)
		{
			if (item.IsChildOf(((Component)p).transform))
			{
				Transform transform = new GameObject(((Object)item).name).transform;
				transform.SetParent(((Object)(object)item.parent == (Object)(object)((Component)p).transform || !characterPuppet2.map.TryGetValue(item.parent, out var value)) ? characterPuppet2.Root : value, false);
				transform.localPosition = item.localPosition;
				transform.localRotation = item.localRotation;
				transform.localScale = item.localScale;
				characterPuppet2.map[item] = transform;
				characterPuppet2.src.Add(item);
				characterPuppet2.dst.Add(transform);
			}
		}
		if (!characterPuppet2.map.TryGetValue(((Component)thisPlayerModel).transform, out var value2))
		{
			value2 = characterPuppet2.Root;
		}
		GameObject val = new GameObject("body");
		val.transform.SetParent(value2, false);
		SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>();
		Transform[] array = (Transform[])(object)new Transform[thisPlayerModel.bones.Length];
		for (int num2 = 0; num2 < array.Length; num2++)
		{
			array[num2] = (((Object)(object)thisPlayerModel.bones[num2] != (Object)null && characterPuppet2.map.TryGetValue(thisPlayerModel.bones[num2], out var value3)) ? value3 : null);
		}
		val2.sharedMesh = thisPlayerModel.sharedMesh;
		val2.bones = array;
		val2.rootBone = (((Object)(object)thisPlayerModel.rootBone != (Object)null && characterPuppet2.map.TryGetValue(thisPlayerModel.rootBone, out var value4)) ? value4 : null);
		((Renderer)val2).sharedMaterials = ((Renderer)thisPlayerModel).sharedMaterials;
		((Renderer)val2).localBounds = ((Renderer)thisPlayerModel).localBounds;
		val2.updateWhenOffscreen = true;
		val2.quality = (SkinQuality)0;
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1;
		((Renderer)val2).receiveShadows = true;
		try
		{
			for (int num3 = 0; num3 < thisPlayerModel.sharedMesh.blendShapeCount; num3++)
			{
				val2.SetBlendShapeWeight(num3, thisPlayerModel.GetBlendShapeWeight(num3));
			}
		}
		catch
		{
		}
		if ((Object)(object)value2 != (Object)(object)characterPuppet2.Root)
		{
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
		}
		return characterPuppet2;
	}

	private static int Depth(Transform t, Transform stop)
	{
		int num = 0;
		while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)stop)
		{
			num++;
			t = t.parent;
		}
		return num;
	}

	public void Sync()
	{
		//IL_002f: 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_0047: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < src.Count; i++)
		{
			Transform val = src[i];
			if (!((Object)(object)val == (Object)null))
			{
				Transform val2 = dst[i];
				val2.localPosition = val.localPosition;
				val2.localRotation = val.localRotation;
				val2.localScale = val.localScale;
			}
		}
		if (hatShown != null && hatVersion != HatManager.HeadVersion)
		{
			Pose();
		}
	}

	public void SetHat(Hat hat)
	{
		if ((Object)(object)hatObj != (Object)null)
		{
			Object.Destroy((Object)(object)hatObj);
		}
		hatObj = null;
		hatShown = hat;
		hatVersion = HatManager.HeadVersion;
		if (hat == null || (Object)(object)player == (Object)null)
		{
			return;
		}
		try
		{
			hatObj = HatVisuals.Build(hat);
			Light[] componentsInChildren = hatObj.GetComponentsInChildren<Light>(true);
			foreach (Light val in componentsInChildren)
			{
				((Behaviour)val).enabled = false;
			}
			Pose();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("puppet hat: " + ex.Message));
		}
	}

	private void Pose()
	{
		//IL_00b6: 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_00c1: 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)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		hatVersion = HatManager.HeadVersion;
		if (!((Object)(object)hatObj == (Object)null) && hatShown != null && !((Object)(object)player == (Object)null))
		{
			HatManager.HatLocalPose(player, hatShown, out var parent, out var local);
			if (map.TryGetValue(parent, out var value))
			{
				hatObj.transform.SetParent(value, false);
				HatManager.SetLocalMatrix(hatObj.transform, local);
			}
			else
			{
				hatObj.transform.SetParent(Root, false);
				HatManager.SetLocalMatrix(hatObj.transform, ((Component)player).transform.worldToLocalMatrix * parent.localToWorldMatrix * local);
			}
		}
	}

	public void Destroy()
	{
		if ((Object)(object)Root != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)Root).gameObject);
		}
		Root = null;
		hatObj = null;
	}
}
public class CharacterStudio
{
	public PreviewStage Stage;

	public CharacterPuppet Puppet;

	private Transform pivot;

	private float camDist = 1.4f;

	private float targetDist = 1.4f;

	public float Swing = 38f;

	private float nextReframe;

	private int framedVersion = -1;

	public RenderTexture Texture => Stage.Texture;

	public bool Active
	{
		set
		{
			Stage.Active = value;
		}
	}

	public static CharacterStudio Create(string name, Vector3 pos, int w, int h)
	{
		//IL_0008: 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)
		CharacterStudio characterStudio = new CharacterStudio();
		characterStudio.Stage = PreviewStage.Create(name, pos, w, h, pedestal: false);
		characterStudio.pivot = HatVisuals.PropPivot(characterStudio.Stage.Turntable, "pivot", new Vector3(0f, 0.4f, 0f), Quaternion.identity);
		return characterStudio;
	}

	public bool Capture(PlayerControllerB p)
	{
		if (Puppet != null)
		{
			Puppet.Destroy();
		}
		Puppet = CharacterPuppet.Build(p, pivot);
		if (Puppet == null)
		{
			return false;
		}
		Puppet.Sync();
		Reframe(snap: true);
		return true;
	}

	public void SetHat(Hat hat)
	{
		if (Puppet != null)
		{
			Puppet.SetHat(hat);
			Reframe(snap: false);
		}
	}

	private void Reframe(bool snap)
	{
		//IL_0012: 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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		if (Puppet != null)
		{
			Vector3 headPoint = Puppet.HeadPoint;
			Bounds val = default(Bounds);
			((Bounds)(ref val))..ctor(headPoint + Vector3.up * 0.05f, new Vector3(0.6f, 0.6f, 0.6f));
			if ((Object)(object)Puppet.Hat != (Object)null && PreviewStage.LocalBounds(Puppet.Hat.transform, Puppet.Root, out var b))
			{
				((Bounds)(ref val)).Encapsulate(((Bounds)(ref b)).min);
				((Bounds)(ref val)).Encapsulate(((Bounds)(ref b)).max);
			}
			Puppet.Root.localPosition = -((Bounds)(ref val)).center;
			float num = Mathf.Max(new float[3]
			{
				((Bounds)(ref val)).size.x,
				((Bounds)(ref val)).size.y,
				((Bounds)(ref val)).size.z
			}) * 0.5f;
			targetDist = Mathf.Clamp(num / Mathf.Tan((float)Math.PI / 12f) * 1.25f, 1f, 3.5f);
			if (snap)
			{
				camDist = targetDist;
			}
		}
	}

	public void Tick()
	{
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		if (Puppet != null)
		{
			Puppet.Sync();
			if (Time.unscaledTime > nextReframe || framedVersion != HatManager.HeadVersion)
			{
				nextReframe = Time.unscaledTime + 0.25f;
				framedVersion = HatManager.HeadVersion;
				Reframe(snap: false);
			}
			pivot.localRotation = Quaternion.Euler(0f, Mathf.Sin(Time.unscaledTime * 0.8f) * Swing, 0f);
			camDist = Mathf.Lerp(camDist, targetDist, Mathf.Min(1f, Time.unscaledDeltaTime * 6f));
			Transform transform = ((Component)Stage.Cam).transform;
			transform.localPosition = new Vector3(0f, 0.4f + camDist * 0.1f, camDist);
			transform.LookAt(pivot.position);
		}
	}

	public void Clear()
	{
		if (Puppet != null)
		{
			Puppet.Destroy();
		}
		Puppet = null;
	}
}
public static class Collection
{
	public static readonly List<HatKey> Hats = new List<HatKey>();

	public static int EquippedIndex = -1;

	public static int Keys;

	public static int Version;

	public static readonly int[] Crates = new int[4];

	private static string Dir => Path.Combine(Paths.ConfigPath, "HatHunt");

	private static string FilePath => Path.Combine(Dir, "my_hats.txt");

	public static HatKey? Equipped => (EquippedIndex >= 0 && EquippedIndex < Hats.Count) ? new HatKey?(Hats[EquippedIndex]) : ((HatKey?)null);

	public static void Load()
	{
		Version++;
		Hats.Clear();
		EquippedIndex = -1;
		Keys = 0;
		for (int i = 0; i < Crates.Length; i++)
		{
			Crates[i] = 0;
		}
		try
		{
			if (!File.Exists(FilePath))
			{
				return;
			}
			string text = null;
			string[] array = File.ReadAllLines(FilePath);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0 || text3.StartsWith("#"))
				{
					continue;
				}
				HatKey key;
				if (text3.StartsWith("equipped="))
				{
					text = text3.Substring(9);
				}
				else if (text3.StartsWith("keys="))
				{
					int.TryParse(text3.Substring(5), out Keys);
				}
				else if (text3.StartsWith("crate="))
				{
					string[] array2 = text3.Substring(6).Split(':');
					if (array2.Length == 2 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && result >= 0 && result < Crates.Length)
					{
						Crates[result] = result2;
					}
				}
				else if (HatKey.TryParse(text3, out key) && !Hats.Contains(key))
				{
					Hats.Add(key);
				}
			}
			if (text != null && HatKey.TryParse(text, out var key2))
			{
				EquippedIndex = Hats.IndexOf(key2);
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Failed to load hat collection: " + ex));
		}
	}

	public static void Save()
	{
		Version++;
		try
		{
			Directory.CreateDirectory(Dir);
			List<string> list = new List<string>();
			list.Add("# HatHunt collection - seed,rarity,serial. Don't edit unless you like broken hats.");
			List<string> list2 = list;
			HatKey? equipped = Equipped;
			if (equipped.HasValue)
			{
				list2.Add("equipped=" + equipped.Value.Serialize());
			}
			list2.Add("keys=" + Keys);
			for (int i = 0; i < Crates.Length; i++)
			{
				if (Crates[i] > 0)
				{
					list2.Add("crate=" + i + ":" + Crates[i]);
				}
			}
			foreach (HatKey hat in Hats)
			{
				list2.Add(hat.Serialize());
			}
			File.WriteAllLines(FilePath, list2.ToArray());
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Failed to save hat collection: " + ex));
		}
	}

	public static void RemoveAll(IList<HatKey> keys)
	{
		HatKey? equipped = Equipped;
		foreach (HatKey key in keys)
		{
			Hats.Remove(key);
		}
		EquippedIndex = (equipped.HasValue ? Hats.IndexOf(equipped.Value) : (-1));
		Save();
	}

	public static bool Add(HatKey k)
	{
		if (Hats.Contains(k))
		{
			return false;
		}
		Hats.Add(k);
		Save();
		return true;
	}
}
public class CrateFx : MonoBehaviour
{
	public const float HatRevealTime = 1.45f;

	private Transform lid;

	private Transform padlock;

	private Transform hatPivot;

	private GameObject hat;

	private Material inside;

	private Light glow;

	private Color rarityColor = Color.white;

	private AudioSource src;

	private float t;

	private float hatScale = 1f;

	private bool clunked;

	private bool creaked;

	private bool chimed;

	private bool padlockFalling;

	private Vector3 padlockVel;

	private readonly List<Transform> sparks = new List<Transform>();

	private readonly List<Vector3> sparkVel = new List<Vector3>();

	private Rarity rarity;

	public static void Play(Vector3 pos, Quaternion rot, CrateType type, HatKey? key)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0011: 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)
		try
		{
			GameObject val = new GameObject("HatHunt_CrateFx");
			val.transform.position = pos;
			val.transform.rotation = rot;
			CrateFx crateFx = val.AddComponent<CrateFx>();
			crateFx.Setup(type, key);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("crate fx: " + ex.Message));
		}
	}

	private void Setup(CrateType type, HatKey? key)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = HatVisuals.BuildCrate(type);
		val.transform.SetParent(((Component)this).transform, false);
		val.transform.localScale = Vector3.one * 1.75f;
		val.transform.localPosition = Vector3.down * (((Object)(object)NetPrefabs.CrateItemProps != (Object)null) ? NetPrefabs.CrateItemProps.verticalOffset : 0f);
		lid = val.transform.Find("lid");
		padlock = val.transform.Find("padlock");
		rarity = (key.HasValue ? key.Value.Rarity : Rarity.Common);
		rarityColor = HatGen.RarityColors[(uint)rarity];
		inside = HatVisuals.NewGlowMaterial(rarityColor, 0.01f);
		HatVisuals.PropPart(val.transform, HatVisuals.CubeMesh, inside, new Vector3(0f, 0.255f, 0f), Quaternion.identity, new Vector3(0.38f, 0.002f, 0.26f));
		glow = HatVisuals.CloneLight(((Component)this).transform, new Vector3(0f, 0.6f, 0f), rarityColor, 5f, 0f);
		if ((Object)(object)glow != (Object)null)
		{
			glow.shadows = (LightShadows)0;
		}
		hatPivot = new GameObject("hatPivot").transform;
		hatPivot.SetParent(((Component)this).transform, false);
		hatPivot.localPosition = new Vector3(0f, 0.25f, 0f);
		if (key.HasValue)
		{
			try
			{
				Hat hat = HatGen.Generate(key.Value);
				this.hat = HatVisuals.Build(hat);
				this.hat.transform.SetParent(hatPivot, false);
				hatScale = HatVisuals.ItemScale(hat);
				this.hat.transform.localScale = Vector3.zero;
				Light[] componentsInChildren = this.hat.GetComponentsInChildren<Light>(true);
				foreach (Light val2 in componentsInChildren)
				{
					((Behaviour)val2).enabled = false;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("crate fx hat: " + ex.Message));
			}
		}
		src = ((Component)this).gameObject.AddComponent<AudioSource>();
		src.spatialBlend = 1f;
		src.rolloffMode = (AudioRolloffMode)1;
		src.minDistance = 1.5f;
		src.maxDistance = 28f;
		src.dopplerLevel = 0f;
		src.playOnAwake = false;
		try
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.ship3DAudio != (Object)null)
			{
				src.outputAudioMixerGroup = instance.ship3DAudio.outputAudioMixerGroup;
			}
		}
		catch
		{
		}
		src.PlayOneShot(CrateSfx.Click, 0.9f);
	}

	private static float EaseOutBack(float x)
	{
		return 1f + 2.70158f * Mathf.Pow(x - 1f, 3f) + 1.70158f * Mathf.Pow(x - 1f, 2f);
	}

	private void Update()
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: 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)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0405: Unknown result type (might be due to invalid IL or missing references)
		//IL_040f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0414: Unknown result type (might be due to invalid IL or missing references)
		//IL_0421: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0606: Unknown result type (might be due to invalid IL or missing references)
		//IL_0594: Unknown result type (might be due to invalid IL or missing references)
		//IL_059f: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0523: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		t += Time.deltaTime;
		if ((Object)(object)padlock != (Object)null)
		{
			if (t < 0.4f)
			{
				padlock.localRotation = Quaternion.Euler(0f, 0f, Mathf.Sin(t * 70f) * 22f * (1f - t / 0.4f));
			}
			else
			{
				if (!padlockFalling)
				{
					padlockFalling = true;
					padlockVel = new Vector3(Random.Range(-0.2f, 0.2f), 0.35f, 0.5f);
				}
				padlockVel += Vector3.down * 3.5f * Time.deltaTime;
				Transform obj = padlock;
				obj.localPosition += padlockVel * Time.deltaTime;
				Transform obj2 = padlock;
				obj2.localRotation *= Quaternion.Euler(400f * Time.deltaTime, 0f, 250f * Time.deltaTime);
				float num = Mathf.Clamp01(1f - (t - 0.6f) / 0.4f);
				padlock.localScale = Vector3.one * num;
			}
		}
		if (!clunked && t > 0.4f)
		{
			clunked = true;
			src.PlayOneShot(CrateSfx.Clunk, 0.8f);
		}
		if (!creaked && t > 0.5f)
		{
			creaked = true;
			src.PlayOneShot(CrateSfx.Creak, 0.75f);
		}
		if ((Object)(object)lid != (Object)null && t > 0.55f)
		{
			float x = Mathf.Clamp01((t - 0.55f) / 0.45f);
			lid.localRotation = Quaternion.Euler(-108f * EaseOutBack(x), 0f, 0f);
		}
		float num2 = ((!(t >= 0.6f)) ? 0f : ((!(t >= 1f)) ? ((t - 0.6f) / 0.4f) : Mathf.Clamp01(1f - (t - 2.2f) / 1f)));
		if ((Object)(object)inside != (Object)null && inside.HasProperty("_EmissiveColor"))
		{
			inside.SetColor("_EmissiveColor", rarityColor * (6f * num2));
		}
		if ((Object)(object)glow != (Object)null)
		{
			HDAdditionalLightData component = ((Component)glow).GetComponent<HDAdditionalLightData>();
			float num3 = (300f + 250f * (float)(int)rarity) * num2;
			if ((Object)(object)component != (Object)null)
			{
				component.SetIntensity(num3, (LightUnit)0);
			}
			else
			{
				glow.intensity = num2 * 2f;
			}
		}
		if (!chimed && t > 0.62f)
		{
			chimed = true;
			src.PlayOneShot(CrateSfx.Chime(rarity), 0.85f);
			SpawnSparks(8 + 4 * (int)rarity);
		}
		for (int num4 = sparks.Count - 1; num4 >= 0; num4--)
		{
			Transform val = sparks[num4];
			if (!((Object)(object)val == (Object)null))
			{
				sparkVel[num4] += Vector3.down * 2.2f * Time.deltaTime;
				val.localPosition += sparkVel[num4] * Time.deltaTime;
				val.localScale *= Mathf.Max(0f, 1f - Time.deltaTime * 1.4f);
				val.Rotate(300f * Time.deltaTime, 200f * Time.deltaTime, 0f);
			}
		}
		if ((Object)(object)hat != (Object)null)
		{
			if (t > 0.7f && t < 1.5f)
			{
				float num5 = Mathf.Clamp01((t - 0.7f) / 0.75000006f);
				float num6 = 1f - (1f - num5) * (1f - num5);
				hat.transform.localScale = Vector3.one * hatScale * num6;
				hatPivot.localPosition = new Vector3(0f, 0.25f + 0.45f * num6, 0f);
				hatPivot.localRotation = Quaternion.Euler(0f, 540f * num6, 0f);
			}
			else if (t >= 1.5f)
			{
				float num7 = Mathf.Clamp01(1f - (t - 1.45f - 0.05f) / 0.12f);
				hat.transform.localScale = Vector3.one * hatScale * num7;
				if (num7 <= 0f)
				{
					Object.Destroy((Object)(object)hat);
					hat = null;
				}
			}
		}
		if (t > 3f)
		{
			((Component)this).transform.localScale = Vector3.one * Mathf.Clamp01(1f - (t - 3f) / 0.5f);
		}
		if (t > 3.6f)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)inside != (Object)null)
		{
			Object.Destroy((Object)(object)inside);
		}
	}

	private void SpawnSparks(int n)
	{
		//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_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		Material m = HatVisuals.GlowMaterial(Color.Lerp(rarityColor, Color.white, 0.35f), 8f);
		for (int i = 0; i < n; i++)
		{
			Transform transform = HatVisuals.PropPart(((Component)this).transform, HatVisuals.CubeMesh, m, new Vector3(Random.Range(-0.15f, 0.15f), 0.45f, Random.Range(-0.1f, 0.1f)), Random.rotation, Vector3.one * Random.Range(0.015f, 0.03f)).transform;
			sparks.Add(transform);
			sparkVel.Add(new Vector3(Random.Range(-0.7f, 0.7f), Random.Range(1.4f, 2.6f), Random.Range(-0.7f, 0.7f)));
		}
	}
}
public class CrateItem : GrabbableObject
{
	public const float ModelScale = 1.75f;

	public bool HasType;

	public CrateType Type;

	private GameObject model;

	private bool built;

	private ScanNodeProperties scan;

	public override void Start()
	{
		((GrabbableObject)this).Start();
		scan = ((Component)this).GetComponentInChildren<ScanNodeProperties>(true);
		TryResolve();
	}

	private void TryResolve()
	{
		if (!HasType && !((Object)(object)((NetworkBehaviour)this).NetworkObject == (Object)null) && ((NetworkBehaviour)this).NetworkObject.IsSpawned && ItemData.ById.TryGetValue(((NetworkBehaviour)this).NetworkObjectId, out var value) && value.Kind == 2)
		{
			Type = value.Crate;
			HasType = true;
		}
	}

	public void SetType(CrateType t)
	{
		Type = t;
		HasType = true;
		built = false;
	}

	public override void Update()
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		((GrabbableObject)this).Update();
		if (!HasType)
		{
			TryResolve();
			return;
		}
		if (((NetworkBehaviour)this).IsServer && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned && !ItemData.ById.ContainsKey(((NetworkBehaviour)this).NetworkObjectId))
		{
			WorldLoot.Host_Register(this, Type);
		}
		if (!built)
		{
			built = true;
			if ((Object)(object)model != (Object)null)
			{
				Object.Destroy((Object)(object)model);
			}
			try
			{
				model = HatVisuals.BuildCrate(Type);
				model.transform.SetParent(((Component)this).transform, false);
				model.transform.localPosition = Vector3.down * (((Object)(object)base.itemProperties != (Object)null) ? base.itemProperties.verticalOffset : 0f);
				model.transform.localScale = Vector3.one * 1.75f;
				MeshRenderer componentInChildren = model.GetComponentInChildren<MeshRenderer>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					base.mainObjectRenderer = componentInChildren;
				}
				if ((Object)(object)scan != (Object)null)
				{
					scan.headerText = Economy.CrateNames[(uint)Type];
					scan.subText = "Locked - use a key on it";
				}
				base.customGrabTooltip = "Grab crate : [E]";
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("crate build: " + ex.Message));
			}
		}
		if ((Object)(object)model != (Object)null && model.activeSelf == base.isPocketed)
		{
			model.SetActive(!base.isPocketed);
		}
	}

	public override void SetControlTipsForItem()
	{
		try
		{
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.ChangeControlTipMultiple(new string[1] { "Locked: drop it, then use a key on it" }, true, base.itemProperties);
			}
		}
		catch
		{
			((GrabbableObject)this).SetControlTipsForItem();
		}
	}

	public override int GetItemDataToSave()
	{
		return (int)((!HasType) ? CrateType.Otaku : (Type + 1));
	}

	public override void LoadItemSaveData(int saveData)
	{
		((GrabbableObject)this).LoadItemSaveData(saveData);
		Type = (CrateType)Mathf.Clamp(saveData - 1, 0, 3);
		HasType = true;
		built = false;
	}
}
public static class CrateSfx
{
	private static AudioClip click;

	private static AudioClip clunk;

	private static AudioClip creak;

	private static readonly AudioClip[] chimes = (AudioClip[])(object)new AudioClip[5];

	private const int Rate = 44100;

	public static AudioClip Click
	{
		get
		{
			if ((Object)(object)click == (Object)null)
			{
				click = Make("hh_click", 0.18f, (float t) => (Mathf.Sin(t * 2f * (float)Math.PI * 2600f) * Mathf.Exp((0f - t) * 120f) + Noise(t, 9000f) * Mathf.Exp((0f - t) * 80f) * 0.6f + ((!(t <= 0.07f)) ? (Mathf.Sin((t - 0.07f) * 2f * (float)Math.PI * 3400f) * Mathf.Exp((0f - (t - 0.07f)) * 150f)) : 0f)) * 0.5f);
			}
			return click;
		}
	}

	public static AudioClip Clunk
	{
		get
		{
			if ((Object)(object)clunk == (Object)null)
			{
				clunk = Make("hh_clunk", 0.3f, (float t) => (Mathf.Sin(t * 2f * (float)Math.PI * (140f - 120f * t)) * 0.8f + Noise(t, 1500f) * 0.4f) * Mathf.Exp((0f - t) * 18f) * 0.8f);
			}
			return clunk;
		}
	}

	public static AudioClip Creak
	{
		get
		{
			if ((Object)(object)creak == (Object)null)
			{
				creak = Make("hh_creak", 0.55f, delegate(float t)
				{
					float num = 210f + 70f * Mathf.Sin(t * 9f) + 40f * t;
					float num2 = Mathf.Repeat(t * num, 1f) * 2f - 1f;
					float num3 = 0.6f + 0.4f * Mathf.Sin(t * 2f * (float)Math.PI * 23f);
					float num4 = Mathf.Clamp01(t / 0.05f) * Mathf.Clamp01((0.55f - t) / 0.15f);
					return num2 * num3 * num4 * 0.28f + Noise(t, 700f) * num4 * 0.08f;
				});
			}
			return creak;
		}
	}

	private static AudioClip Make(string name, float seconds, Func<float, float> wave)
	{
		int num = (int)(44100f * seconds);
		float[] array = new float[num];
		for (int i = 0; i < num; i++)
		{
			array[i] = Mathf.Clamp(wave((float)i / 44100f), -1f, 1f);
		}
		AudioClip val = AudioClip.Create(name, num, 1, 44100, false);
		val.SetData(array, 0);
		return val;
	}

	private static float Noise(float t, float f)
	{
		return Mathf.PerlinNoise(t * f, 0.37f) * 2f - 1f;
	}

	public static AudioClip Chime(Rarity r)
	{
		int ri = (int)r;
		if ((Object)(object)chimes[ri] != (Object)null)
		{
			return chimes[ri];
		}
		float[] notes = new float[7] { 523.25f, 659.25f, 783.99f, 1046.5f, 1318.5f, 1568f, 2093f };
		int count = 2 + ri;
		float step = 0.09f;
		float seconds = (float)count * step + 0.9f;
		chimes[ri] = Make("hh_chime" + ri, seconds, delegate(float t)
		{
			float num = 0f;
			for (int i = 0; i < count; i++)
			{
				float num2 = t - (float)i * step;
				if (num2 < 0f)
				{
					break;
				}
				float num3 = notes[Mathf.Min(i, notes.Length - 1)];
				num += (Mathf.Sin(num2 * 2f * (float)Math.PI * num3) + 0.3f * Mathf.Sin(num2 * 2f * (float)Math.PI * num3 * 2.01f)) * Mathf.Exp((0f - num2) * 4.5f);
			}
			if (ri >= 3)
			{
				num += Noise(t, 12000f) * 0.25f * Mathf.Exp((0f - t) * 2.5f) * Mathf.Abs(Mathf.Sin(t * 60f));
			}
			return num * 0.22f;
		});
		return chimes[ri];
	}
}
public enum CrateType : byte
{
	Scavenger,
	Otaku,
	Wig,
	Golden
}
public enum CrownStyle : byte
{
	Straight,
	Taper,
	Cone,
	Dome,
	Bell,
	Bulb,
	Tiered,
	Pinched,
	Flared
}
public struct Decor
{
	public DecorType Type;

	public Color Color;

	public float Size;

	public float Angle;

	public int Count;

	public bool IsTop => (int)Type <= 5;

	public bool Glows => Type == DecorType.Halo || Type == DecorType.Orbiters || Type == DecorType.Flame || Type == DecorType.Antenna;
}
public enum DecorType : byte
{
	Pompom,
	Antenna,
	Propeller,
	Star,
	Flame,
	Tassel,
	Feathers,
	Horns,
	Spikes,
	Gems,
	Ears,
	Bow,
	Buckle,
	Flower,
	Halo,
	Orbiters,
	GooglyEyes,
	Mohawk,
	Ribbons,
	BunnyEars,
	OniHorns,
	Headphones,
	BigBow,
	Ahoge,
	FoxMask,
	SweatDrop,
	AngerMark,
	Hearts,
	Sparkles,
	Crest,
	Tiara
}
public static class Economy
{
	public class StoreItem
	{
		public HatKey Key;

		public HatKey? Shown;

		public int Price;

		public int ListPrice;

		public bool Sold;

		public bool Mystery;

		public bool Scam;

		public bool PreOwned;

		public HatKey Display => Shown.HasValue ? Shown.Value : Key;

		public bool Discounted => ListPrice > Price;
	}

	public enum BoothEvent : byte
	{
		None,
		FlashSale,
		Mystery,
		Deal,
		Haggle
	}

	private enum Pending
	{
		None,
		Trade,
		Open,
		Buy,
		Sell
	}

	public const int CrateTypeCount = 4;

	public static readonly string[] CrateNames = new string[4] { "Scavenger Crate", "Otaku Crate", "Wig Crate", "Golden Crate" };

	private static readonly string[] CrateHex = new string[4] { "#C9A46B", "#FF7AB8", "#7FD6FF", "#FFD24A" };

	private static readonly string[] CrateBlurb = new string[4] { "any hat or wig", "anime-inspired hats only", "wigs and hairstyles only", "Rare or better, guaranteed" };

	private static readonly float[][] CrateWeights = new float[4][]
	{
		new float[5] { 45f, 30f, 16f, 7f, 2f },
		new float[5] { 45f, 30f, 16f, 7f, 2f },
		new float[5] { 45f, 30f, 16f, 7f, 2f },
		new float[5] { 0f, 0f, 60f, 30f, 10f }
	};

	public static BoothEvent Event = BoothEvent.None;

	public static int StockDay = -1;

	public static readonly List<StoreItem> Stock = new List<StoreItem>();

	public static int KeyPrice = 60;

	private static Pending pending = Pending.None;

	private static float pendingSince;

	private static List<HatKey> pendingTrade = new List<HatKey>();

	private static CrateType pendingCrate;

	private static readonly HashSet<HatKey> soldThisSession = new HashSet<HatKey>();

	public static float LastStockAt = -100f;

	private static string noticeText;

	public static string LastResult;

	public static float LastResultTime;

	private static Terminal cachedTerminal;

	private static bool Busy
	{
		get
		{
			if (pending != Pending.None && Time.time - pendingSince > 10f)
			{
				pending = Pending.None;
			}
			return pending != Pending.None;
		}
	}

	public static bool IsBusy => Busy;

	public static void ResetSession()
	{
		soldThisSession.Clear();
		StockDay = -1;
		Stock.Clear();
		Event = BoothEvent.None;
		Vendors.Current = VendorId.Coat;
		pending = Pending.None;
		pendingTrade.Clear();
	}

	private static void SetPending(Pending p)
	{
		pending = p;
		pendingSince = Time.time;
	}

	private static string Hex(Rarity r)
	{
		return HatGen.RarityHex(r);
	}

	private static string Tag(Rarity r)
	{
		return "<color=" + Hex(r) + ">" + r.ToString().ToUpper() + "</color>";
	}

	public static bool AtCompany()
	{
		StartOfRound instance = StartOfRound.Instance;
		return !((Object)(object)instance == (Object)null) && !((Object)(object)instance.currentLevel == (Object)null) && (instance.currentLevel.sceneName == "CompanyBuilding" || instance.currentLevel.levelID == 3);
	}

	public static bool CanShop()
	{
		return AtCompany() || Encounters.VendorActive;
	}

	public static string EventTitle(BoothEvent e)
	{
		return e switch
		{
			BoothEvent.FlashSale => "FLASH SALE", 
			BoothEvent.Mystery => "MYSTERY ITEM", 
			BoothEvent.Deal => "DEAL OF THE CENTURY", 
			BoothEvent.Haggle => "GOOD MOOD: 20% OFF", 
			_ => null, 
		};
	}

	public static string EventColor(BoothEvent e)
	{
		return e switch
		{
			BoothEvent.FlashSale => "#FF5A4A", 
			BoothEvent.Mystery => "#C58BFF", 
			BoothEvent.Deal => "#FFB020", 
			BoothEvent.Haggle => "#6CFF8E", 
			_ => "#FFFFFF", 
		};
	}

	private static int CurrentDay()
	{
		StartOfRound instance = StartOfRound.Instance;
		return ((Object)(object)instance != (Object)null && instance.gameStats != null) ? instance.gameStats.daysSpent : 0;
	}

	private static Terminal FindTerminal()
	{
		return Object.FindObjectOfType<Terminal>();
	}

	public static float[] Weights(CrateType t)
	{
		return CrateWeights[(uint)t];
	}

	public static Func<Hat, bool> ThemeFilter(CrateType t)
	{
		return t switch
		{
			CrateType.Otaku => (Hat h) => h.Design.Anime != AnimeBase.None, 
			CrateType.Wig => (Hat h) => h.Design.Wig != WigStyle.None, 
			_ => null, 
		};
	}

	public static bool Host_TryDropExtra(int playerIdx, GrabbableObject item)
	{
		Random rng = HatManager.Instance.Rng;
		double num = rng.NextDouble() * 100.0;
		double num2 = Mathf.Max(0f, Plugin.CfgDropKey.Value);
		double num3 = Mathf.Max(0f, Plugin.CfgDropCrate.Value);
		if (num < num2)
		{
			Host_Grant(playerIdx, 0, 0, 1, 0);
			return true;
		}
		if (num < num2 + num3)
		{
			double num4 = rng.NextDouble() * 100.0;
			CrateType crate = ((!(num4 >= 5.0)) ? CrateType.Golden : ((!(num4 >= 25.0)) ? CrateType.Otaku : ((!(num4 >= 45.0)) ? CrateType.Wig : CrateType.Scavenger)));
			Host_Grant(playerIdx, 1, (byte)crate, 1, 0);
			return true;
		}
		return false;
	}

	private static void Host_Grant(int playerIdx, byte kind, byte crate, int count, byte how)
	{
		HatNet.ToAll("HatHunt.Grant", HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(playerIdx);
			w.Write(kind);
			w.Write(crate);
			w.Write(count);
			w.Write(how);
		}));
	}

	private static void Host_Notice(ulong client, string text)
	{
		HatNet.ToClient("HatHunt.Notice", client, HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(text);
		}));
	}

	public static void Host_OnTrade(ulong sender, byte[] data)
	{
		if (!HatNet.IsHost)
		{
			return;
		}
		List<HatKey> list = new List<HatKey>();
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			int num = binaryReader.ReadInt32();
			for (int i = 0; i < num && i < 20; i++)
			{
				HatKey? hatKey = HatNet.ReadKey(binaryReader);
				if (hatKey.HasValue)
				{
					list.Add(hatKey.Value);
				}
			}
		}
		int num2 = Mathf.Max(2, Plugin.CfgTradeCount.Value);
		int num3 = HatManager.PlayerIndexOf(sender);
		if (num3 < 0)
		{
			return;
		}
		if (list.Count != num2 || list.Distinct().Count() != num2)
		{
			Host_Notice(sender, "Trade-up needs exactly " + num2 + " different hats.");
			return;
		}
		Rarity rarity = list[0].Rarity;
		if (list.Any((HatKey k) => k.Rarity != rarity))
		{
			Host_Notice(sender, "All hats in a trade-up must be the same rarity.");
			return;
		}
		if (rarity == Rarity.Legendary)
		{
			Host_Notice(sender, "Legendary is already the top rarity.");
			return;
		}
		List<Hat> source = list.Select((HatKey k) => HatGen.Generate(k)).ToList();
		Func<Hat, bool> filter = null;
		if (source.Count((Hat h) => h.Design.Anime != AnimeBase.None) * 2 > num2)
		{
			filter = ThemeFilter(CrateType.Otaku);
		}
		else if (source.Count((Hat h) => h.Design.Wig != WigStyle.None) * 2 > num2)
		{
			filter = ThemeFilter(CrateType.Wig);
		}
		HatKey key = Registry.CreateUnique(HatManager.Instance.Rng, rarity + 1, filter);
		HatManager.Instance.Host_GiveHat(num3, key, FoundReason.TradeUp, "");
	}

	public static void Host_OnOpen(ulong sender, byte[] data)
	{
		if (HatNet.IsHost)
		{
			CrateType crateType;
			using (BinaryReader binaryReader = HatNet.Reader(data))
			{
				crateType = (CrateType)Mathf.Clamp((int)binaryReader.ReadByte(), 0, 3);
			}
			int num = HatManager.PlayerIndexOf(sender);
			if (num >= 0)
			{
				Random rng = HatManager.Instance.Rng;
				Rarity rarity = HatGen.RollRarity(rng, CrateWeights[(uint)crateType], HatManager.Instance.FortuneOf(num));
				HatKey key = Registry.CreateUnique(rng, rarity, ThemeFilter(crateType));
				HatManager.Instance.Host_GiveHat(num, key, FoundReason.Crate, CrateNames[(uint)crateType]);
			}
		}
	}

	public static void Host_PrepareStock()
	{
		if (HatNet.IsHost && !((Object)(object)HatManager.Instance == (Object)null) && Host_EnsureStock())
		{
			HatNet.ToAll("HatHunt.Stock", StockPayload());
		}
	}

	private static bool Host_EnsureStock()
	{
		int num = CurrentDay();
		if (StockDay == num && Stock.Count > 0)
		{
			return false;
		}
		StockDay = num;
		Stock.Clear();
		Event = BoothEvent.None;
		Random rng = HatManager.Instance.Rng;
		Vendors.Current = Vendors.HostPick(rng);
		VendorDef def = Vendors.Def;
		KeyPrice = Mathf.Max(1, Mathf.RoundToInt((float)Mathf.Max(1, Plugin.CfgKeyPrice.Value) * def.KeyMul));
		int num2 = Mathf.Clamp(Plugin.CfgStoreSize.Value + def.ExtraStock, 1, 12);
		for (int i = 0; i < num2; i++)
		{
			Rarity rarity = HatGen.RollRarity(rng, def.Weights, 0f);
			Func<Hat, bool> filter;
			if (def.AnimeShare <= 0f && def.WigShare <= 0f)
			{
				filter = i switch
				{
					1 => ThemeFilter(CrateType.Wig), 
					0 => ThemeFilter(CrateType.Otaku), 
					_ => null, 
				};
			}
			else
			{
				double num3 = rng.NextDouble();
				filter = ((!(num3 >= (double)def.AnimeShare)) ? ThemeFilter(CrateType.Otaku) : ((!(num3 >= (double)(def.AnimeShare + def.WigShare))) ? ThemeFilter(CrateType.Wig) : null));
			}
			HatKey hatKey = Registry.CreateUnique(rng, rarity, filter);
			int num4 = VendorPrice(hatKey, rng);
			Stock.Add(new StoreItem
			{
				Key = hatKey,
				Price = num4,
				ListPrice = num4
			});
		}
		Stock.Sort((StoreItem a, StoreItem b) => a.Key.Rarity.CompareTo(b.Key.Rarity));
		if (Plugin.CfgBoothEvents.Value || def.MysteryBias >= 1f)
		{
			Host_RollEvent(rng, def);
		}
		Plugin.Log.LogInfo((object)string.Concat("HatHunt: ", def.Name, " runs the booth on day ", num, " (", Stock.Count, " items, event ", Event, ")"));
		return true;
	}

	private static int Round5(float v)
	{
		return Mathf.Max(5, Mathf.RoundToInt(v / 5f) * 5);
	}

	private static int VendorPrice(HatKey k, Random rng)
	{
		VendorDef def = Vendors.Def;
		float num = 1f - def.PriceSpread * 0.5f + (float)rng.NextDouble() * def.PriceSpread;
		int[] array = new int[5]
		{
			Plugin.CfgPriceCommon.Value,
			Plugin.CfgPriceUncommon.Value,
			Plugin.CfgPriceRare.Value,
			Plugin.CfgPriceEpic.Value,
			Plugin.CfgPriceLegendary.Value
		};
		return Mathf.Max(1, Mathf.RoundToInt((float)array[(uint)k.Rarity] * def.PriceMul * num / 5f) * 5);
	}

	private static void Host_RollEvent(Random rng, VendorDef v)
	{
		bool flag = false;
		if (v.MysteryBias >= 1f)
		{
			Host_AddMystery(rng, new float[5] { 0f, 0f, 38f, 38f, 24f });
			flag = true;
			if (!Plugin.CfgBoothEvents.Value || rng.NextDouble() < 0.5)
			{
				return;
			}
		}
		double num = rng.NextDouble();
		if (num < 1.0 - (double)v.EventChance)
		{
			return;
		}
		num = rng.NextDouble();
		double num2 = 0.33;
		double num3 = 0.27 + (double)v.MysteryBias;
		double num4 = 0.2;
		double num5 = 0.2 + (double)v.HaggleBias;
		if (flag)
		{
			num3 = 0.0;
		}
		double num6 = num2 + num3 + num4 + num5;
		num *= num6;
		if (num < num2)
		{
			Event = BoothEvent.FlashSale;
			StoreItem storeItem = Stock[rng.Next(Stock.Count)];
			storeItem.Price = Round5((float)storeItem.ListPrice * 0.5f);
			return;
		}
		if (num < num2 + num3)
		{
			Host_AddMystery(rng, new float[5] { 0f, 0f, 55f, 33f, 12f });
			return;
		}
		if (num < num2 + num3 + num4)
		{
			Event = BoothEvent.Deal;
			int num7 = Mathf.Max(5, Mathf.RoundToInt((float)Plugin.CfgPriceLegendary.Value * v.PriceMul));
			StoreItem storeItem2 = new StoreItem();
			storeItem2.Price = Round5((float)num7 * 0.55f);
			storeItem2.ListPrice = num7;
			StoreItem storeItem3 = storeItem2;
			if (rng.NextDouble() < (double)v.DealReal)
			{
				storeItem3.Key = Registry.CreateUnique(rng, Rarity.Legendary);
			}
			else
			{
				storeItem3.Scam = true;
				storeItem3.Key = Registry.CreateUnique(rng, (rng.NextDouble() >= 0.7) ? Rarity.Uncommon : Rarity.Common);
				storeItem3.Shown = new HatKey(rng.Next(int.MinValue, int.MaxValue), Rarity.Legendary, Registry.NextSerial + rng.Next(0, 3));
			}
			Stock.Add(storeItem3);
			return;
		}
		Event = BoothEvent.Haggle;
		foreach (StoreItem item in Stock)
		{
			item.Price = Round5((float)item.ListPrice * 0.8f);
		}
	}

	private static void Host_AddMystery(Random rng, float[] weights)
	{
		Event = BoothEvent.Mystery;
		Rarity rarity = HatGen.RollRarity(rng, weights, 0f);
		HatKey key = Registry.CreateUnique(rng, rarity);
		int num = Round5((240f + (float)rng.NextDouble() * 60f) * Vendors.Def.PriceMul);
		Stock.Add(new StoreItem
		{
			Key = key,
			Price = num,
			ListPrice = num,
			Mystery = true
		});
	}

	private static int PriceOf(HatKey k, Random rng)
	{
		int[] array = new int[5]
		{
			Plugin.CfgPriceCommon.Value,
			Plugin.CfgPriceUncommon.Value,
			Plugin.CfgPriceRare.Value,
			Plugin.CfgPriceEpic.Value,
			Plugin.CfgPriceLegendary.Value
		};
		float num = 0.85f + (float)rng.NextDouble() * 0.3f;
		return Mathf.Max(1, Mathf.RoundToInt((float)array[(uint)k.Rarity] * num / 5f) * 5);
	}

	private static byte[] StockPayload()
	{
		return HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(StockDay);
			w.Write(KeyPrice);
			w.Write((byte)Event);
			w.Write(Stock.Count);
			foreach (StoreItem item in Stock)
			{
				if (item.Mystery)
				{
					HatNet.WriteKey(w, null);
				}
				else
				{
					HatNet.WriteKey(w, item.Display);
				}
				w.Write(item.Price);
				w.Write(item.ListPrice);
				w.Write(item.Sold);
				w.Write(item.Mystery);
				w.Write(item.PreOwned);
			}
			w.Write((byte)Vendors.Current);
		});
	}

	public static void Host_SendStock(ulong client)
	{
		if (HatNet.IsHost)
		{
			Host_EnsureStock();
			HatNet.ToClient("HatHunt.Stock", client, StockPayload());
		}
	}

	public static void Host_OnBuy(ulong sender, byte[] data)
	{
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: 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_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0304: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Unknown result type (might be due to invalid IL or missing references)
		//IL_0315: Unknown result type (might be due to invalid IL or missing references)
		//IL_031a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0465: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		if (!HatNet.IsHost)
		{
			return;
		}
		Vector3? val = null;
		HatKey? hatKey = null;
		int num;
		int num2;
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			num = binaryReader.ReadInt32();
			num2 = binaryReader.ReadInt32();
			if (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length && binaryReader.ReadBoolean())
			{
				val = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			if (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
			{
				hatKey = HatNet.ReadKey(binaryReader);
			}
		}
		int idx = HatManager.PlayerIndexOf(sender);
		if (idx < 0)
		{
			return;
		}
		if (!CanShop())
		{
			Host_Notice(sender, "The booth is only open at the Company.");
			return;
		}
		Host_EnsureStock();
		Terminal val2 = FindTerminal();
		if ((Object)(object)val2 == (Object)null)
		{
			Host_Notice(sender, "Terminal not found.");
			return;
		}
		int num3;
		if (num < 0)
		{
			num2 = Mathf.Clamp(num2, 1, 20);
			num3 = KeyPrice * num2;
		}
		else
		{
			if (num >= Stock.Count)
			{
				Host_Notice(sender, "No such store item.");
				return;
			}
			if (Stock[num].Sold)
			{
				Host_Notice(sender, "Sorry, that one just sold.");
				HatNet.ToAll("HatHunt.Stock", StockPayload());
				return;
			}
			if (hatKey.HasValue && !Stock[num].Mystery && !Stock[num].Display.Equals(hatKey.Value))
			{
				Host_Notice(sender, "The stock just changed - take another look.");
				HatNet.ToAll("HatHunt.Stock", StockPayload());
				return;
			}
			num3 = Stock[num].Price;
		}
		if (val2.groupCredits < num3)
		{
			Host_Notice(sender, "Not enough credits (" + num3 + " needed, you have " + val2.groupCredits + ").");
			return;
		}
		val2.groupCredits -= num3;
		try
		{
			val2.SyncGroupCreditsClientRpc(val2.groupCredits, val2.numberOfItemsInDropship);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Credit sync failed: " + ex.Message));
		}
		Vector3 pos = WorldLoot.BoothDropPoint(idx);
		PlayerControllerB val3 = (((Object)(object)StartOfRound.Instance != (Object)null && idx < StartOfRound.Instance.allPlayerScripts.Length) ? StartOfRound.Instance.allPlayerScripts[idx] : null);
		if (val.HasValue && (Object)(object)val3 != (Object)null)
		{
			Vector3 val4 = val.Value - ((Component)val3).transform.position;
			if (((Vector3)(ref val4)).sqrMagnitude < 64f)
			{
				pos = val.Value;
			}
		}
		if (num < 0)
		{
			if (!((Object)(object)WorldLoot.Host_SpawnVanillaKey(pos, inFactory: false) != (Object)null))
			{
				Host_Grant(idx, 0, 0, 1, 1);
			}
			HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write("<color=#FFD54A>" + HatManager.PlayerName(idx) + "</color> bought a key from " + Vendors.Def.Name + ".");
			}));
			HatNet.ToClient("HatHunt.Notice", sender, HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write(Vendors.Def.Name + " slides a key across the counter.");
			}));
			return;
		}
		StoreItem storeItem = Stock[num];
		storeItem.Sold = true;
		if (storeItem.PreOwned)
		{
			soldThisSession.Remove(storeItem.Key);
		}
		HatKey key = storeItem.Key;
		Hat hat = HatGen.Generate(key);
		string text = "<color=#FFD54A>" + HatManager.PlayerName(idx) + "</color>";
		string text2 = string.Concat("<color=", HatGen.RarityHex(key.Rarity), ">[", key.Rarity, "]</color> ", hat.RichName());
		bool flag = (Object)(object)WorldLoot.Host_SpawnHat(key, pos, inFactory: false) != (Object)null;
		if (!flag)
		{
			HatManager.Instance.Host_GiveHat(idx, key, FoundReason.Store, "");
		}
		string chat;
		string notice;
		if (storeItem.Scam)
		{
			chat = text + " bought the 'Legendary' deal of the century... it's a " + text2 + ". " + Vendors.Def.Name + " won't make eye contact.";
			notice = "Wait... that's not the hat that was on the counter. No refunds.";
		}
		else if (storeItem.Mystery)
		{
			chat = text + " unwrapped " + Vendors.Def.Name + "'s mystery hat: " + text2 + "!";
			notice = "You pull the tarp off: " + text2 + ". It's in front of the booth.";
		}
		else
		{
			chat = text + " bought a " + text2 + " from " + Vendors.Def.Name + ".";
			notice = "Sold. It's on the ground in front of the booth - pick it up and put it on.";
		}
		if (flag)
		{
			HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write(chat);
			}));
			HatNet.ToClient("HatHunt.Notice", sender, HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write(notice);
			}));
		}
		HatNet.ToAll("HatHunt.Stock", StockPayload());
	}

	public static int SellPrice(HatKey k)
	{
		int[] array = new int[5]
		{
			Plugin.CfgPriceCommon.Value,
			Plugin.CfgPriceUncommon.Value,
			Plugin.CfgPriceRare.Value,
			Plugin.CfgPriceEpic.Value,
			Plugin.CfgPriceLegendary.Value
		};
		float num = 0.9f + 0.2f * ((float)(k.Seed & 0xFFFF) / 65535f);
		return Round5((float)array[(uint)k.Rarity] * Vendors.Def.SellMul * num);
	}

	public static void Host_OnSell(ulong sender, byte[] data)
	{
		if (!HatNet.IsHost)
		{
			return;
		}
		HatKey? hatKey;
		using (BinaryReader r = HatNet.Reader(data))
		{
			hatKey = HatNet.ReadKey(r);
		}
		int num = HatManager.PlayerIndexOf(sender);
		if (!hatKey.HasValue || num < 0)
		{
			return;
		}
		if (!CanShop())
		{
			Host_Notice(sender, "The booth is only open at the Company.");
			return;
		}
		HatKey k = hatKey.Value;
		if (soldThisSession.Contains(k))
		{
			Host_Notice(sender, "\"You already sold me that one.\"");
			return;
		}
		Terminal val = FindTerminal();
		if ((Object)(object)val == (Object)null)
		{
			Host_Notice(sender, "Terminal not found.");
			return;
		}
		Host_EnsureStock();
		soldThisSession.Add(k);
		int price = SellPrice(k);
		val.groupCredits += price;
		try
		{
			val.SyncGroupCreditsClientRpc(val.groupCredits, val.numberOfItemsInDropship);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Credit sync failed: " + ex.Message));
		}
		Random rng = HatManager.Instance.Rng;
		int num2 = 0;
		for (int num3 = Stock.Count - 1; num3 >= 0; num3--)
		{
			if (Stock[num3].PreOwned && !Stock[num3].Sold && ++num2 >= 6)
			{
				Stock.RemoveAt(num3);
			}
		}
		int num4 = VendorPrice(k, rng);
		Stock.Add(new StoreItem
		{
			Key = k,
			Price = num4,
			ListPrice = num4,
			PreOwned = true
		});
		HatNet.ToAll("HatHunt.Stock", StockPayload());
		Hat hat = HatGen.Generate(k);
		string who = "<color=#FFD54A>" + HatManager.PlayerName(num) + "</color>";
		HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(string.Concat(who, " sold a <color=", HatGen.RarityHex(k.Rarity), ">[", k.Rarity, "]</color> ", hat.RichName(), " to ", Vendors.Def.Name, " for $", price, "."));
		}));
		HatNet.ToClient("HatHunt.SellOk", sender, HatNet.Build(delegate(BinaryWriter w)
		{
			HatNet.WriteKey(w, k);
			w.Write(price);
		}));
	}

	public static string RequestSell(HatKey k)
	{
		if (Busy)
		{
			return "Hang on... (waiting for the host)";
		}
		if (!HatNet.Online)
		{
			return "You need to be in a lobby.";
		}
		if (!CanShop())
		{
			return "The booth only trades at the Company.";
		}
		if (!Collection.Hats.Contains(k))
		{
			return "You don't have that hat any more.";
		}
		SetPending(Pending.Sell);
		HatNet.ToHost("HatHunt.Sell", HatNet.Build(delegate(BinaryWriter w)
		{
			HatNet.WriteKey(w, k);
		}));
		return null;
	}

	public static void Client_OnSellOk(byte[] data)
	{
		HatKey? hatKey;
		int num;
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			hatKey = HatNet.ReadKey(binaryReader);
			num = binaryReader.ReadInt32();
		}
		if (pending == Pending.Sell)
		{
			pending = Pending.None;
		}
		if (hatKey.HasValue)
		{
			Hat hat = HatGen.Generate(hatKey.Value);
			bool flag = Collection.Equipped.HasValue && Collection.Equipped.Value.Equals(hatKey.Value);
			List<HatKey> list = new List<HatKey>();
			list.Add(hatKey.Value);
			Collection.RemoveAll(list);
			if ((Object)(object)HatManager.Instance != (Object)null)
			{
				HatManager.Instance.Equip(Collection.EquippedIndex);
			}
			string text = "Sold " + hat.RichName() + " for <color=#FFD54A>$" + num + "</color>." + (flag ? " (You were wearing it.)" : "");
			if (ShopWindow.IsOpen)
			{
				ShopWindow.OnNotice(text);
			}
			else
			{
				HatInteraction.Flash(text, 3f);
			}
			RefreshTerminalIfOpen();
		}
	}

	public static void Client_OnStock(byte[] data)
	{
		LastStockAt = Time.time;
		if (HatNet.IsHost)
		{
			RefreshTerminalIfOpen();
			return;
		}
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			StockDay = binaryReader.ReadInt32();
			KeyPrice = binaryReader.ReadInt32();
			Event = (BoothEvent)binaryReader.ReadByte();
			int num = binaryReader.ReadInt32();
			Stock.Clear();
			for (int i = 0; i < num; i++)
			{
				HatKey? hatKey = HatNet.ReadKey(binaryReader);
				int price = binaryReader.ReadInt32();
				int listPrice = binaryReader.ReadInt32();
				bool sold = binaryReader.ReadBoolean();
				bool flag = binaryReader.ReadBoolean();
				bool preOwned = binaryReader.ReadBoolean();
				if (hatKey.HasValue || flag)
				{
					Stock.Add(new StoreItem
					{
						Key = (hatKey.HasValue ? hatKey.Value : default(HatKey)),
						Price = price,
						ListPrice = listPrice,
						Sold = sold,
						Mystery = flag,
						PreOwned = preOwned
					});
				}
			}
			if (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
			{
				int num2 = binaryReader.ReadByte();
				if (num2 < Vendors.All.Length)
				{
					Vendors.Current = (VendorId)num2;
				}
			}
		}
		RefreshTerminalIfOpen();
	}

	public static void Client_OnGrant(byte[] data)
	{
		int idx;
		byte b;
		int num;
		byte b3;
		byte b2;
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			idx = binaryReader.ReadInt32();
			b = binaryReader.ReadByte();
			b2 = binaryReader.ReadByte();
			num = binaryReader.ReadInt32();
			b3 = binaryReader.ReadByte();
		}
		b2 = (byte)Mathf.Clamp((int)b2, 0, 3);
		string text = ((b != 0) ? ("a <color=" + CrateHex[b2] + ">" + CrateNames[b2] + "</color>") : ((num > 1) ? (num + " Hat Keys") : "a Hat Key"));
		HatManager.ChatPublic("<color=#FFD54A>" + HatManager.PlayerName(idx) + "</color> " + ((b3 == 1) ? "bought " : "found ") + text + "!");
		if (!HatManager.IsLocalIndex(idx))
		{
			return;
		}
		if (b == 0)
		{
			Collection.Keys += num;
			if (b3 == 1 && pending == Pending.Buy)
			{
				pending = Pending.None;
			}
			HatManager.TipPublic((b3 == 1) ? "Purchased!" : "You found a Hat Key!", "Keys: " + Collection.Keys + "\nUse it at the terminal: hats open");
		}
		else
		{
			Collection.Crates[b2] += num;
			HatManager.TipPublic("You found a " + CrateNames[b2] + "!", "Contains " + CrateBlurb[b2] + ".\nNeeds a Hat Key. Terminal: hats crates");
		}
		Collection.Save();
		HatManager.PlayJingle();
		RefreshTerminalIfOpen();
	}

	public static void Client_OnNotice(byte[] data)
	{
		string text;
		using (BinaryReader binaryReader = HatNet.Reader(data))
		{
			text = binaryReader.ReadString();
		}
		pending = Pending.None;
		pendingTrade.Clear();
		if (ShopWindow.IsOpen)
		{
			ShopWindow.OnNotice(text);
		}
		else
		{
			HatManager.TipPublic("Hat Hunt", text);
			HatInteraction.Flash(text, 3f);
		}
		LastResult = "<color=#FF7B7B>" + text + "</color>";
		LastResultTime = Time.time;
		RefreshTerminalIfOpen();
	}

	public static void OnLocalHatResult(FoundReason reason)
	{
		if (reason == FoundReason.TradeUp && pending == Pending.Trade)
		{
			Collection.RemoveAll(pendingTrade);
			pendingTrade.Clear();
			pending = Pending.None;
			HatManager.Instance.Equip(Collection.EquippedIndex);
		}
		else if (reason == FoundReason.Crate && pending == Pending.Open)
		{
			Collection.Keys = Math.Max(0, Collection.Keys - 1);
			Collection.Crates[(uint)pendingCrate] = Math.Max(0, Collection.Crates[(uint)pendingCrate] - 1);
			Collection.Save();
			pending = Pending.None;
		}
		else if (reason == FoundReason.Store && pending == Pending.Buy)
		{
			pending = Pending.None;
		}
	}

	public static void RefreshTerminalIfOpen()
	{
		TerminalMenu.Redraw();
	}

	public static string RequestTrade(List<HatKey> chosen)
	{
		int num = Mathf.Max(2, Plugin.CfgTradeCount.Value);
		if (Busy)
		{
			return "Waiting for the host to answer your last request...";
		}
		if (!HatNet.Online)
		{
			return "You need to be in a lobby.";
		}
		if (chosen.Count != num)
		{
			return "Pick exactly " + num + " hats.";
		}
		Rarity rarity = chosen[0].Rarity;
		if (chosen.Any((HatKey k) => k.Rarity != rarity))
		{
			return "All hats must be the same rarity.";
		}
		if (rarity == Rarity.Legendary)
		{
			return "Legendary is already the top rarity.";
		}
		pendingTrade = new List<HatKey>(chosen);
		SetPending(Pending.Trade);
		HatNet.ToHost("HatHunt.Trade", HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(chosen.Count);
			foreach (HatKey item in chosen)
			{
				HatNet.WriteKey(w, item);
			}
		}));
		return null;
	}

	public static List<HatKey> AutoPick(Rarity r)
	{
		int num = Mathf.Max(2, Plugin.CfgTradeCount.Value);
		List<HatKey> list = new List<HatKey>();
		for (int i = 0; i < Collection.Hats.Count; i++)
		{
			if (list.Count >= num)
			{
				break;
			}
			if (Collection.Hats[i].Rarity == r && i != Collection.EquippedIndex)
			{
				list.Add(Collection.Hats[i]);
			}
		}
		return list;
	}

	public static string RequestOpen(CrateType t)
	{
		if (Busy)
		{
			return "Waiting for the host to answer your last request...";
		}
		if (!HatNet.Online)
		{
			return "You need to be in a lobby.";
		}
		if (Collection.Crates[(uint)t] <= 0)
		{
			return "You don't have a " + CrateNames[(uint)t] + ".";
		}
		if (Collection.Keys <= 0)
		{
			return "You need a Hat Key. Buy one at the shady booth at the Company.";
		}
		pendingCrate = t;
		SetPending(Pending.Open);
		HatNet.ToHost("HatHunt.Open", HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write((byte)t);
		}));
		return null;
	}

	public static string RequestBuy(int slot)
	{
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		if (Busy)
		{
			return "Hang on... (waiting for the host)";
		}
		if (!HatNet.Online)
		{
			return "You need to be in a lobby.";
		}
		if (!CanShop())
		{
			return "The booth only trades at the Company.";
		}
		if (slot >= 0 && (slot >= Stock.Count || Stock[slot].Sold))
		{
			return "Sold out.";
		}
		int num = ((slot < 0) ? KeyPrice : Stock[slot].Price);
		int num2 = Credits();
		if (num2 >= 0 && num2 < num)
		{
			return "Not enough credits.";
		}
		SetPending(Pending.Buy);
		Vector3? drop = null;
		if ((Object)(object)HatBooth.Instance != (Object)null)
		{
			drop = ((Component)HatBooth.Instance).transform.TransformPoint(new Vector3(Random.Range(-0.4f, 0.4f), 0.4f, 1.15f));
		}
		HatNet.ToHost("HatHunt.Buy", HatNet.Build(delegate(BinaryWriter w)
		{
			//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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			w.Write(slot);
			w.Write(1);
			w.Write(drop.HasValue);
			if (drop.HasValue)
			{
				w.Write(drop.Value.x);
				w.Write(drop.Value.y);
				w.Write(drop.Value.z);
			}
			HatNet.WriteKey(w, (slot >= 0 && !Stock[slot].Mystery) ? new HatKey?(Stock[slot].Display) : ((HatKey?)null));
		}));
		return null;
	}

	public static int Credits()
	{
		if ((Object)(object)cachedTerminal == (Object)null)
		{
			cachedTerminal = FindTerminal();
		}
		return ((Object)(object)cachedTerminal != (Object)null) ? cachedTerminal.groupCredits : (-1);
	}

	public static string CrateName(int i)
	{
		return "<color=" + CrateHex[i] + ">" + CrateNames[i] + "</color>";
	}

	public static string CrateInfo(int i)
	{
		return CrateBlurb[i];
	}

	public static string RarityTag(Rarity r)
	{
		return Tag(r);
	}
}
public enum EffectType : byte
{
	Swiftness,
	Springy,
	Endurance,
	SecondWind,
	Toughness,
	Featherfall,
	Regeneration,
	LongReach,
	Climber,
	Fortune,
	Lantern,
	Sluggish,
	Heavy,
	Wheezy,
	Fragile
}
public static class Encounters
{
	private class Runaway
	{
		public HatItem Item;

		public int Hops;

		public float CalmUntil;

		public bool Announced;
	}

	public static bool VendorActive;

	private static int vendorLevel = -1;

	private static Vector3 vendorPos;

	private static float vendorYaw;

	private static int lastLandingKey = int.MinValue;

	private static bool landedHandled;

	private static Vector3? pendingGuardAt;

	private static string pendingRumour;

	private static float nextRunawayCheck;

	private static readonly List<Runaway> runaways = new List<Runaway>();

	private const byte EvVendor = 1;

	private const byte EvFlash = 2;

	private const byte EvCrateFx = 3;

	private static Random Rng => HatManager.Instance.Rng;

	public static void ResetSession()
	{
		VendorActive = false;
		vendorLevel = -1;
		lastLandingKey = int.MinValue;
		landedHandled = false;
		pendingGuardAt = null;
		pendingRumour = null;
		runaways.Clear();
	}

	public static void Tick()
	{
		StartOfRound instance = StartOfRound.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (VendorActive && (instance.inShipPhase || (Object)(object)instance.currentLevel == (Object)null || instance.currentLevel.levelID != vendorLevel))
		{
			VendorActive = false;
		}
		if (!HatNet.IsHost)
		{
			return;
		}
		if (instance.inShipPhase || !instance.shipHasLanded || (Object)(object)instance.currentLevel == (Object)null)
		{
			landedHandled = false;
			return;
		}
		int num = instance.randomMapSeed * 31 + instance.currentLevel.levelID;
		if (num != lastLandingKey || !landedHandled)
		{
			lastLandingKey = num;
			landedHandled = true;
			Host_OnLanded(instance);
		}
	}

	public static void FastTick()
	{
		if (!HatNet.IsHost || runaways.Count == 0 || Time.time < nextRunawayCheck)
		{
			return;
		}
		nextRunawayCheck = Time.time + 0.1f;
		try
		{
			Host_CheckRunaways();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("runaway hat: " + ex.Message));
		}
	}

	private static void Host_OnLanded(StartOfRound sor)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		if (!Economy.AtCompany() && Rng.NextDouble() * 100.0 < (double)Plugin.CfgVendorChance.Value)
		{
			if (FindVendorSpot(sor, out var pos, out var yaw))
			{
				VendorActive = true;
				vendorLevel = sor.currentLevel.levelID;
				vendorPos = pos;
				vendorYaw = yaw;
				Economy.Host_PrepareStock();
				HatNet.ToAll("HatHunt.Encounter", VendorPayload());
				HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
				{
					w.Write("<color=#FFD54A>Psst...</color> <color=" + Vendors.Def.Hex + ">" + Vendors.Def.Name + "</color> set up a booth outside, not far from the ship. Hats & keys, credits only.");
				}));
				Plugin.Log.LogInfo((object)("HatHunt: the vendor set up shop at " + pos));
			}
		}
		else if (VendorActive)
		{
			VendorActive = false;
			HatNet.ToAll("HatHunt.Encounter", VendorPayload());
		}
		if (pendingRumour != null)
		{
			string r = pendingRumour;
			HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write(r);
			}));
			pendingRumour = null;
		}
		if (pendingGuardAt.HasValue)
		{
			try
			{
				Host_SpawnGuard(pendingGuardAt.Value);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("stash guard: " + ex.Message));
			}
			pendingGuardAt = null;
		}
	}

	private static byte[] VendorPayload()
	{
		return HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(1);
			w.Write(VendorActive);
			w.Write(vendorLevel);
			w.Write(vendorPos.x);
			w.Write(vendorPos.y);
			w.Write(vendorPos.z);
			w.Write(vendorYaw);
		});
	}

	public static void Host_CrateFx(Vector3 p, Quaternion q, CrateType t, HatKey key)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		HatNet.ToAll("HatHunt.Encounter", HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(3);
			w.Write(p.x);
			w.Write(p.y);
			w.Write(p.z);
			w.Write(q.x);
			w.Write(q.y);
			w.Write(q.z);
			w.Write(q.w);
			w.Write((byte)t);
			HatNet.WriteKey(w, key);
		}));
	}

	public static void Host_SyncTo(ulong client)
	{
		if (HatNet.IsHost && VendorActive)
		{
			HatNet.ToClient("HatHunt.Encounter", client, VendorPayload());
		}
	}

	private static bool FindVendorSpot(StartOfRound sor, out Vector3 pos, out float yaw)
	{
		//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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0301: Unknown result type (might be due to invalid IL or missing references)
		//IL_0306: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_032b: Unknown result type (might be due to invalid IL or missing references)
		//IL_036c: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0376: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		yaw = 0f;
		RoundManager instance = RoundManager.Instance;
		GameObject[] array = (((Object)(object)instance != (Object)null && instance.outsideAINodes != null && instance.outsideAINodes.Length > 0) ? instance.outsideAINodes : GameObject.FindGameObjectsWithTag("OutsideAINode"));
		if (array == null || array.Length == 0)
		{
			return false;
		}
		Vector3 position = sor.elevatorTransform.position;
		int num = LayerMask.NameToLayer("Player");
		int num2 = sor.collidersAndRoomMaskAndDefault & -5 & ~((num >= 0) ? (1 << num) : 0);
		List<GameObject> list = new List<GameObject>(array);
		for (int num3 = list.Count - 1; num3 > 0; num3--)
		{
			int index = Rng.Next(num3 + 1);
			GameObject value = list[num3];
			list[num3] = list[index];
			list[index] = value;
		}
		RaycastHit val = default(RaycastHit);
		RaycastHit val7 = default(RaycastHit);
		foreach (GameObject item in list)
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			Vector3 position2 = item.transform.position;
			float num4 = Vector3.Distance(new Vector3(position2.x, 0f, position2.z), new Vector3(position.x, 0f, position.z));
			if (!(num4 >= 14f) || !(num4 <= 48f) || !Physics.Raycast(position2 + Vector3.up * 6f, Vector3.down, ref val, 14f, num2, (QueryTriggerInteraction)1) || !(((RaycastHit)(ref val)).normal.y >= 0.88f))
			{
				continue;
			}
			Vector3 point = ((RaycastHit)(ref val)).point;
			Vector3 val2 = position - point;
			val2.y = 0f;
			if (!(((Vector3)(ref val2)).sqrMagnitude >= 0.01f))
			{
				continue;
			}
			Quaternion val3 = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up);
			if (Physics.CheckBox(point + val3 * HatBooth.CheckCenter, HatBooth.CheckExtents, val3, num2, (QueryTriggerInteraction)1))
			{
				continue;
			}
			bool flag = true;
			Vector3[] array2 = (Vector3[])(object)new Vector3[4]
			{
				new Vector3(-2.4f, 0f, -0.85f),
				new Vector3(2.4f, 0f, -0.85f),
				new Vector3(-2.4f, 0f, 1.25f),
				new Vector3(2.4f, 0f, 1.25f)
			};
			foreach (Vector3 val4 in array2)
			{
				Vector3 val5 = val4 * (HatBooth.Scale / 1.4f);
				Vector3 val6 = point + val3 * val5;
				if (!Physics.Raycast(val6 + Vector3.up * 1.5f, Vector3.down, ref val7, 3f, num2, (QueryTriggerInteraction)1) || Mathf.Abs(((RaycastHit)(ref val7)).point.y - point.y) > 0.45f)
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				pos = point;
				yaw = ((Quaternion)(ref val3)).eulerAngles.y;
				return true;
			}
		}
		return false;
	}

	public static bool VendorHere(out Scene scene, out Vector3 pos, out Quaternion rot)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: 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_0015: 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_002f: 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)
		scene = default(Scene);
		pos = vendorPos;
		rot = Quaternion.Euler(0f, vendorYaw, 0f);
		StartOfRound instance = StartOfRound.Instance;
		if (!VendorActive || (Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null || instance.inShipPhase || instance.currentLevel.levelID != vendorLevel)
		{
			return false;
		}
		scene = SceneManager.GetSceneByName(instance.currentLevel.sceneName);
		return ((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded;
	}

	public static void Client_OnEncounter(byte[] data)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = HatNet.Reader(data);
		switch (binaryReader.ReadByte())
		{
		case 1:
		{
			bool vendorActive = binaryReader.ReadBoolean();
			int num = binaryReader.ReadInt32();
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			float num2 = binaryReader.ReadSingle();
			if (!HatNet.IsHost)
			{
				VendorActive = vendorActive;
				vendorLevel = num;
				vendorPos = val;
				vendorYaw = num2;
			}
			break;
		}
		case 2:
		{
			string text = binaryReader.ReadString();
			HatInteraction.Flash(text, 3f);
			break;
		}
		case 3:
		{
			Vector3 pos = default(Vector3);
			((Vector3)(ref pos))..ctor(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			Quaternion rot = default(Quaternion);
			((Quaternion)(ref rot))..ctor(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			CrateType type = (CrateType)Mathf.Clamp((int)binaryReader.ReadByte(), 0, 3);
			HatKey? key = HatNet.ReadKey(binaryReader);
			CrateFx.Play(pos, rot, type, key);
			break;
		}
		}
	}

	public static void Host_OnLevelLoot(List<HatItem> spawnedHats)
	{
		if (!HatNet.IsHost)
		{
			return;
		}
		runaways.Clear();
		pendingGuardAt = null;
		pendingRumour = null;
		RoundManager instance = RoundManager.Instance;
		if ((Object)(object)instance == (Object)null || Economy.AtCompany())
		{
			return;
		}
		if (Rng.NextDouble() * 100.0 < (double)Plugin.CfgStashChance.Value)
		{
			try
			{
				Host_SpawnStash(instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("hat stash: " + ex.Message));
			}
		}
		if (spawnedHats.Count > 0 && Rng.NextDouble() * 100.0 < (double)Plugin.CfgRunawayChance.Value)
		{
			HatItem hatItem = spawnedHats[Rng.Next(spawnedHats.Count)];
			if ((Object)(object)hatItem != (Object)null && hatItem.HasKey && ((GrabbableObject)hatItem).isInFactory)
			{
				WorldLoot.Host_SetFlags(hatItem, 1);
				runaways.Add(new Runaway
				{
					Item = hatItem,
					Hops = 3,
					CalmUntil = 0f
				});
				Plugin.Log.LogInfo((object)"HatHunt: one of today's hats is a runaway.");
			}
		}
	}

	private static bool FloorAt(Vector3 near, float spread, out Vector3 floor)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		floor = near;
		StartOfRound instance = StartOfRound.Instance;
		RaycastHit val2 = default(RaycastHit);
		for (int i = 0; i < 8; i++)
		{
			Vector3 val = new Vector3((float)Rng.NextDouble() - 0.5f, 0f, (float)Rng.NextDouble() - 0.5f) * spread * 2f;
			if (Physics.Raycast(near + val + Vector3.up * 1.2f, Vector3.down, ref val2, 4f, instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val2)).normal.y > 0.7f)
			{
				floor = ((RaycastHit)(ref val2)).point + Vector3.up * 0.25f;
				return true;
			}
		}
		return false;
	}

	private static void Host_SpawnStash(RoundManager rm)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0299: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		GameObject[] insideAINodes = rm.insideAINodes;
		if (insideAINodes == null || insideAINodes.Length == 0)
		{
			return;
		}
		Vector3 val = Vector3.zero;
		EntranceTeleport val2 = null;
		float num = float.MaxValue;
		Vector3 val3 = (((Object)(object)insideAINodes[0] != (Object)null) ? insideAINodes[0].transform.position : Vector3.zero);
		EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>();
		foreach (EntranceTeleport val4 in array)
		{
			if (!((Object)(object)val4 == (Object)null) && val4.entranceId == 0)
			{
				Vector3 val5 = ((Component)val4).transform.position - val3;
				float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					val2 = val4;
				}
			}
		}
		if ((Object)(object)val2 != (Object)null)
		{
			val = ((Component)val2).transform.position;
		}
		GameObject val6 = null;
		float num2 = -1f;
		for (int j = 0; j < 6; j++)
		{
			GameObject val7 = insideAINodes[Rng.Next(insideAINodes.Length)];
			if (!((Object)(object)val7 == (Object)null))
			{
				float num3 = (((Object)(object)val2 != (Object)null) ? Vector3.Distance(val7.transform.position, val) : ((float)Rng.NextDouble()));
				if (num3 > num2)
				{
					num2 = num3;
					val6 = val7;
				}
			}
		}
		if ((Object)(object)val6 == (Object)null)
		{
			return;
		}
		Vector3 position = val6.transform.position;
		int num4 = 0;
		for (int k = 0; k < 3; k++)
		{
			if (FloorAt(position, 0.9f, out var floor))
			{
				Rarity rarity = HatGen.RollRarity(Rng, HatManager.Instance.DropWeights(), 0.8f);
				if ((Object)(object)WorldLoot.Host_SpawnHat(Registry.CreateUnique(Rng, rarity), floor, inFactory: true) != (Object)null)
				{
					num4++;
				}
			}
		}
		if (FloorAt(position, 0.7f, out var floor2))
		{
			double num5 = Rng.NextDouble();
			CrateType t = ((!(num5 >= 0.25)) ? CrateType.Golden : ((!(num5 >= 0.5)) ? CrateType.Otaku : ((!(num5 >= 0.7)) ? CrateType.Wig : CrateType.Scavenger)));
			if ((Object)(object)WorldLoot.Host_SpawnCrate(t, floor2, inFactory: true) != (Object)null)
			{
				num4++;
			}
		}
		if (FloorAt(position, 0.7f, out var floor3) && (Object)(object)WorldLoot.Host_SpawnVanillaKey(floor3, inFactory: true) != (Object)null)
		{
			num4++;
		}
		if (num4 != 0)
		{
			if (Plugin.CfgStashGuard.Value)
			{
				pendingGuardAt = position;
			}
			pendingRumour = (Plugin.CfgStashGuard.Value ? "<color=#FFD54A>Rumour has it</color> someone stashed a pile of hats somewhere in this facility... <color=#FF7B7B>and something is guarding it.</color>" : "<color=#FFD54A>Rumour has it</color> someone stashed a pile of hats somewhere in this facility.");
			Plugin.Log.LogInfo((object)string.Concat("HatHunt: hat stash at ", position, " (", num4, " items)"));
		}
	}

	private static void Host_SpawnGuard(Vector3 at)
	{
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0263: Unknown result type (might be due to invalid IL or missing references)
		RoundManager instance = RoundManager.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null || instance.currentLevel.Enemies == null || instance.currentLevel.Enemies.Count == 0)
		{
			return;
		}
		EnemyType val = null;
		string[] array = new string[6] { "hoard", "spider", "crawler", "centipede", "spring", "puffer" };
		foreach (string value in array)
		{
			foreach (SpawnableEnemyWithRarity enemy in instance.currentLevel.Enemies)
			{
				if (enemy != null && (Object)(object)enemy.enemyType != (Object)null && (Object)(object)enemy.enemyType.enemyPrefab != (Object)null && enemy.enemyType.enemyName != null && enemy.enemyType.enemyName.ToLowerInvariant().Contains(value))
				{
					val = enemy.enemyType;
					break;
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			foreach (SpawnableEnemyWithRarity enemy2 in instance.currentLevel.Enemies)
			{
				if (enemy2 != null && (Object)(object)enemy2.enemyType != (Object)null && (Object)(object)enemy2.enemyType.enemyPrefab != (Object)null && !enemy2.enemyType.isOutsideEnemy)
				{
					val = enemy2.enemyType;
					break;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		Vector3 val2 = at;
		bool flag = false;
		NavMeshHit val4 = default(NavMeshHit);
		for (int j = 0; j < 6; j++)
		{
			if (flag)
			{
				break;
			}
			Vector3 val3 = new Vector3((float)Rng.NextDouble() - 0.5f, 0f, (float)Rng.NextDouble() - 0.5f) * 6f;
			if (NavMesh.SamplePosition(at + val3, ref val4, 4f, -1))
			{
				val2 = ((NavMeshHit)(ref val4)).position;
				flag = true;
			}
		}
		if (flag)
		{
			instance.SpawnEnemyGameObject(val2, (float)Rng.NextDouble() * 360f, -1, val);
			Plugin.Log.LogInfo((object)("HatHunt: a " + val.enemyName + " guards the hat stash."));
		}
	}

	private static void Host_CheckRunaways()
	{
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: 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)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		StartOfRound instance = StartOfRound.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		for (int num = runaways.Count - 1; num >= 0; num--)
		{
			Runaway runaway = runaways[num];
			HatItem item = runaway.Item;
			if ((Object)(object)item == (Object)null || (Object)(object)((NetworkBehaviour)item).NetworkObject == (Object)null || !((NetworkBehaviour)item).NetworkObject.IsSpawned)
			{
				runaways.RemoveAt(num);
			}
			else if (((GrabbableObject)item).isHeld || ((GrabbableObject)item).hasBeenHeld || ((GrabbableObject)item).isHeldByEnemy || ((GrabbableObject)item).heldByPlayerOnServer || (Object)(object)((GrabbableObject)item).playerHeldBy != (Object)null)
			{
				runaways.RemoveAt(num);
				if ((Object)(object)((GrabbableObject)item).playerHeldBy != (Object)null)
				{
					string who = ((GrabbableObject)item).playerHeldBy.playerUsername;
					HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
					{
						w.Write("<color=#FFD54A>" + who + "</color> caught the runaway hat!");
					}));
				}
			}
			else if (runaway.Hops > 0 && Time.time >= runaway.CalmUntil)
			{
				Vector3 val = ((Component)item).transform.position + Vector3.up * 0.15f;
				PlayerControllerB val2 = null;
				bool flag = false;
				PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
				foreach (PlayerControllerB val3 in allPlayerScripts)
				{
					if (!((Object)(object)val3 == (Object)null) && val3.isPlayerControlled && !val3.isPlayerDead)
					{
						Vector3 val4 = (((Object)(object)val3.gameplayCamera != (Object)null) ? ((Component)val3.gameplayCamera).transform.position : (((Component)val3).transform.position + Vector3.up * 1.6f));
						float num3 = Mathf.Max(3f, val3.grabDistance) + 1.5f;
						Vector3 val5 = val4 - val;
						float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
						if (sqrMagnitude < num3 * num3)
						{
							flag = true;
							break;
						}
						if (val3.isInsideFactory && sqrMagnitude <= 56.25f && !((Object)(object)val2 != (Object)null) && !Physics.Linecast(val4, val, instance.collidersAndRoomMask, (QueryTriggerInteraction)1))
						{
							val2 = val3;
						}
					}
				}
				if (flag)
				{
					runaway.CalmUntil = Time.time + 0.5f;
				}
				else if (!((Object)(object)val2 == (Object)null))
				{
					Hop(runaway, val2);
				}
			}
		}
	}

	private static void Hop(Runaway ra, PlayerControllerB spooker)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		RoundManager instance = RoundManager.Instance;
		HatItem item = ra.Item;
		if ((Object)(object)instance == (Object)null || instance.insideAINodes == null || instance.insideAINodes.Length == 0)
		{
			ra.Hops = 0;
			return;
		}
		Vector3 position = ((Component)item).transform.position;
		Vector3? val = null;
		for (int i = 0; i < 20; i++)
		{
			if (val.HasValue)
			{
				break;
			}
			GameObject val2 = instance.insideAINodes[Rng.Next(instance.insideAINodes.Length)];
			if (!((Object)(object)val2 == (Object)null))
			{
				float num = Vector3.Distance(val2.transform.position, position);
				if (num >= 7f && num <= 18f && FloorAt(val2.transform.position, 0.4f, out var floor))
				{
					val = floor;
				}
			}
		}
		if (!val.HasValue)
		{
			ra.CalmUntil = Time.time + 3f;
			return;
		}
		HatKey key = item.Key;
		int scrapValue = ((GrabbableObject)item).scrapValue;
		ulong networkObjectId = ((NetworkBehaviour)item).NetworkObjectId;
		ItemData.ById.Remove(networkObjectId);
		((NetworkBehaviour)item).NetworkObject.Despawn(true);
		HatItem hatItem = WorldLoot.Host_SpawnHat(key, val.Value, inFactory: true, scrapValue);
		ra.Hops--;
		if ((Object)(object)hatItem == (Object)null)
		{
			ra.Item = null;
			return;
		}
		WorldLoot.Host_SetFlags(hatItem, (byte)((ra.Hops > 0) ? 1u : 3u));
		ra.Item = hatItem;
		ra.CalmUntil = Time.time + 2.5f;
		string line = ((ra.Hops > 0) ? "The hat <b>skitters off</b> into the dark!" : "The hat scurries away... it looks exhausted.");
		HatNet.ToClient("HatHunt.Encounter", spooker.actualClientId, HatNet.Build(delegate(BinaryWriter w)
		{
			w.Write(2);
			w.Write(line);
		}));
		if (!ra.Announced)
		{
			ra.Announced = true;
			string who = spooker.playerUsername;
			HatNet.ToAll("HatHunt.Chat", HatNet.Build(delegate(BinaryWriter w)
			{
				w.Write("<color=#FFD54A>" + who + "</color> spooked a <color=#7FE7FF>runaway hat</color>! Catch it!");
			}));
		}
	}
}
public class FaceCamera : MonoBehaviour
{
	public Transform Target;

	private void LateUpdate()
	{
		//IL_001d: 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_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Target != (Object)null)
		{
			((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - Target.position, Vector3.up);
		}
	}
}
public enum Finish : byte
{
	Matte,
	Satin,
	Glossy,
	Metallic
}
public enum FoundReason : byte
{
	Found,
	TradeUp,
	Crate,
	Store,
	Worn
}
public class Hat
{
	public HatKey Key;

	public string Name;

	public HatDesign Design;

	public List<HatEffect> Effects = new List<HatEffect>();

	p