Decompiled source of TalkingBingBong v1.0.0

plugins/BingBong/HowToFish.BingBong.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Managing.Client;
using FishNet.Managing.Server;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Yakari")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Yakari")]
[assembly: AssemblyDescription("Squeeze Bing Bong. He squeaks, then he answers.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Talking Bing Bong")]
[assembly: AssemblyTitle("HowToFish.BingBong")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HowToFish.BingBong;

internal sealed class BingBongBeak
{
	private readonly Item _fish;

	private SkinnedMeshRenderer _source;

	private GameObject _root;

	private Transform _upper;

	private Transform _lower;

	private Quaternion _upperRest;

	private Quaternion _lowerRest;

	private Vector3 _pivot;

	private Vector3 _hingeAxisLocal = Vector3.up;

	private const int HingeSide = 1;

	private readonly List<Mesh> _meshes = new List<Mesh>();

	private static Texture2D _paletteCache;

	private static Texture _paletteSource;

	internal bool Built => (Object)(object)_root != (Object)null;

	internal SkinnedMeshRenderer Source => _source;

	internal BingBongBeak(Item fish)
	{
		//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)
		_fish = fish;
	}

	internal bool Build(Transform rootBone)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Expected O, but got Unknown
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: 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_0178: 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_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0438: Unknown result type (might be due to invalid IL or missing references)
		//IL_0442: Expected O, but got Unknown
		//IL_0455: 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_046a: Unknown result type (might be due to invalid IL or missing references)
		//IL_046f: Unknown result type (might be due to invalid IL or missing references)
		//IL_047f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_049b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0551: Unknown result type (might be due to invalid IL or missing references)
		//IL_0556: Unknown result type (might be due to invalid IL or missing references)
		//IL_0562: Unknown result type (might be due to invalid IL or missing references)
		//IL_0567: Unknown result type (might be due to invalid IL or missing references)
		//IL_056d: Unknown result type (might be due to invalid IL or missing references)
		//IL_056f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0575: Unknown result type (might be due to invalid IL or missing references)
		//IL_057a: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		Dispose();
		if ((Object)(object)_fish == (Object)null || (Object)(object)rootBone == (Object)null)
		{
			return false;
		}
		SkinnedMeshRenderer componentInChildren = ((Component)_fish).GetComponentInChildren<SkinnedMeshRenderer>(false);
		if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.sharedMesh == (Object)null)
		{
			return false;
		}
		Mesh val = new Mesh();
		componentInChildren.BakeMesh(val, true);
		if (val.vertexCount < 100)
		{
			Object.Destroy((Object)(object)val);
			return false;
		}
		Matrix4x4 val2 = ((Component)_fish).transform.worldToLocalMatrix * ((Component)componentInChildren).transform.localToWorldMatrix;
		Vector3[] vertices = val.vertices;
		Vector3[] normals = val.normals;
		for (int i = 0; i < vertices.Length; i++)
		{
			vertices[i] = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(vertices[i]);
		}
		if (normals != null && normals.Length == vertices.Length)
		{
			for (int j = 0; j < normals.Length; j++)
			{
				int num = j;
				Vector3 val3 = ((Matrix4x4)(ref val2)).MultiplyVector(normals[j]);
				normals[num] = ((Vector3)(ref val3)).normalized;
			}
		}
		Vector2[] uv = val.uv;
		int[] triangles = val.triangles;
		Texture2D val4 = Palette(((Renderer)componentInChildren).sharedMaterial);
		if ((Object)(object)val4 == (Object)null || uv == null || uv.Length != vertices.Length)
		{
			Object.Destroy((Object)(object)val);
			return false;
		}
		List<int> list = new List<int>();
		List<int> list2 = new List<int>();
		List<float> list3 = new List<float>();
		for (int k = 0; k + 2 < triangles.Length; k += 3)
		{
			int num2 = triangles[k];
			int num3 = triangles[k + 1];
			int num4 = triangles[k + 2];
			if (IsOrange(val4, uv[num2]) && IsOrange(val4, uv[num3]) && IsOrange(val4, uv[num4]))
			{
				list.Add(k);
				list3.Add((vertices[num2].z + vertices[num3].z + vertices[num4].z) / 3f);
			}
			else
			{
				list2.Add(k);
			}
		}
		if (list.Count < 50 || list.Count > 2000)
		{
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogWarning((object)("BingBong: beak classification found " + list.Count + " triangles - not splitting."));
			}
			Object.Destroy((Object)(object)val);
			return false;
		}
		List<float> list4 = new List<float>(list3);
		list4.Sort();
		float num5 = list4[list4.Count / 5];
		float num6 = list4[list4.Count * 4 / 5];
		for (int l = 0; l < 12; l++)
		{
			float num7 = 0f;
			float num8 = 0f;
			int num9 = 0;
			int num10 = 0;
			foreach (float item in list4)
			{
				if (Mathf.Abs(item - num5) <= Mathf.Abs(item - num6))
				{
					num7 += item;
					num9++;
				}
				else
				{
					num8 += item;
					num10++;
				}
			}
			if (num9 > 0)
			{
				num5 = num7 / (float)num9;
			}
			if (num10 > 0)
			{
				num6 = num8 / (float)num10;
			}
		}
		float num11 = (num5 + num6) * 0.5f;
		List<int> list5 = new List<int>();
		List<int> list6 = new List<int>();
		float num12 = float.MaxValue;
		float num13 = float.MinValue;
		float num14 = 0f;
		int num15 = 0;
		for (int m = 0; m < list.Count; m++)
		{
			int num16 = list[m];
			((list3[m] >= num11) ? list5 : list6).Add(num16);
			for (int n = 0; n < 3; n++)
			{
				Vector3 val5 = vertices[triangles[num16 + n]];
				if (val5.x < num12)
				{
					num12 = val5.x;
				}
				if (val5.x > num13)
				{
					num13 = val5.x;
				}
				num14 += val5.y;
				num15++;
			}
		}
		float num17 = (num13 - num12) * 0.12f;
		float num18 = num13 - num17;
		Vector3 pivot = default(Vector3);
		((Vector3)(ref pivot))..ctor(num18, num14 / (float)Mathf.Max(1, num15), num11);
		_source = componentInChildren;
		_root = new GameObject("YakariBingBongBeak");
		_root.transform.SetParent(rootBone, false);
		Matrix4x4 val6 = rootBone.worldToLocalMatrix * ((Component)_fish).transform.localToWorldMatrix;
		_root.transform.localPosition = Vector4.op_Implicit(((Matrix4x4)(ref val6)).GetColumn(3));
		_root.transform.localRotation = ((Matrix4x4)(ref val6)).rotation;
		_root.transform.localScale = ((Matrix4x4)(ref val6)).lossyScale;
		Material material = ((Renderer)componentInChildren).material;
		MakePart("Body", vertices, normals, uv, val, list2, triangles, Vector3.zero, material, _root.transform);
		_upper = MakePart("BeakUpper", vertices, normals, uv, val, list5, triangles, pivot, material, _root.transform).transform;
		_lower = MakePart("BeakLower", vertices, normals, uv, val, list6, triangles, pivot, material, _root.transform).transform;
		_upperRest = _upper.localRotation;
		_lowerRest = _lower.localRotation;
		_pivot = pivot;
		_hingeAxisLocal = Vector3.up;
		((Renderer)componentInChildren).enabled = false;
		Object.Destroy((Object)(object)val);
		ManualLogSource logSrc2 = Plugin.LogSrc;
		if (logSrc2 != null)
		{
			logSrc2.LogInfo((object)("BingBong: beak split - " + list5.Count + " upper / " + list6.Count + " lower tris, seam z=" + num11.ToString("0.000") + ", joint x=" + num18.ToString("0.000") + " (beak x " + num12.ToString("0.000") + ".." + num13.ToString("0.000") + ")"));
		}
		return true;
	}

	private GameObject MakePart(string name, Vector3[] v, Vector3[] n, Vector2[] uv0, Mesh src, List<int> triStarts, int[] tris, Vector3 pivot, Material mat, Transform parent)
	{
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Expected O, but got Unknown
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: 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_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_028e: Expected O, but got Unknown
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		List<int> list = new List<int>(triStarts.Count * 3);
		List<Vector3> list2 = new List<Vector3>();
		List<Vector3> list3 = new List<Vector3>();
		List<List<Vector4>> list4 = new List<List<Vector4>>();
		List<List<Vector4>> list5 = new List<List<Vector4>>();
		for (int i = 0; i < 8; i++)
		{
			List<Vector4> list6 = new List<Vector4>();
			src.GetUVs(i, list6);
			list5.Add((list6.Count == v.Length) ? list6 : null);
			list4.Add(new List<Vector4>());
		}
		Color[] colors = src.colors;
		bool flag = colors != null && colors.Length == v.Length;
		List<Color> list7 = new List<Color>();
		foreach (int triStart in triStarts)
		{
			for (int j = 0; j < 3; j++)
			{
				int num = tris[triStart + j];
				if (!dictionary.TryGetValue(num, out var value))
				{
					value = (dictionary[num] = list2.Count);
					list2.Add(v[num] - pivot);
					if (n != null && n.Length == v.Length)
					{
						list3.Add(n[num]);
					}
					for (int k = 0; k < 8; k++)
					{
						if (list5[k] != null)
						{
							list4[k].Add(list5[k][num]);
						}
					}
					if (flag)
					{
						list7.Add(colors[num]);
					}
				}
				list.Add(value);
			}
		}
		Mesh val = new Mesh
		{
			name = "YakariBingBong_" + name
		};
		val.SetVertices(list2);
		if (list3.Count == list2.Count)
		{
			val.SetNormals(list3);
		}
		for (int l = 0; l < 8; l++)
		{
			if (list5[l] != null)
			{
				val.SetUVs(l, list4[l]);
			}
		}
		if (flag)
		{
			val.SetColors(list7);
		}
		val.SetTriangles(list, 0);
		if (list3.Count != list2.Count)
		{
			val.RecalculateNormals();
		}
		val.RecalculateBounds();
		_meshes.Add(val);
		GameObject val2 = new GameObject(name);
		val2.transform.SetParent(parent, false);
		val2.transform.localPosition = pivot;
		val2.AddComponent<MeshFilter>().sharedMesh = val;
		MeshRenderer obj = val2.AddComponent<MeshRenderer>();
		((Renderer)obj).sharedMaterial = mat;
		((Renderer)obj).shadowCastingMode = ((Renderer)_source).shadowCastingMode;
		((Renderer)obj).receiveShadows = ((Renderer)_source).receiveShadows;
		return val2;
	}

	internal void SetOpen(float open01, float maxAngle, bool flip)
	{
		//IL_0043: 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_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_upper == (Object)null) && !((Object)(object)_lower == (Object)null))
		{
			float num = Mathf.Clamp01(open01) * maxAngle * (flip ? (-1f) : 1f) * -1f;
			_upper.localRotation = _upperRest * Quaternion.AngleAxis(0f - num, _hingeAxisLocal);
			_lower.localRotation = _lowerRest * Quaternion.AngleAxis(num, _hingeAxisLocal);
		}
	}

	internal bool SourceChanged()
	{
		SkinnedMeshRenderer val = (((Object)(object)_fish != (Object)null) ? ((Component)_fish).GetComponentInChildren<SkinnedMeshRenderer>(false) : null);
		if ((Object)(object)_root != (Object)null && (Object)(object)val != (Object)null)
		{
			return (Object)(object)val != (Object)(object)_source;
		}
		return false;
	}

	internal void Dispose()
	{
		if ((Object)(object)_source != (Object)null)
		{
			((Renderer)_source).enabled = true;
		}
		_source = null;
		if ((Object)(object)_root != (Object)null)
		{
			Object.Destroy((Object)(object)_root);
		}
		_root = null;
		_upper = null;
		_lower = null;
		foreach (Mesh mesh in _meshes)
		{
			if ((Object)(object)mesh != (Object)null)
			{
				Object.Destroy((Object)(object)mesh);
			}
		}
		_meshes.Clear();
	}

	private static Texture2D Palette(Material mat)
	{
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: 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_00d2: Expected O, but got Unknown
		//IL_00d9: Expected O, but got Unknown
		if ((Object)(object)mat == (Object)null || !mat.HasProperty("_Colors"))
		{
			return null;
		}
		Texture texture = mat.GetTexture("_Colors");
		if ((Object)(object)texture == (Object)null)
		{
			return null;
		}
		if ((Object)(object)_paletteCache != (Object)null && (Object)(object)_paletteSource == (Object)(object)texture)
		{
			return _paletteCache;
		}
		RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		try
		{
			Graphics.Blit(texture, temporary);
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(texture.width, texture.height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(0f, 0f, (float)texture.width, (float)texture.height), 0, 0);
			val.Apply();
			if ((Object)(object)_paletteCache != (Object)null)
			{
				Object.Destroy((Object)(object)_paletteCache);
			}
			_paletteCache = val;
			_paletteSource = texture;
			return val;
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
		}
	}

	private static bool IsOrange(Texture2D palette, Vector2 uv)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Clamp((int)(uv.x * (float)((Texture)palette).width), 0, ((Texture)palette).width - 1);
		int num2 = Mathf.Clamp((int)(uv.y * (float)((Texture)palette).height), 0, ((Texture)palette).height - 1);
		float num3 = default(float);
		float num4 = default(float);
		float num5 = default(float);
		Color.RGBToHSV(palette.GetPixel(num, num2), ref num3, ref num4, ref num5);
		if (num3 >= 0.04f && num3 <= 0.13f && num4 > 0.5f)
		{
			return num5 > 0.5f;
		}
		return false;
	}

	internal static void ReleasePalette()
	{
		if ((Object)(object)_paletteCache != (Object)null)
		{
			Object.Destroy((Object)(object)_paletteCache);
		}
		_paletteCache = null;
		_paletteSource = null;
	}
}
internal static class BingBongBossBar
{
	private static GameObject _go;

	private static CanvasGroup _group;

	private static TextMeshProUGUI _name;

	private static Image _fill;

	private static Image _fillLerped;

	private static RectTransform _move;

	private static RectTransform _rot;

	private static Image _timer;

	private static CanvasGroup _countdown;

	private static TextMeshProUGUI _countdownText;

	private static float _fightEndsAt = -1f;

	private static float _fightTotal = 1f;

	private static bool _countingDown;

	private static Vector3 _startPos;

	private static Vector3 _vel;

	private static Vector3 _angVel;

	private static float _lastFill = 1f;

	private static Item _fish;

	private static bool _visible;

	private static readonly List<Material> _ownedMats = new List<Material>();

	private static readonly int RotMultID = Shader.PropertyToID("_Rotation_Multiplier");

	private const float ShakeForce = 750f;

	private const float LerpForce = 1200f;

	private const float HpDamping = 12f;

	private const float ShakeAngForce = 10f;

	private const float AngLerpForce = 120f;

	private const float HpAngDamping = 20f;

	private static bool Build()
	{
		//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e8: Expected O, but got Unknown
		//IL_0569: Unknown result type (might be due to invalid IL or missing references)
		//IL_056e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_go != (Object)null)
		{
			return true;
		}
		FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerUI), "_instance");
		FieldInfo fieldInfo2 = AccessTools.Field(typeof(PlayerUI), "_bossUI");
		PlayerUI val = (PlayerUI)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
		BossUI val2 = (BossUI)(((Object)(object)val != (Object)null && fieldInfo2 != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val2 == (Object)null)
		{
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogWarning((object)"BingBong: vanilla BossUI not found - no boss bar.");
			}
			return false;
		}
		string[] obj = new string[9] { "_bossNameText", "_bossHpToMove", "_bossHpToRotate", "_bossHealth", "_bossHealthLerped", "_timeLeftImage", "_countdownGroup", "_timeCountdownText", "_bossCanvasLerped" };
		Dictionary<string, Component> parts = new Dictionary<string, Component>();
		string[] array = obj;
		foreach (string text in array)
		{
			object? obj2 = AccessTools.Field(typeof(BossUI), text)?.GetValue(val2);
			Component val3 = (Component)((obj2 is Component) ? obj2 : null);
			if ((Object)(object)val3 != (Object)null)
			{
				parts[text] = val3;
			}
		}
		if (!parts.ContainsKey("_bossHealth") || !parts.ContainsKey("_bossNameText"))
		{
			ManualLogSource logSrc2 = Plugin.LogSrc;
			if (logSrc2 != null)
			{
				logSrc2.LogWarning((object)"BingBong: boss bar parts missing on the vanilla widget - no boss bar.");
			}
			return false;
		}
		Transform panel = CommonAncestor(parts.Values);
		if ((Object)(object)panel == (Object)null)
		{
			ManualLogSource logSrc3 = Plugin.LogSrc;
			if (logSrc3 != null)
			{
				logSrc3.LogWarning((object)"BingBong: no common panel for the boss bar parts.");
			}
			return false;
		}
		_go = Object.Instantiate<GameObject>(((Component)panel).gameObject, panel.parent, true);
		((Object)_go).name = "YakariBingBongBossBar";
		LeanTween.cancel(_go, true);
		MonoBehaviour[] componentsInChildren = _go.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val4 in componentsInChildren)
		{
			if (!((Object)(object)val4 == (Object)null))
			{
				string text2 = ((object)val4).GetType().Namespace ?? "";
				if (!(val4 is Graphic) && !(val4 is TMP_Text) && !(val4 is LayoutGroup) && !(val4 is ContentSizeFitter) && !(val4 is Mask) && !(val4 is RectMask2D) && !(val4 is Shadow) && !(val4 is Outline) && !text2.StartsWith("UnityEngine.UI") && !text2.StartsWith("TMPro"))
				{
					Object.Destroy((Object)(object)val4);
				}
			}
		}
		Component obj3 = Copy("_bossNameText");
		_name = (TextMeshProUGUI)(object)((obj3 is TextMeshProUGUI) ? obj3 : null);
		Component obj4 = Copy("_bossHpToMove");
		_move = (RectTransform)(object)((obj4 is RectTransform) ? obj4 : null);
		Component obj5 = Copy("_bossHpToRotate");
		_rot = (RectTransform)(object)((obj5 is RectTransform) ? obj5 : null);
		Component obj6 = Copy("_bossHealth");
		_fill = (Image)(object)((obj6 is Image) ? obj6 : null);
		Component obj7 = Copy("_bossHealthLerped");
		_fillLerped = (Image)(object)((obj7 is Image) ? obj7 : null);
		Component obj8 = Copy("_timeLeftImage");
		_timer = (Image)(object)((obj8 is Image) ? obj8 : null);
		Component obj9 = Copy("_countdownGroup");
		_countdown = (CanvasGroup)(object)((obj9 is CanvasGroup) ? obj9 : null);
		Component obj10 = Copy("_timeCountdownText");
		_countdownText = (TextMeshProUGUI)(object)((obj10 is TextMeshProUGUI) ? obj10 : null);
		Component obj11 = Copy("_bossCanvasLerped");
		CanvasGroup val5 = (CanvasGroup)(object)((obj11 is CanvasGroup) ? obj11 : null);
		if ((Object)(object)val5 != (Object)null)
		{
			LeanTween.cancel(((Component)val5).gameObject);
			val5.alpha = 1f;
		}
		_group = _go.GetComponent<CanvasGroup>();
		if ((Object)(object)_group == (Object)null)
		{
			_group = _go.AddComponent<CanvasGroup>();
		}
		_ = (Object)(object)val5 == (Object)(object)_group;
		if ((Object)(object)_name == (Object)null || (Object)(object)_move == (Object)null || (Object)(object)_rot == (Object)null || (Object)(object)_fill == (Object)null || (Object)(object)_fillLerped == (Object)null)
		{
			ManualLogSource logSrc4 = Plugin.LogSrc;
			if (logSrc4 != null)
			{
				logSrc4.LogWarning((object)"BingBong: could not resolve every boss bar part in the panel copy - no boss bar.");
			}
			Object.Destroy((Object)(object)_go);
			_go = null;
			return false;
		}
		ManualLogSource logSrc5 = Plugin.LogSrc;
		if (logSrc5 != null)
		{
			logSrc5.LogInfo((object)("BingBong: boss bar cloned from panel '" + ((Object)panel).name + "' (timer " + (((Object)(object)_timer != (Object)null) ? "yes" : "no") + ")."));
		}
		Image[] componentsInChildren2 = _go.GetComponentsInChildren<Image>(true);
		foreach (Image val6 in componentsInChildren2)
		{
			if ((Object)(object)((Graphic)val6).material != (Object)null && ((Graphic)val6).material.HasProperty(RotMultID))
			{
				Material val7 = new Material(((Graphic)val6).material);
				val7.SetFloat(RotMultID, 0f);
				((Graphic)val6).material = val7;
				_ownedMats.Add(val7);
			}
		}
		if ((Object)(object)_timer != (Object)null)
		{
			_timer.fillAmount = 1f;
		}
		if ((Object)(object)_countdown != (Object)null)
		{
			_countdown.alpha = 0f;
			((Component)_countdown).gameObject.SetActive(false);
		}
		_startPos = ((Transform)_move).localPosition;
		_group.alpha = 0f;
		_go.SetActive(false);
		return true;
		Component Copy(string f)
		{
			if (!parts.TryGetValue(f, out var value))
			{
				return null;
			}
			Transform obj12 = FindMatching(_go.transform, panel, value.transform);
			if (obj12 == null)
			{
				return null;
			}
			return ((Component)obj12).GetComponent(((object)value).GetType());
		}
	}

	private static Transform CommonAncestor(IEnumerable<Component> comps)
	{
		Transform val = null;
		foreach (Component comp in comps)
		{
			if ((Object)(object)comp == (Object)null)
			{
				continue;
			}
			if ((Object)(object)val == (Object)null)
			{
				val = comp.transform;
				continue;
			}
			while ((Object)(object)val != (Object)null && !comp.transform.IsChildOf(val))
			{
				val = val.parent;
			}
			if (!((Object)(object)val == (Object)null))
			{
				continue;
			}
			return null;
		}
		return val;
	}

	private static Transform FindMatching(Transform copyRoot, Transform origRoot, Transform origNode)
	{
		List<int> list = new List<int>();
		Transform val = origNode;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)origRoot)
		{
			list.Insert(0, val.GetSiblingIndex());
			val = val.parent;
		}
		Transform val2 = copyRoot;
		foreach (int item in list)
		{
			if (item >= val2.childCount)
			{
				return null;
			}
			val2 = val2.GetChild(item);
		}
		return val2;
	}

	internal static void RepairVanilla()
	{
		FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerUI), "_instance");
		FieldInfo fieldInfo2 = AccessTools.Field(typeof(PlayerUI), "_bossUI");
		PlayerUI val = (PlayerUI)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
		BossUI val2 = (BossUI)(((Object)(object)val != (Object)null && fieldInfo2 != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val2 == (Object)null)
		{
			return;
		}
		object? value = AccessTools.Field(typeof(BossUI), "_timeLeftImage").GetValue(val2);
		Image val3 = (Image)((value is Image) ? value : null);
		object? value2 = AccessTools.Field(typeof(BossUI), "_countdownGroup").GetValue(val2);
		CanvasGroup val4 = (CanvasGroup)((value2 is CanvasGroup) ? value2 : null);
		int num = 0;
		if ((Object)(object)val3 != (Object)null)
		{
			Transform val5 = ((Component)val3).transform;
			while ((Object)(object)val5 != (Object)null && (Object)(object)val5 != (Object)(object)((Component)val2).transform.parent)
			{
				if (!((Component)val5).gameObject.activeSelf && (Object)(object)val5 != (Object)(object)((Component)val2).transform)
				{
					((Component)val5).gameObject.SetActive(true);
					num++;
				}
				val5 = val5.parent;
			}
		}
		if ((Object)(object)val4 != (Object)null && !((Component)val4).gameObject.activeSelf)
		{
			((Component)val4).gameObject.SetActive(true);
			num++;
		}
		if (num > 0)
		{
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogInfo((object)("BingBong: restored " + num + " vanilla boss-timer object(s) an earlier build had hidden."));
			}
		}
	}

	internal static void Show(Item fish, string name, float fightSeconds)
	{
		//IL_00a0: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)fish == (Object)null) && Build())
		{
			_fightTotal = Mathf.Max(1f, fightSeconds);
			_fightEndsAt = ((fightSeconds > 0f) ? (Time.time + fightSeconds) : (-1f));
			_countingDown = false;
			if ((Object)(object)_timer != (Object)null)
			{
				_timer.fillAmount = 1f;
			}
			if ((Object)(object)_countdown != (Object)null)
			{
				_countdown.alpha = 0f;
				((Component)_countdown).gameObject.SetActive(false);
			}
			_fish = fish;
			((TMP_Text)_name).text = name;
			((Graphic)_fill).color = GameInfo.RedColor;
			_fill.fillAmount = 1f;
			_fillLerped.fillAmount = 1f;
			_lastFill = 1f;
			_vel = (_angVel = Vector3.zero);
			((Transform)_move).localPosition = _startPos;
			((Transform)_rot).localRotation = Quaternion.identity;
			_go.SetActive(true);
			Fade(1f);
			_visible = true;
		}
	}

	internal static void Hide()
	{
		if (!((Object)(object)_go == (Object)null) && _visible)
		{
			_visible = false;
			_fish = null;
			Fade(0f);
		}
	}

	private static void Fade(float to)
	{
		LeanTween.cancel(((Component)_group).gameObject);
		LeanTween.value(((Component)_group).gameObject, _group.alpha, to, 1f).setEase((LeanTweenType)2).setOnUpdate((Action<float>)delegate(float a)
		{
			if ((Object)(object)_group != (Object)null)
			{
				_group.alpha = a;
			}
		})
			.setOnComplete((Action)delegate
			{
				if (to == 0f && (Object)(object)_go != (Object)null && !_visible)
				{
					_go.SetActive(false);
				}
			});
	}

	internal static void Tick()
	{
		//IL_00ac: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: 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)
		if ((Object)(object)_go == (Object)null || !_visible)
		{
			return;
		}
		if ((Object)(object)_fish == (Object)null || ((NetworkBehaviour)_fish).IsDeinitializing || (Object)(object)BossManager.Boss != (Object)null)
		{
			Hide();
			return;
		}
		Creature component = ((Component)_fish).GetComponent<Creature>();
		if ((Object)(object)component == (Object)null)
		{
			Hide();
			return;
		}
		UpdateTimer();
		if (component.Hp <= 0)
		{
			RunSpring();
			return;
		}
		float num = Mathf.Clamp01((float)component.Hp / (float)Mathf.Max(1, component.MaxHp));
		if (num < _lastFill)
		{
			float num2 = Mathf.Clamp(_lastFill - num, 0.025f, 1f);
			Vector3 insideUnitSphere = Random.insideUnitSphere;
			_vel = ((Vector3)(ref insideUnitSphere)).normalized * num2 * ((Random.Range(0, 2) == 1) ? 1f : (-1f)) * 750f;
			float num3 = ((Random.Range(0, 2) == 1) ? 1f : (-1f));
			_angVel += new Vector3(0f, 0f, num3 * num2 * 10f);
			_fill.fillAmount = num;
			LeanTween.cancel(((Component)_fillLerped).gameObject);
			LeanTween.value(((Component)_fillLerped).gameObject, _fillLerped.fillAmount, num, 0.5f).setDelay(0.25f).setEase((LeanTweenType)9)
				.setOnUpdate((Action<float>)delegate(float f)
				{
					if ((Object)(object)_fillLerped != (Object)null)
					{
						_fillLerped.fillAmount = f;
					}
				});
		}
		else if (num > _lastFill)
		{
			_fill.fillAmount = num;
			_fillLerped.fillAmount = num;
		}
		_lastFill = num;
		RunSpring();
	}

	private static void UpdateTimer()
	{
		if (_fightEndsAt < 0f)
		{
			return;
		}
		float num = Mathf.Max(0f, _fightEndsAt - Time.time);
		if ((Object)(object)_timer != (Object)null)
		{
			_timer.fillAmount = num / _fightTotal;
		}
		if ((Object)(object)_countdown == (Object)null || (Object)(object)_countdownText == (Object)null)
		{
			return;
		}
		if (num >= 10f)
		{
			_countdown.alpha = 0f;
			return;
		}
		if (!_countingDown)
		{
			_countingDown = true;
			((Component)_countdown).gameObject.SetActive(true);
			LeanTween.cancel(((Component)_countdown).gameObject);
			LeanTween.value(((Component)_countdown).gameObject, 0f, 1f, 1f).setEase((LeanTweenType)2).setOnUpdate((Action<float>)delegate(float a)
			{
				if ((Object)(object)_countdown != (Object)null)
				{
					_countdown.alpha = a;
				}
			});
		}
		((TMP_Text)_countdownText).text = num.ToString("#0");
	}

	private static void RunSpring()
	{
		//IL_0000: 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_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: 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_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = (_startPos - ((Transform)_move).localPosition) * 1200f;
		_vel += val * Time.deltaTime;
		_vel -= _vel * (12f * Time.deltaTime);
		RectTransform move = _move;
		((Transform)move).localPosition = ((Transform)move).localPosition + _vel * Time.deltaTime;
		Quaternion localRotation = ((Transform)_rot).localRotation;
		DazedUtils.SimulateSpringRotation(ref localRotation, ref _angVel, Quaternion.identity, 120f, 20f);
		((Transform)_rot).localRotation = localRotation;
	}

	internal static void DestroyAll()
	{
		if ((Object)(object)_go != (Object)null)
		{
			LeanTween.cancel(_go);
			Object.Destroy((Object)(object)_go);
		}
		foreach (Material ownedMat in _ownedMats)
		{
			if ((Object)(object)ownedMat != (Object)null)
			{
				Object.Destroy((Object)(object)ownedMat);
			}
		}
		_ownedMats.Clear();
		_go = null;
		_group = null;
		_name = null;
		_fill = null;
		_fillLerped = null;
		_move = null;
		_rot = null;
		_fish = null;
		_visible = false;
	}
}
internal struct SqueezeMsg : IBroadcast
{
	public byte Version;

	public int PlayerObjectId;

	public int FishObjectId;

	public byte Kind;

	public byte LineIndex;
}
internal static class BingBongNet
{
	internal const byte ProtocolVersion = 2;

	private static bool _registered;

	private static bool _disabled;

	private static bool _warnedVersion;

	private static bool _warnedSendError;

	internal static void EnsureRegistered()
	{
		if (_registered || _disabled || (Object)(object)InstanceFinder.NetworkManager == (Object)null || (Object)(object)InstanceFinder.ServerManager == (Object)null || (Object)(object)InstanceFinder.ClientManager == (Object)null)
		{
			return;
		}
		try
		{
			PurgeStaleHandlers(InstanceFinder.ServerManager);
			PurgeStaleHandlers(InstanceFinder.ClientManager);
			GenericWriter<SqueezeMsg>.SetWrite((Action<Writer, SqueezeMsg>)WriteMsg);
			GenericReader<SqueezeMsg>.SetRead((Func<Reader, SqueezeMsg>)ReadMsg);
			InstanceFinder.ServerManager.RegisterBroadcast<SqueezeMsg>((Action<NetworkConnection, SqueezeMsg, Channel>)OnServer, true);
			InstanceFinder.ClientManager.RegisterBroadcast<SqueezeMsg>((Action<SqueezeMsg, Channel>)OnClient);
			_registered = true;
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogInfo((object)("BingBongNet registered (protocol v" + (byte)2 + ")."));
			}
		}
		catch (Exception ex)
		{
			_disabled = true;
			ManualLogSource logSrc2 = Plugin.LogSrc;
			if (logSrc2 != null)
			{
				logSrc2.LogWarning((object)("BingBongNet disabled - register failed: " + ex.Message));
			}
		}
	}

	internal static void Unregister()
	{
		if (!_registered)
		{
			return;
		}
		_registered = false;
		try
		{
			ServerManager serverManager = InstanceFinder.ServerManager;
			if (serverManager != null)
			{
				serverManager.UnregisterBroadcast<SqueezeMsg>((Action<NetworkConnection, SqueezeMsg, Channel>)OnServer);
			}
			ClientManager clientManager = InstanceFinder.ClientManager;
			if (clientManager != null)
			{
				clientManager.UnregisterBroadcast<SqueezeMsg>((Action<SqueezeMsg, Channel>)OnClient);
			}
			PurgeStaleHandlers(InstanceFinder.ServerManager);
			PurgeStaleHandlers(InstanceFinder.ClientManager);
		}
		catch (Exception ex)
		{
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogWarning((object)("BingBongNet unregister: " + ex.Message));
			}
		}
	}

	private static void PurgeStaleHandlers(object manager)
	{
		if (manager == null || !(manager.GetType().GetField("_broadcastHandlers", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(manager) is IDictionary dictionary))
		{
			return;
		}
		List<object> list = new List<object>();
		foreach (DictionaryEntry item in dictionary)
		{
			Type type = item.Value?.GetType();
			if (!(type == null) && type.IsGenericType)
			{
				Type[] genericArguments = type.GetGenericArguments();
				if (genericArguments.Length == 1 && genericArguments[0].FullName == typeof(SqueezeMsg).FullName)
				{
					list.Add(item.Key);
				}
			}
		}
		foreach (object item2 in list)
		{
			dictionary.Remove(item2);
		}
		if (list.Count > 0)
		{
			ManualLogSource logSrc = Plugin.LogSrc;
			if (logSrc != null)
			{
				logSrc.LogInfo((object)("BingBongNet purged " + list.Count + " stale handler(s) from " + manager.GetType().Name + " (hot reload leftovers)."));
			}
		}
	}

	private static void WriteMsg(Writer w, SqueezeMsg m)
	{
		w.WriteUInt8Unpacked(m.Version);
		w.WriteInt32(m.PlayerObjectId);
		w.WriteInt32(m.FishObjectId);
		w.WriteUInt8Unpacked(m.Kind);
		w.WriteUInt8Unpacked(m.LineIndex);
	}

	private static SqueezeMsg ReadMsg(Reader r)
	{
		return new SqueezeMsg
		{
			Version = r.ReadUInt8Unpacked(),
			PlayerObjectId = r.ReadInt32(),
			FishObjectId = r.ReadInt32(),
			Kind = r.ReadUInt8Unpacked(),
			LineIndex = r.ReadUInt8Unpacked()
		};
	}

	internal static void SendSqueeze()
	{
		Send(0, 255);
	}

	internal static void SendSpeak(int lineIndex, Plugin.Pool pool, Item fish)
	{
		int kind = pool switch
		{
			Plugin.Pool.PanicAngry => 18, 
			Plugin.Pool.Hundred => 17, 
			Plugin.Pool.Idle => 16, 
			Plugin.Pool.Panic => 15, 
			Plugin.Pool.Relief => 14, 
			Plugin.Pool.FightOpen => 11, 
			Plugin.Pool.Warn => 10, 
			Plugin.Pool.Fight => 9, 
			Plugin.Pool.Hurt => 8, 
			Plugin.Pool.Angry => 4, 
			_ => 1, 
		};
		int fishObjectId = (((Object)(object)fish != (Object)null && (Object)(object)fish.Holder == (Object)null) ? ((NetworkBehaviour)fish).ObjectId : 0);
		Send((byte)kind, lineIndex, fishObjectId);
	}

	internal static void SendFight(Item fish)
	{
		if ((Object)(object)fish != (Object)null)
		{
			Send(6, 255, ((NetworkBehaviour)fish).ObjectId);
		}
	}

	internal static void SendStage(Item fish, bool fighting)
	{
		if ((Object)(object)fish != (Object)null)
		{
			Send(7, fighting ? 1 : 0, ((NetworkBehaviour)fish).ObjectId);
		}
	}

	internal static void SendRage(bool on)
	{
		Send((byte)(on ? 2 : 3), 255);
	}

	internal static void SendProvoke(Item fish, float points)
	{
		if (!((Object)(object)fish == (Object)null))
		{
			Send(5, Mathf.Clamp(Mathf.RoundToInt(points * 10f), 1, 254), ((NetworkBehaviour)fish).ObjectId);
		}
	}

	private static void Send(byte kind, int lineIndex, int fishObjectId = 0)
	{
		try
		{
			if (_disabled)
			{
				return;
			}
			EnsureRegistered();
			if (!_registered)
			{
				return;
			}
			Player localPlayer = Player.LocalPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				SqueezeMsg squeezeMsg = new SqueezeMsg
				{
					Version = 2,
					PlayerObjectId = ((NetworkBehaviour)localPlayer).ObjectId,
					FishObjectId = fishObjectId,
					Kind = kind,
					LineIndex = (byte)((lineIndex >= 0 && lineIndex < 255) ? ((uint)lineIndex) : 255u)
				};
				if (InstanceFinder.IsServerStarted)
				{
					InstanceFinder.ServerManager.BroadcastExcept<SqueezeMsg>(InstanceFinder.ClientManager.Connection, squeezeMsg, true, (Channel)0);
				}
				else if (InstanceFinder.IsClientStarted)
				{
					InstanceFinder.ClientManager.Broadcast<SqueezeMsg>(squeezeMsg, (Channel)0);
				}
			}
		}
		catch (Exception ex)
		{
			if (!_warnedSendError)
			{
				_warnedSendError = true;
				ManualLogSource logSrc = Plugin.LogSrc;
				if (logSrc != null)
				{
					logSrc.LogWarning((object)("Squeeze sync disabled until next reload - send failed: " + ex.Message));
				}
			}
			_disabled = true;
		}
	}

	private static Item FindFish(int objectId)
	{
		if (objectId == 0)
		{
			return null;
		}
		Item val = Plugin.Instance?.FindShownFish(objectId);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		foreach (Creature deadCreature in Creature.DeadCreatures)
		{
			if ((Object)(object)deadCreature != (Object)null && ((NetworkBehaviour)deadCreature).ObjectId == objectId)
			{
				return (Item)(object)deadCreature;
			}
		}
		return null;
	}

	private static void OnServer(NetworkConnection sender, SqueezeMsg msg, Channel ch)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		if (msg.Kind == 6)
		{
			Player provoker = null;
			foreach (Player player in PlayerManager.Players)
			{
				if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).ObjectId == msg.PlayerObjectId)
				{
					provoker = player;
					break;
				}
			}
			Plugin.Instance?.HostRevive(FindFish(msg.FishObjectId), provoker);
		}
		else
		{
			InstanceFinder.ServerManager.BroadcastExcept<SqueezeMsg>(sender, msg, true, ch);
		}
	}

	private static void OnClient(SqueezeMsg msg, Channel ch)
	{
		if (msg.Version != 2)
		{
			if (!_warnedVersion)
			{
				_warnedVersion = true;
				ManualLogSource logSrc = Plugin.LogSrc;
				if (logSrc != null)
				{
					logSrc.LogWarning((object)("Received squeeze protocol v" + msg.Version + " but ours is v" + (byte)2 + " - both players need the same BingBong version."));
				}
			}
			return;
		}
		Player localPlayer = Player.LocalPlayer;
		if ((Object)(object)localPlayer != (Object)null && msg.PlayerObjectId == ((NetworkBehaviour)localPlayer).ObjectId)
		{
			return;
		}
		Player val = null;
		foreach (Player player in PlayerManager.Players)
		{
			if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).ObjectId == msg.PlayerObjectId)
			{
				val = player;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		int lineIdx = ((msg.LineIndex == byte.MaxValue) ? (-1) : msg.LineIndex);
		switch (msg.Kind)
		{
		case 5:
			Plugin.Instance?.RemoteProvoke(val, FindFish(msg.FishObjectId), (float)(int)msg.LineIndex / 10f);
			break;
		case 7:
		{
			Item val2 = FindFish(msg.FishObjectId);
			if ((Object)(object)val2 != (Object)null && msg.LineIndex == 1)
			{
				Plugin.Instance?.ApplyStageFight(Plugin.Instance.ShowFor(val2));
			}
			break;
		}
		case 0:
			Plugin.Instance?.RemoteSqueeze(val);
			break;
		case 1:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Normal);
			break;
		case 4:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Angry);
			break;
		case 8:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Hurt);
			break;
		case 9:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Fight);
			break;
		case 10:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Warn);
			break;
		case 11:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.FightOpen);
			break;
		case 14:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Relief);
			break;
		case 15:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Panic);
			break;
		case 16:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Idle);
			break;
		case 17:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.Hundred);
			break;
		case 18:
			Plugin.Instance?.RemoteSpeak(val, FindFish(msg.FishObjectId), lineIdx, Plugin.Pool.PanicAngry);
			break;
		case 2:
			Plugin.Instance?.RemoteRage(val, on: true);
			break;
		case 3:
			Plugin.Instance?.RemoteRage(val, on: false);
			break;
		case 6:
		case 12:
		case 13:
			break;
		}
	}
}
[BepInPlugin("howtofish.bingbong", "BingBong", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
	internal enum Pool : byte
	{
		Normal,
		Angry,
		Hurt,
		Fight,
		Sorry,
		Warn,
		FightOpen,
		Relief,
		Panic,
		Idle,
		Hundred,
		PanicAngry
	}

	private class FishShow
	{
		public Item Fish;

		public Transform Root;

		public Vector3 RestScale;

		public bool SpringActive;

		public float S;

		public float V;

		public AudioSource SqueakSource;

		public AudioSource VoiceSource;

		public float SpeakAt = -1f;

		public AudioClip TalkClip;

		public float[] TalkEnv;

		public Pool TalkPool;

		public bool Talking;

		public float Open;

		public Transform ShakeBone;

		public Quaternion ShakeRest;

		public Transform LeanTarget;

		public WorldText Caption;

		public BingBongBeak Beak;

		public float BeakOpen;

		public float CookLean = 1f;

		public float Cook;

		public float BasePitch = 1f;

		public float WobbleSeed;

		public float DropoutUntil = -1f;

		public float NextDropoutRoll;

		public float Shrivel = 1f;

		public AudioLowPassFilter LowPass;

		public AudioDistortionFilter Distortion;

		public float Heat;

		public bool Raging;

		public GameObject EnableOnShiny;

		public GameObject DisableOnShiny;

		public Vector3 JerkTarget;

		public Vector3 Jerk;

		public Vector3 JerkVel;

		public bool AttackArmed = true;

		public float Provoke;

		public float LastProvoke = -1f;

		public bool Fighting;

		public float FightEndsAt = -1f;

		public float NextChatter;

		public float NextIdle;

		public bool BirdHeld;

		public readonly List<int> FightBag = new List<int>();

		public int LastFightIdx = -1;

		public float SorryUntil = -1f;
	}

	private enum ProvokeStage
	{
		Calm,
		Hurt,
		Angry,
		Fight
	}

	public const string Guid = "howtofish.bingbong";

	public const string Name = "BingBong";

	public const string Version = "1.0.0";

	internal static Plugin Instance;

	internal static ManualLogSource LogSrc;

	private static readonly string AssetDir = ResolveAssetDir();

	private ConfigEntry<string> _clipFile;

	private ConfigEntry<float> _volume;

	private ConfigEntry<float> _settleDelay;

	private ConfigEntry<string> _squeakFile;

	private ConfigEntry<float> _squeakVolume;

	private ConfigEntry<float> _leanAmount;

	private ConfigEntry<float> _squashAmount;

	private ConfigEntry<float> _springK;

	private ConfigEntry<float> _springDamp;

	private ConfigEntry<float> _cooldown;

	private ConfigEntry<bool> _syncEnabled;

	private ConfigEntry<bool> _captionEnabled;

	private ConfigEntry<float> _captionSize;

	private ConfigEntry<float> _captionHeight;

	private ConfigEntry<int> _captionWrap;

	private ConfigEntry<bool> _cookEnabled;

	private ConfigEntry<float> _cookMinPitch;

	private ConfigEntry<float> _cookMinVolume;

	private ConfigEntry<float> _cookSqueakMinPitch;

	private ConfigEntry<float> _cookDeadAt;

	private ConfigEntry<float> _cookWobble;

	private ConfigEntry<float> _cookDropouts;

	private ConfigEntry<float> _cookLowPass;

	private ConfigEntry<float> _cookDistortion;

	private ConfigEntry<float> _cookShrivel;

	private ConfigEntry<bool> _cookGlitchText;

	private ConfigEntry<bool> _rageEnabled;

	private ConfigEntry<float> _rageSqueezes;

	private ConfigEntry<float> _rageDecay;

	private ConfigEntry<string> _rageCaptionColor;

	private ConfigEntry<float> _thrashAngle;

	private ConfigEntry<float> _thrashJitter;

	private ConfigEntry<float> _thrashPump;

	private ConfigEntry<bool> _provokeEnabled;

	private ConfigEntry<float> _provokeAngryAt;

	private ConfigEntry<float> _provokeFightAt;

	private ConfigEntry<float> _provokeDecay;

	private ConfigEntry<float> _provokeSpamWeight;

	private ConfigEntry<float> _groundThrashScale;

	private ConfigEntry<float> _chatterInterval;

	private ConfigEntry<float> _sorrySeconds;

	private ConfigEntry<float> _lungeSpeed;

	private ConfigEntry<float> _idleInterval;

	private ConfigEntry<float> _idleVolume;

	private ConfigEntry<int> _hundredEvery;

	private ConfigEntry<int> _squeezeCount;

	private ConfigEntry<string> _fightMusic;

	private ConfigEntry<bool> _beakEnabled;

	private ConfigEntry<float> _beakAngle;

	private ConfigEntry<bool> _beakFlip;

	private ConfigEntry<float> _beakGain;

	private ConfigEntry<float> _beakFloor;

	private ConfigEntry<float> _beakRelease;

	private ConfigEntry<float> _beakFlutterHz;

	private ConfigEntry<float> _beakFlutter;

	private ConfigEntry<bool> _bossBar;

	private ConfigEntry<string> _bossBarName;

	private ConfigEntry<float> _fightSeconds;

	private static int _fightsWithMusic;

	private Harmony _harmony;

	private bool _inputHooked;

	private float _lastSqueeze;

	private AudioClip _clip;

	private float[] _envelope;

	private AudioClip _squeak;

	private readonly List<AudioClip> _lines = new List<AudioClip>();

	private readonly List<float[]> _lineEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _angry = new List<AudioClip>();

	private readonly List<float[]> _angryEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _hurt = new List<AudioClip>();

	private readonly List<float[]> _hurtEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _fight = new List<AudioClip>();

	private readonly List<float[]> _fightEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _sorry = new List<AudioClip>();

	private readonly List<float[]> _sorryEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _warn = new List<AudioClip>();

	private readonly List<float[]> _warnEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _open = new List<AudioClip>();

	private readonly List<float[]> _openEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _relief = new List<AudioClip>();

	private readonly List<float[]> _reliefEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _panic = new List<AudioClip>();

	private readonly List<float[]> _panicEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _idle = new List<AudioClip>();

	private readonly List<float[]> _idleEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _hundred = new List<AudioClip>();

	private readonly List<float[]> _hundredEnvs = new List<float[]>();

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

	private readonly List<AudioClip> _panicAngry = new List<AudioClip>();

	private readonly List<float[]> _panicAngryEnvs = new List<float[]>();

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

	private readonly Dictionary<Item, FishShow> _shows = new Dictionary<Item, FishShow>();

	private static readonly List<Item> _deadKeys = new List<Item>();

	private bool _warnedVanillaHost;

	private static string ResolveAssetDir()
	{
		try
		{
			string location = Assembly.GetExecutingAssembly().Location;
			if (!string.IsNullOrEmpty(location))
			{
				string directoryName = Path.GetDirectoryName(location);
				string text = Path.Combine(directoryName, "BingBong");
				if (Directory.Exists(text))
				{
					return text;
				}
				if (Directory.Exists(Path.Combine(directoryName, "lines")))
				{
					return directoryName;
				}
			}
		}
		catch
		{
		}
		return Path.Combine(Paths.PluginPath, "BingBong");
	}

	private List<AudioClip> Clips(Pool p)
	{
		return p switch
		{
			Pool.Angry => _angry, 
			Pool.Hurt => _hurt, 
			Pool.Fight => _fight, 
			Pool.Sorry => _sorry, 
			Pool.Warn => _warn, 
			Pool.FightOpen => _open, 
			Pool.Relief => _relief, 
			Pool.Panic => _panic, 
			Pool.Idle => _idle, 
			Pool.Hundred => _hundred, 
			Pool.PanicAngry => _panicAngry, 
			_ => _lines, 
		};
	}

	private List<float[]> Envs(Pool p)
	{
		return p switch
		{
			Pool.Angry => _angryEnvs, 
			Pool.Hurt => _hurtEnvs, 
			Pool.Fight => _fightEnvs, 
			Pool.Sorry => _sorryEnvs, 
			Pool.Warn => _warnEnvs, 
			Pool.FightOpen => _openEnvs, 
			Pool.Relief => _reliefEnvs, 
			Pool.Panic => _panicEnvs, 
			Pool.Idle => _idleEnvs, 
			Pool.Hundred => _hundredEnvs, 
			Pool.PanicAngry => _panicAngryEnvs, 
			_ => _lineEnvs, 
		};
	}

	private List<string> Caps(Pool p)
	{
		return p switch
		{
			Pool.Angry => _angryCaptions, 
			Pool.Hurt => _hurtCaptions, 
			Pool.Fight => _fightCaptions, 
			Pool.Sorry => _sorryCaptions, 
			Pool.Warn => _warnCaptions, 
			Pool.FightOpen => _openCaptions, 
			Pool.Relief => _reliefCaptions, 
			Pool.Panic => _panicCaptions, 
			Pool.Idle => _idleCaptions, 
			Pool.Hundred => _hundredCaptions, 
			Pool.PanicAngry => _panicAngryCaptions, 
			_ => _lineCaptions, 
		};
	}

	private void Awake()
	{
		//IL_084b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0855: Expected O, but got Unknown
		Instance = this;
		LogSrc = ((BaseUnityPlugin)this).Logger;
		_clipFile = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "ClipFile", "bingbong-1.50.mp3", "Fallback voice clip in BepInEx/plugins/BingBong/ (used only if lines/ is missing).");
		_volume = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "Volume", 1f, "Voice volume (0..1).");
		_settleDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "VoiceSettleDelay", 0.22f, "Seconds of NO squeezing before he answers. Spamming keeps resetting this, so you get pure squeaks while mashing and one clean answer when you stop.");
		_squeakFile = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "SqueakFile", "bingbong-squeak.mp3", "Squeaky-toy SFX played the instant he is squeezed (Marsh's cut of Pixabay squeaky-toy-1).");
		_squeakVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "SqueakVolume", 1f, "Squeak volume (0..1).");
		_leanAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "TalkLeanAmount", 16f, "How far (degrees) he leans into the listener on loud syllables. 0 disables.");
		_squashAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Squeeze", "SquashAmount", 0.45f, "Squish depth: 0.45 = pressed to 55% on the grip axis, bulging outward to keep volume.");
		_springK = ((BaseUnityPlugin)this).Config.Bind<float>("Squeeze", "SpringStiffness", 260f, "Spring stiffness. Higher = snappier pop back.");
		_springDamp = ((BaseUnityPlugin)this).Config.Bind<float>("Squeeze", "SpringDamping", 11f, "Damping. Lower = more rubbery wobbles before settling.");
		_cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Squeeze", "Cooldown", 0.06f, "Min seconds between squeezes - low so the squeak stays spammable.");
		_syncEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "EnableSync", true, "Broadcast squeezes so other modded players see and hear them.");
		_captionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Caption", "Enabled", true, "Float the words he is saying over his head while he talks.");
		_captionSize = ((BaseUnityPlugin)this).Config.Bind<float>("Caption", "Size", 0.065f, "Caption font size (game WorldText units).");
		_captionWrap = ((BaseUnityPlugin)this).Config.Bind<int>("Caption", "WrapAfter", 12, "Captions longer than this many characters break onto a second row at the nearest space.");
		_captionHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Caption", "Height", 0.15f, "How far above the top of his body the caption sits, in metres.");
		_cookEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Cooking", "Enabled", true, "Cooking him lowers his pitch and volume; burnt, he can only wheeze.");
		_cookMinPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "VoiceMinPitch", 0.5f, "Voice pitch when fully burnt (1 = normal). Lower pitch also slows the line - dying-battery toy. At cookness 1.0 (the x1.5 point) he is already ~60% of the way there.");
		_cookMinVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "VoiceMinVolume", 0.3f, "Voice volume multiplier when fully burnt.");
		_cookSqueakMinPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "SqueakMinPitch", 0.55f, "Squeak pitch when fully burnt - the rubber melts too.");
		_cookDeadAt = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "DeadAt", 1.95f, "Cookness at which he stops talking altogether. 2 = fully black; 1.95 = visibly charcoal.");
		_cookWobble = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "WobbleDepth", 0.14f, "Wow & flutter: how far his pitch drifts and wobbles when fully burnt (0.14 = +/-14%). The dying-battery sound.");
		_cookDropouts = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "DropoutsPerSecond", 7f, "Frying-contact cut-outs per second when fully burnt (each 20-60 ms). Scales with cookness.");
		_cookLowPass = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "LowPassAtBurnt", 900f, "Low-pass cutoff (Hz) when fully burnt - the speaker cone melting. 22000 = off.");
		_cookDistortion = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "DistortionAtBurnt", 0.6f, "Distortion level (0..1) when fully burnt - fried speaker crunch.");
		_cookShrivel = ((BaseUnityPlugin)this).Config.Bind<float>("Cooking", "Shrivel", 0.08f, "Uniform melt-shrink when fully burnt (0.08 = 8% smaller). Uniform on purpose - squashing one axis of a held item reads as a glitch.");
		_cookGlitchText = ((BaseUnityPlugin)this).Config.Bind<bool>("Cooking", "GlitchCaption", true, "Stutter and drop letters in the caption as he cooks.");
		_rageEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Rage", "Enabled", true, "Over-squeezing turns him into the angry red version until he is dropped in water.");
		_rageSqueezes = ((BaseUnityPlugin)this).Config.Bind<float>("Rage", "SqueezesToSnap", 12f, "Heat needed to snap. Each squeeze adds 1; heat decays HeatDecayPerSecond.");
		_rageDecay = ((BaseUnityPlugin)this).Config.Bind<float>("Rage", "HeatDecayPerSecond", 1.5f, "How fast squeeze-heat bleeds off. Spam faster than this and he snaps.");
		_rageCaptionColor = ((BaseUnityPlugin)this).Config.Bind<string>("Rage", "CaptionColor", "#FF3B3B", "Caption colour while angry (hex).");
		_thrashAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Rage", "ThrashAngle", 38f, "How far (degrees) each shout throws him in a random direction while red. He overshoots and jitters back.");
		_thrashJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Rage", "ThrashJitter", 9f, "Continuous uncontrolled wobble (degrees) while he is shouting, on top of the throws.");
		_thrashPump = ((BaseUnityPlugin)this).Config.Bind<float>("Rage", "ThrashPump", 14f, "Body puff on each shout - a kick into the squish spring (a click is 28).");
		_provokeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Provoke", "Enabled", true, "Hitting a dead Bing Bong on the ground provokes him.");
		_provokeAngryAt = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "AngryAt", 3f, "Provocation points before he turns red. Each hit = 1 point.");
		_provokeFightAt = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "FightAt", 6f, "Provocation points before he comes alive and attacks (needs a modded host).");
		_provokeDecay = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "DecayPerSecond", 0.12f, "How fast provocation cools off when you leave him alone.");
		_provokeSpamWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "SpamSqueezeWeight", 1f, "Provocation points per squeeze while he is already red (Trigger B).");
		_chatterInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "FightChatterSeconds", 7f, "While he hunts you he throws a threat now and then: base seconds between lines, jittered 0.7x-1.8x (about 5-12 s), never before the previous line has finished, and every line plays once before any repeats.");
		_sorrySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "SorrySeconds", 2f, "Cooldown after you kill him: he says sorry and cannot be provoked.");
		_lungeSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "LungeSpeed", 9f, "Squeezed into a fight: he leaps out of your hands at your face at this speed (m/s).");
		_idleInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Charm", "IdleMumbleSeconds", 100f, "A green Bing Bong left on the ground mumbles something sleepy about this often (+/-40%). 0 = never.");
		_idleVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Charm", "IdleVolume", 0.45f, "How quiet the sleepy mumbles are.");
		_hundredEvery = ((BaseUnityPlugin)this).Config.Bind<int>("Charm", "HundredEvery", 100, "Every N answers you have squeezed out of any Bing Bong, he says something about it instead.");
		_squeezeCount = ((BaseUnityPlugin)this).Config.Bind<int>("Stats", "AnswersSqueezed", 0, "How many answers you have squeezed out of Bing Bongs on this install. He is counting.");
		_beakEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Beak", "Enabled", true, "Split his beak into two wedges that open and close like scissors while he talks.");
		_beakAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "MaxAngle", 22f, "How wide the beak opens (degrees per wedge).");
		_beakFlip = ((BaseUnityPlugin)this).Config.Bind<bool>("Beak", "Flip", false, "If the wedges close instead of open, flip the direction.");
		_beakGain = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "Gain", 2.2f, "Sensitivity to the voice. Higher = snaps open on quieter syllables.");
		_beakFloor = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "Floor", 0.1f, "Loudness below this keeps the beak shut (0..1).");
		_beakRelease = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "Release", 0.07f, "Seconds to fall shut after a syllable. Opening is instant.");
		_beakFlutterHz = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "FlutterHz", 24f, "The chatter: how fast the open beak vibrates.");
		_beakFlutter = ((BaseUnityPlugin)this).Config.Bind<float>("Beak", "Flutter", 0.45f, "How much of the opening the chatter modulates (0 = none, 1 = slams shut each cycle).");
		_bossBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Music", "BossBar", true, "Show the vanilla-style boss health bar while he hunts you.");
		_bossBarName = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "BossBarName", "Angry Bing Bong", "The name on his boss bar.");
		_fightSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "FightSeconds", 75f, "How long he hunts you before he gives up and goes poof, like a boss leaving. 0 = no limit.");
		_fightMusic = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "FightMusic", "Mini", "Music while he hunts you: Mini (the mini-boss track), Boss (the big boss track), or None. Never plays over a real boss fight.");
		_groundThrashScale = ((BaseUnityPlugin)this).Config.Bind<float>("Provoke", "GroundThrashScale", 0.4f, "On the ground he shakes lighter than in the hand: thrash multiplier when not held.");
		_harmony = new Harmony("howtofish.bingbong");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		((MonoBehaviour)this).StartCoroutine(LoadClips());
		BingBongBossBar.RepairVanilla();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong 1.0: spam-squeak, deferred voice, angry character (water-obsessed), FishNet sync.");
	}

	internal static bool IsBingBong(Item item)
	{
		if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).GetComponent<Creature>() != (Object)null)
		{
			return ((Object)item).name.StartsWith("BingBong");
		}
		return false;
	}

	internal static bool IsBingBongHeld()
	{
		Player localPlayer = Player.LocalPlayer;
		if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Holding != (Object)null)
		{
			return IsBingBong(localPlayer.Holding.HeldItem);
		}
		return false;
	}

	private void Update()
	{
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		BingBongHint.Tick();
		if (!_inputHooked && (Object)(object)GameInfo.Input != (Object)null)
		{
			GameInfo.Input.actions["PlayerLeftClick"].performed += OnLeftClick;
			_inputHooked = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: PlayerLeftClick hooked.");
		}
		if (_syncEnabled.Value)
		{
			BingBongNet.EnsureRegistered();
		}
		BingBongBossBar.Tick();
		foreach (FishShow value in _shows.Values)
		{
			UpdateSpring(value);
			UpdateIdle(value);
			if (value.SpeakAt > 0f && Time.time >= value.SpeakAt)
			{
				SpeakNow(value);
			}
			if (value.Heat > 0f)
			{
				value.Heat = Mathf.Max(0f, value.Heat - _rageDecay.Value * Time.deltaTime);
			}
			if (value.Provoke > 0f)
			{
				value.Provoke = Mathf.Max(0f, value.Provoke - _provokeDecay.Value * Time.deltaTime);
			}
			if (!value.Fighting && (Object)(object)value.Fish != (Object)null && (value.Raging || value.Heat > 0f || value.Provoke > 0f) && WaterManager.IsUnderWater(((Component)value.Fish).transform.position))
			{
				bool raging = value.Raging;
				EndRage(value);
				value.Provoke = 0f;
				value.Heat = 0f;
				if (raging)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: dunked - back to normal.");
					DunkMoment(value);
				}
			}
			if (value.Raging && (Object)(object)value.EnableOnShiny != (Object)null && !value.EnableOnShiny.activeSelf)
			{
				SetDripLook(value, drip: true);
			}
			if (value.Fighting && InstanceFinder.IsServerStarted && value.FightEndsAt > 0f && Time.time >= value.FightEndsAt && (Object)(object)value.Fish != (Object)null && !((NetworkBehaviour)value.Fish).IsDeinitializing)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: time's up - he gives up and goes poof.");
				value.FightEndsAt = -1f;
				value.Fish.DestroyItem((byte)0, byte.MaxValue);
			}
			if (value.Fighting && InstanceFinder.IsServerStarted && (Object)(object)value.Fish != (Object)null && IsDead(value.Fish))
			{
				Creature component = ((Component)value.Fish).GetComponent<Creature>();
				if ((Object)(object)component != (Object)null && !component.IsDead)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: fully cooked mid-fight - he drops dead.");
					component.ServerChangeHp(component.MaxHp);
				}
			}
			if (!value.Fighting || !InstanceFinder.IsServerStarted || !(Time.time >= value.NextChatter) || _fight.Count <= 0)
			{
				continue;
			}
			if (value.Talking)
			{
				value.NextChatter = Time.time + 0.5f;
				continue;
			}
			value.NextChatter = Time.time + _chatterInterval.Value * Random.Range(0.7f, 1.8f);
			int num = NextFromBag(value);
			PlayLine(value, num, Pool.Fight);
			if (_syncEnabled.Value)
			{
				BingBongNet.SendSpeak(num, Pool.Fight, value.Fish);
			}
		}
	}

	private void LateUpdate()
	{
		_deadKeys.Clear();
		foreach (KeyValuePair<Item, FishShow> show in _shows)
		{
			if ((Object)(object)show.Key == (Object)null || (Object)(object)show.Value.Root == (Object)null)
			{
				_deadKeys.Add(show.Key);
				continue;
			}
			UpdateLean(show.Value);
			UpdateBeak(show.Value);
			UpdateCookFx(show.Value);
			UpdateShrivel(show.Value);
			UpdateCaption(show.Value);
		}
		foreach (Item deadKey in _deadKeys)
		{
			DisposeShow(deadKey);
		}
	}

	private void OnLeftClick(CallbackContext ctx)
	{
		Player localPlayer = Player.LocalPlayer;
		if ((Object)(object)localPlayer == (Object)null || localPlayer.BlockInputs || (Object)(object)localPlayer.Holding == (Object)null)
		{
			return;
		}
		Item heldItem = localPlayer.Holding.HeldItem;
		if (!IsBingBong(heldItem) || Time.unscaledTime - _lastSqueeze < _cooldown.Value)
		{
			return;
		}
		_lastSqueeze = Time.unscaledTime;
		Squeeze(heldItem, localPlayer.CamObject);
		if (_syncEnabled.Value)
		{
			BingBongNet.SendSqueeze();
		}
		FishShow show = GetShow(heldItem);
		if (IsDead(heldItem))
		{
			return;
		}
		if (_rageEnabled.Value && !show.Raging)
		{
			show.Heat += 1f;
			if (show.Heat >= _rageSqueezes.Value)
			{
				StartRage(show);
				if (_syncEnabled.Value)
				{
					BingBongNet.SendRage(on: true);
				}
			}
		}
		else if (show.Raging && _provokeEnabled.Value)
		{
			LocalProvoke(show, _provokeSpamWeight.Value, localPlayer.CamObject, react: false);
		}
	}

	internal void OnCorpseHit(Item fish, Player hitter)
	{
		if (_provokeEnabled.Value && !((Object)(object)hitter == (Object)null) && ((NetworkBehaviour)hitter).Owner.IsLocalClient)
		{
			FishShow show = GetShow(fish);
			LocalProvoke(show, 1f, FaceOf(hitter));
		}
	}

	private void LocalProvoke(FishShow show, float points, Transform provoker, bool react = true)
	{
		bool num = ApplyProvoke(show, points, provoker);
		if (_syncEnabled.Value)
		{
			BingBongNet.SendProvoke(show.Fish, points);
		}
		if (!num && react)
		{
			Pool pool = ((!show.Raging) ? ((_hurt.Count > 0) ? Pool.Hurt : Pool.Normal) : ((_warn.Count > 0) ? Pool.Warn : Pool.Hurt));
			int count = Clips(pool).Count;
			int num2 = ((count > 0) ? Random.Range(0, count) : (-1));
			if (show.Talking)
			{
				StopTalking(show);
			}
			show.SpeakAt = -1f;
			PlayLine(show, num2, pool);
			if (_syncEnabled.Value)
			{
				BingBongNet.SendSpeak(num2, pool, show.Fish);
			}
		}
	}

	internal void RemoteProvoke(Player provoker, Item fish, float points)
	{
		if (!((Object)(object)fish == (Object)null) && IsBingBong(fish))
		{
			ApplyProvoke(GetShow(fish), points, ((Object)(object)provoker != (Object)null) ? FaceOf(provoker) : null);
		}
	}

	private bool ApplyProvoke(FishShow show, float points, Transform provoker)
	{
		if ((Object)(object)show.Fish == (Object)null || show.Fighting)
		{
			return false;
		}
		if (IsDead(show.Fish))
		{
			return false;
		}
		if (Time.time < show.SorryUntil)
		{
			return false;
		}
		ProvokeStage provokeStage = StageOf(show);
		show.Provoke += points;
		show.LastProvoke = Time.time;
		if ((Object)(object)provoker != (Object)null)
		{
			show.LeanTarget = provoker;
		}
		ProvokeStage provokeStage2 = StageOf(show);
		if (provokeStage2 != provokeStage)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("BingBong: provoke " + show.Provoke.ToString("0.0") + " -> " + provokeStage2));
		}
		if (provokeStage2 >= ProvokeStage.Angry && !show.Raging)
		{
			StartRage(show);
		}
		if ((Object)(object)_squeak != (Object)null && (Object)(object)show.SqueakSource != (Object)null)
		{
			show.SqueakSource.PlayOneShot(_squeak, _squeakVolume.Value * MasterVolume() * Mathf.Lerp(1f, _cookSqueakMinPitch.Value, Cook01(show.Fish)));
		}
		if (provokeStage2 == ProvokeStage.Fight && provokeStage != ProvokeStage.Fight)
		{
			RequestFight(show);
			return true;
		}
		return false;
	}

	private ProvokeStage StageOf(FishShow show)
	{
		if (show.Provoke >= _provokeFightAt.Value)
		{
			return ProvokeStage.Fight;
		}
		if (show.Provoke >= _provokeAngryAt.Value)
		{
			return ProvokeStage.Angry;
		}
		if (show.Provoke > 0f)
		{
			return ProvokeStage.Hurt;
		}
		return ProvokeStage.Calm;
	}

	private void DunkMoment(FishShow show)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_0033: 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)
		if ((Object)(object)show.Fish == (Object)null)
		{
			return;
		}
		Vector3 position = ((Component)show.Fish).transform.position;
		position.y = WaterManager.GetWaterHeight(position);
		VFXManager.Play("WaterSplash", position, Vector3.zero);
		AudioManager.PlayRandomClipAt("ItemHitWaterMedium_V", 1, 3, position, true, (AudioDistance)1, 1.2f, 0.1f);
		if (_relief.Count != 0)
		{
			if (show.Talking)
			{
				StopTalking(show);
			}
			((MonoBehaviour)this).StartCoroutine(SpeakLater(show, 0.6f, Pool.Relief, ((NetworkBehaviour)show.Fish).ObjectId % _relief.Count));
		}
	}

	private IEnumerator SpeakLater(FishShow show, float delay, Pool pool, int idx)
	{
		yield return (object)new WaitForSeconds(delay);
		if (!((Object)(object)show.Fish == (Object)null) && !show.Talking)
		{
			PlayLine(show, idx, pool);
		}
	}

	internal void OnBirdTookHim(Item fish)
	{
		if (!InstanceFinder.IsServerStarted || (Object)(object)fish == (Object)null || IsDead(fish))
		{
			return;
		}
		FishShow show = GetShow(fish);
		Pool pool = ((show.Raging && _panicAngry.Count > 0) ? Pool.PanicAngry : Pool.Panic);
		if (Clips(pool).Count != 0)
		{
			int num = Random.Range(0, Clips(pool).Count);
			if (show.Talking)
			{
				StopTalking(show);
			}
			PlayLine(show, num, pool);
			if (_syncEnabled.Value)
			{
				BingBongNet.SendSpeak(num, pool, fish);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: a seagull took him.");
		}
	}

	private void UpdateIdle(FishShow show)
	{
		if (!InstanceFinder.IsServerStarted || _idle.Count == 0 || _idleInterval.Value <= 0f)
		{
			return;
		}
		Item fish = show.Fish;
		if ((Object)(object)fish == (Object)null || (Object)(object)fish.Holder != (Object)null || fish.IsInInventory || (Object)(object)fish.BirdHolder != (Object)null)
		{
			return;
		}
		if (show.Raging || show.Fighting || show.Talking || IsDead(fish))
		{
			show.NextIdle = 0f;
			return;
		}
		Creature component = ((Component)fish).GetComponent<Creature>();
		if ((Object)(object)component == (Object)null || !component.IsDead)
		{
			return;
		}
		if (show.NextIdle <= 0f)
		{
			show.NextIdle = Time.time + _idleInterval.Value * Random.Range(0.6f, 1.4f);
		}
		else if (!(Time.time < show.NextIdle))
		{
			show.NextIdle = Time.time + _idleInterval.Value * Random.Range(0.6f, 1.4f);
			int num = Random.Range(0, _idle.Count);
			PlayLine(show, num, Pool.Idle);
			if (_syncEnabled.Value)
			{
				BingBongNet.SendSpeak(num, Pool.Idle, fish);
			}
		}
	}

	private bool FightTrack(out string clip, out string intro, out string outro, out float delay)
	{
		clip = (intro = (outro = ""));
		delay = 5f;
		string text = (_fightMusic.Value ?? "").Trim().ToLowerInvariant();
		if (text == "boss")
		{
			clip = "BossFight1";
			intro = "BossFightIntro";
			outro = "BossFightOutro";
			delay = 5f;
			return true;
		}
		if (text == "mini")
		{
			clip = "BossFightMini";
			intro = "BossFightMini_Intro6s";
			outro = "BossFightMini_Outro";
			delay = 6f;
			return true;
		}
		return false;
	}

	private void FightMusicStart()
	{
		_fightsWithMusic++;
		if (_fightsWithMusic == 1 && !((Object)(object)BossManager.Boss != (Object)null) && FightTrack(out var clip, out var intro, out var _, out var delay))
		{
			MusicManager.PlayMusic(clip, intro, delay, true);
		}
	}

	private void FightMusicStop()
	{
		_fightsWithMusic = Mathf.Max(0, _fightsWithMusic - 1);
		if (_fightsWithMusic == 0 && FightTrack(out var clip, out var _, out var outro, out var _))
		{
			MusicManager.StopMusic(clip, outro);
		}
	}

	private int NextFromBag(FishShow show)
	{
		if (show.FightBag.Count == 0)
		{
			for (int i = 0; i < _fight.Count; i++)
			{
				show.FightBag.Add(i);
			}
			for (int num = show.FightBag.Count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				int value = show.FightBag[num];
				show.FightBag[num] = show.FightBag[index];
				show.FightBag[index] = value;
			}
			int index2 = show.FightBag.Count - 1;
			if (show.FightBag.Count > 1 && show.FightBag[index2] == show.LastFightIdx)
			{
				int value2 = show.FightBag[index2];
				show.FightBag[index2] = show.FightBag[0];
				show.FightBag[0] = value2;
			}
		}
		int num2 = show.FightBag[show.FightBag.Count - 1];
		show.FightBag.RemoveAt(show.FightBag.Count - 1);
		show.LastFightIdx = num2;
		return num2;
	}

	private void RequestFight(FishShow show)
	{
		//IL_00af: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		if (!show.Raging)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("BingBong: fight requested on a GREEN fish - refused (Provoke " + show.Provoke.ToString("0.0") + ")."));
			show.Provoke = Mathf.Min(show.Provoke, _provokeAngryAt.Value - 0.01f);
			return;
		}
		Player localPlayer = Player.LocalPlayer;
		Item fish = show.Fish;
		if ((Object)(object)fish != (Object)null && (Object)(object)fish.Holder != (Object)null && ((NetworkBehaviour)fish.Holder).Owner.IsLocalClient)
		{
			Transform val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.CamObject : null);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? (val.forward * 0.5f) : Vector3.zero);
			fish.Drop(true, val2, default(Vector3));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: wriggled out of the hand - here it comes.");
		}
		if (InstanceFinder.IsServerStarted)
		{
			HostRevive(show.Fish, localPlayer);
		}
		else if (_syncEnabled.Value)
		{
			BingBongNet.SendFight(show.Fish);
			if (!_warnedVanillaHost)
			{
				_warnedVanillaHost = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: asked the host to revive him. If the host has no mod, nothing will happen.");
			}
		}
	}

	internal void HostRevive(Item fish, Player provoker)
	{
		//IL_0056: 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_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: 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_00cf: 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_0124: Unknown result type (might be due to invalid IL or missing references)
		//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_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: 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_0167: Unknown result type (might be due to invalid IL or missing references)
		if (!InstanceFinder.IsServerStarted || (Object)(object)fish == (Object)null)
		{
			return;
		}
		Creature component = ((Component)fish).GetComponent<Creature>();
		if ((Object)(object)component == (Object)null || !component.IsDead || ((NetworkBehaviour)fish).IsDeinitializing)
		{
			return;
		}
		Vector3 val;
		if ((Object)(object)fish.Holder != (Object)null && ((NetworkBehaviour)fish.Holder).Owner.IsLocalClient)
		{
			val = default(Vector3);
			Vector3 val2 = val;
			val = default(Vector3);
			fish.Drop(true, val2, val);
		}
		component._hp.Value = component.MaxHp;
		if ((Object)(object)CreatureManager.Instance != (Object)null)
		{
			CreatureManager.Instance.AddAliveCreature(component);
		}
		ReviveFixups(component);
		SetField(component, typeof(AttackingFish), "_target", provoker);
		if ((Object)(object)fish.RigidbodySync != (Object)null)
		{
			RigidbodySync rigidbodySync = fish.RigidbodySync;
			val = default(Vector3);
			rigidbodySync.StartSimulateLocal(val, default(Quaternion));
		}
		Rigidbody component2 = ((Component)fish).GetComponent<Rigidbody>();
		if ((Object)(object)component2 != (Object)null && (Object)(object)provoker != (Object)null && (Object)(object)provoker.Body != (Object)null && (Object)(object)provoker.Body.Head != (Object)null)
		{
			val = provoker.Body.Head.position - component2.worldCenterOfMass;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			component2.isKinematic = false;
			component2.linearVelocity = normalized * _lungeSpeed.Value + Vector3.up * 1.5f;
		}
		FishShow show = GetShow(fish);
		ApplyStageFight(show);
		show.FightBag.Clear();
		show.NextChatter = Time.time + _chatterInterval.Value * 0.8f;
		if (_open.Count > 0)
		{
			int num = Random.Range(0, _open.Count);
			if (show.Talking)
			{
				StopTalking(show);
			}
			PlayLine(show, num, Pool.FightOpen);
			if (_syncEnabled.Value)
			{
				BingBongNet.SendSpeak(num, Pool.FightOpen, fish);
			}
		}
		if (_syncEnabled.Value)
		{
			BingBongNet.SendStage(fish, fighting: true);
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("BingBong: REVIVED '" + ((Object)fish).name + "' with " + component.MaxHp + " hp - he is hunting " + (((Object)(object)provoker != (Object)null) ? ((Object)provoker).name : "nearest")));
	}

	internal void ApplyStageFight(object showObj)
	{
		if (showObj is FishShow fishShow && !((Object)(object)fishShow.Fish == (Object)null))
		{
			fishShow.Fighting = true;
			fishShow.Provoke = 0f;
			if (!fishShow.Raging)
			{
				StartRage(fishShow);
			}
			FightMusicStart();
			fishShow.FightEndsAt = ((_fightSeconds.Value > 0f) ? (Time.time + _fightSeconds.Value) : (-1f));
			if (_bossBar.Value)
			{
				BingBongBossBar.Show(fishShow.Fish, _bossBarName.Value, _fightSeconds.Value);
			}
			Creature component = ((Component)fishShow.Fish).GetComponent<Creature>();
			if ((Object)(object)component != (Object)null)
			{
				ReviveFixups(component);
			}
			if (fishShow.Talking)
			{
				StopTalking(fishShow);
			}
		}
	}

	private static void ReviveFixups(Creature cr)
	{
		SetField(cr, typeof(Item), "_canPickUp", false);
		SetField(cr, typeof(Creature), "_localIsDead", false);
		(typeof(Creature).GetField("_deadCreatures", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as HashSet<Creature>)?.Remove(cr);
		typeof(Creature).GetMethod("SetSleepThreshold", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(cr, new object[1] { false });
	}

	private static void SetField(object target, Type declaring, string name, object value)
	{
		FieldInfo field = declaring.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
		if (field != null && declaring.IsInstanceOfType(target))
		{
			field.SetValue(target, value);
		}
	}

	internal void OnFishDeath(Item fish)
	{
		if (_shows.TryGetValue(fish, out var value) && value.Fighting)
		{
			value.Fighting = false;
			value.Provoke = 0f;
			value.Heat = 0f;
			EndRage(value);
			FightMusicStop();
			BingBongBossBar.Hide();
			if (value.Talking)
			{
				StopTalking(value);
			}
			value.SorryUntil = Time.time + _sorrySeconds.Value;
			if (IsDead(fish))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: burnt out - no apology, nothing left in him.");
				return;
			}
			((MonoBehaviour)this).StartCoroutine(SaySorry(value));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"BingBong: he surrenders.");
		}
	}

	private IEnumerator SaySorry(FishShow show)
	{
		yield return (object)new WaitForSeconds(0.45f);
		if (!((Object)(object)show.Fish == (Object)null) && _sorry.Count != 0)
		{
			PlayLine(show, ((NetworkBehaviour)show.Fish).ObjectId % _sorry.Count, Pool.Sorry);
		}
	}

	private void StartRage(FishShow show)
	{
		if (!show.Raging && !((Object)(object)show.Fish == (Object)null) && !IsDead(show.Fish))
		{
			show.Raging = true;
			show.Heat = 0f;
			SetDripLook(show, drip: true);
			if (show.Talking)
			{
				StopTalking(show);
			}
		}
	}

	private void EndRage(FishShow show)
	{
		if (show.Raging)
		{
			show.Raging = false;
			Creature val = (((Object)(object)show.Fish != (Object)null) ? ((Component)show.Fish).GetComponent<Creature>() : null);
			SetDripLook(show, (Object)(object)val != (Object)null && val.IsDrip);
		}
	}

	private void SetDripLook(FishShow show, bool drip)
	{
		if ((Object)(object)show.EnableOnShiny == (Object)null || (Object)(object)show.DisableOnShiny == (Object)null)
		{
			Creature val = (((Object)(object)show.Fish != (Object)null) ? ((Component)show.Fish).GetComponent<Creature>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ref GameObject enableOnShiny = ref show.EnableOnShiny;
			object? obj = typeof(Creature).GetField("_enableOnShiny", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val);
			enableOnShiny = (GameObject)((obj is GameObject) ? obj : null);
			ref GameObject disableOnShiny = ref show.DisableOnShiny;
			object? obj2 = typeof(Creature).GetField("_disableOnShiny", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val);
			disableOnShiny = (GameObject)((obj2 is GameObject) ? obj2 : null);
			if ((Object)(object)show.EnableOnShiny == (Object)null || (Object)(object)show.DisableOnShiny == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"BingBong: shiny toggles not found - no shape-shift.");
				return;
			}
		}
		show.EnableOnShiny.SetActive(drip);
		show.DisableOnShiny.SetActive(!drip);
	}

	internal void RemoteRage(Player squeezer, bool on)
	{
		Item val = ResolveFish(squeezer);
		if (!((Object)(object)val == (Object)null))
		{
			FishShow show = GetShow(val);
			if (on)
			{
				StartRage(show);
			}
			else
			{
				EndRage(show);
			}
		}
	}

	internal void RemoteSqueeze(Player squeezer)
	{
		Item val = ResolveFish(squeezer);
		if (!((Object)(object)val == (Object)null))
		{
			Squeeze(val, FaceOf(squeezer));
		}
	}

	internal void RemoteSpeak(Player squeezer, Item fishById, int lineIdx, Pool pool)
	{
		Item val = (((Object)(object)fishById != (Object)null) ? fishById : ResolveFish(squeezer));
		if (!((Object)(object)val == (Object)null))
		{
			FishShow show = GetShow(val);
			show.LeanTarget = FaceOf(squeezer);
			show.SpeakAt = -1f;
			if (show.Talking)
			{
				StopTalking(show);
			}
			if (Clips(pool).Count == 0)
			{
				pool = Pool.Normal;
			}
			PlayLine(show, lineIdx, pool);
		}
	}

	internal Item FindShownFish(int objectId)
	{
		foreach (KeyValuePair<Item, FishShow> show in _shows)
		{
			if ((Object)(object)show.Key != (Object)null && ((NetworkBehaviour)show.Key).ObjectId == objectId)
			{
				return show.Key;
			}
		}
		return null;
	}

	internal object ShowFor(Item fish)
	{
		return GetShow(fish);
	}

	private static Item ResolveFish(Player squeezer)
	{
		if ((Object)(object)squeezer == (Object)null || (Object)(object)squeezer.Holding == (Object)null)
		{
			return null;
		}
		Item heldItem = squeezer.Holding.HeldItem;
		if (!IsBingBong(heldItem))
		{
			return null;
		}
		return heldItem;
	}

	private static Transform FaceOf(Player p)
	{
		if (!((Object)(object)p.Body != (Object)null) || !((Object)(object)p.Body.Head != (Object)null))
		{
			return ((Component)p).transform;
		}
		return p.Body.Head;
	}

	private FishShow GetShow(Item fish)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_005f: 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_0074: Expected O, but got Unknown
		if (_shows.TryGetValue(fish, out var value))
		{
			return value;
		}
		FishShow fishShow = new FishShow
		{
			Fish = fish,
			Root = ((Component)fish).transform,
			RestScale = ((Component)fish).transform.localScale
		};
		GameObject val = new GameObject("YakariBingBongVoice");
		val.transform.SetParent(((Component)fish).transform, false);
		val.transform.localPosition = Vector3.zero;
		GameObject val2 = new GameObject("Voice");
		val2.transform.SetParent(val.transform, false);
		fishShow.SqueakSource = val.AddComponent<AudioSource>();
		fishShow.VoiceSource = val2.AddComponent<AudioSource>();
		AudioSource[] array = (AudioSource[])(object)new AudioSource[2] { fishShow.SqueakSource, fishShow.VoiceSource };
		foreach (AudioSource obj in array)
		{
			obj.playOnAwake = false;
			obj.spatialBlend = 1f;
			CopyGameSourceSettings(obj);
		}
		fishShow.LowPass = val2.AddComponent<AudioLowPassFilter>();
		fishShow.LowPass.cutoffFrequency = 22000f;
		fishShow.Distortion = val2.AddComponent<AudioDistortionFilter>();
		fishShow.Distortion.distortionLevel = 0f;
		fishShow.WobbleSeed = Random.value * 100f;
		_shows[fish] = fishShow;
		TryBuildBeak(fishShow);
		Creature component = ((Component)fish).GetComponent<Creature>();
		((BaseUnityPlugin)this).Logger.LogInfo((object)("BingBong: PROBE type=" + (((Object)(object)component != (Object)null) ? ((object)component).GetType().FullName : "null") + " maxHp=" + (((Object)(object)component != (Object)null) ? component.MaxHp.ToString() : "?") + " hp=" + (((Object)(object)component != (Object)null) ? component.Hp.ToString() : "?") + " dead=" + ((Object)(object)component != (Object)null && component.IsDead) + " comps=" + string.Join(",", Array.ConvertAll(((Component)fish).GetComponents<Component>(), (Component c) => ((object)c).GetType().Name))));
		return fishShow;
	}

	private void Squeeze(Item fish, Transform leanTarget)
	{
		FishShow show = GetShow(fish);
		show.LeanTarget = leanTarget;
		show.SpringActive = true;
		show.V += 28f;
		if ((Object)(object)_squeak != (Object)null && (Object)(object)show.SqueakSource != (Object)null)
		{
			float num = Cook01(fish);
			show.SqueakSource.pitch = Mathf.Lerp(1f, _cookSqueakMinPitch.Value, num);
			show.SqueakSource.PlayOneShot(_squeak, _squeakVolume.Value * MasterVolume() * Mathf.Lerp(1f, 0.5f, num));
		}
		if (show.Talking)
		{
			StopTalking(show);
		}
		show.SpeakAt = Time.time + _settleDelay.Value;
	}

	private void SpeakNow(FishShow show)
	{
		show.SpeakAt = -1f;
		if ((Object)(object)show.Fish == (Object)null || (Object)(object)show.VoiceSource == (Object)null)
		{
			return;
		}
		Pool pool = ((show.Raging && _angry.Count > 0) ? Pool.Angry : Pool.Normal);
		if (pool == Pool.Normal)
		{
			_squeezeCount.Value += 1;
			if (_hundred.Count > 0 && _hundredEvery.Value > 0 && _squeezeCount.Value % _hundredEvery.Value == 0)
			{
				pool = Pool.Hundred;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("BingBong: answer #" + _squeezeCount.Value + " - he has something to say about that."));
			}
		}
		int count = Clips(pool).Count;
		int num = ((count > 0) ? Random.Range(0, count) : (-1));
		PlayLine(show, num, pool);
		if (_syncEnabled.Value)
		{
			BingBongNet.SendSpeak(num, pool, show.Fish);
		}
	}

	private void PlayLine(FishShow show, int lineIdx, Pool pool = Pool.Normal)
	{
		List<AudioClip> list = Clips(pool);
		List<float[]> list2 = Envs(pool);
		if (lineIdx >= 0 && lineIdx < list.Count)
		{
			show.TalkClip = list[lineIdx];
			show.TalkEnv = list2[lineIdx];
		}
		else
		{
			show.TalkClip = _clip;
			show.TalkEnv = _envelope;
		}
		show.TalkPool = pool;
		if ((Object)(object)show.TalkClip == (Object)null || (Object)(object)show.VoiceSource == (Object)null)
		{
			return;
		}
		float num = Cook01(show.Fish);
		if (!IsDead(show.Fish))
		{
			show.Cook = num;
			show.BasePitch = Mathf.Lerp(1f, _cookMinPitch.Value, num);
			bool flag = show.Raging && show.TalkPool != Pool.Angry;
			if (flag)
			{
				show.BasePitch *= 0.85f;
			}
			show.VoiceSource.clip = show.TalkClip;
			show.VoiceSource.pitch = show.BasePitch;
			show.VoiceSource.mute = false;
			show.VoiceSource.volume = _volume.Value * MasterVolume() * Mathf.Lerp(1f, _cookMinVolume.Value, num) * (flag ? 1.25f : 1f) * ((pool == Pool.Idle) ? _idleVolume.Value : 1f);
			if ((Object)(object)show.LowPass != (Object)null)
			{
				show.LowPass.cutoffFrequency = Mathf.Exp(Mathf.Lerp(Mathf.Log(22000f), Mathf.Log(Mathf.Max(200f, _cookLowPass.Value)), num));
			}
			if ((Object)(object)show.Distortion != (Object)null)
			{
				show.Distortion.distortionLevel = Mathf.Lerp(0f, _cookDistortion.Value, num);
			}
			show.DropoutUntil = -1f;
			show.NextDropoutRoll = Time.time;
			show.VoiceSource.Play();
			show.Talking = true;
			show.CookLean = (1f - num * 0.7f) * (show.Raging ? 1.5f : 1f);
			BeginLean(show);
			ShowCaption(show, lineIdx);
		}
	}

	private void UpdateCookFx(FishShow show)
	{
		if (!show.Talking || (Object)(object)show.VoiceSource == (Object)null || show.Cook <= 0f)
		{
			return;
		}
		float cook = show.Cook;
		float time = Time.time;
		float num = _cookWobble.Value * cook;
		float num2 = Mathf.Sin(time * 1.7f + show.WobbleSeed);
		float num3 = Mathf.PerlinNoise(time * 9f, show.WobbleSeed) * 2f - 1f;
		show.VoiceSource.pitch = show.BasePitch * (1f + num * (0.65f * num2 + 0.35f * num3));
		if (time < show.DropoutUntil)
		{
			show.VoiceSource.mute = true;
			return;
		}
		show.VoiceSource.mute = false;
		if (time >= show.NextDropoutRoll)
		{
			show.NextDropoutRoll = time + 0.05f;
			float num4 = _cookDropouts.Value * cook * cook;
			if (Random.value < num4 * 0.05f)
			{
				show.DropoutUntil = time + Random.Range(0.02f, 0.06f);
			}
		}
	}

	private void UpdateShrivel(FishShow show)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)show.Root == (Object)null))
		{
			float num = 1f - _cookShrivel.Value * Cook01(show.Fish);
			show.Shrivel = Mathf.Lerp(show.Shrivel, num, Time.deltaTime * 3f);
			if (!show.SpringActive && Mathf.Abs(show.Shrivel - 1f) > 0.0005f)
			{
				show.Root.localScale = show.RestScale * show.Shrivel;
			}
		}
	}

	private float Cook01(Item fish)
	{
		if (!_cookEnabled.Value || (Object)(object)fish == (Object)null)
		{
			return 0f;
		}
		float num = Mathf.Clamp(fish.Cookness, 0f, 2f);
		if (!(num <= 1f))
		{
			return 0.6f + (num - 1f) * 0.4f;
		}
		return num * 0.6f;
	}

	private bool IsDead(Item fish)
	{
		if (_cookEnabled.Value && (Object)(object)fish != (Object)null)
		{
			return fish.Cookness >= _cookDeadAt.Value;
		}
		return false;
	}

	private void StopTalking(FishShow show)
	{
		if ((Object)(object)show.VoiceSource != (Object)null)
		{
			show.VoiceSource.Stop();
			show.VoiceSource.mute = false;
		}
		show.Talking = false;
		EndLean(show);
		HideCaption(show);
	}

	private void ShowCaption(FishShow show, int lineIdx)
	{
		//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)
		HideCaption(show);
		if (!_captionEnabled.Value || (Object)(object)GameInfo.CurCamera == (Object)null || (Object)(object)GameInfo.WorldTextPrefab == (Object)null)
		{
			return;
		}
		List<string> list = Caps(show.TalkPool);
		string text = ((lineIdx >= 0 && lineIdx < list.Count) ? list[lineIdx] : "Bing bong!");
		if (!string.IsNullOrEmpty(text))
		{
			if (_cookGlitchText.Value)
			{
				text = Glitch(text, Cook01(show.Fish));
			}
			if (show.Raging)
			{
				text = "<color=" + _rageCaptionColor.Value + ">" + text.ToUpperInvariant() + "</color>";
			}
			show.Caption = Object.Instantiate<WorldText>(GameInfo.WorldTextPrefab, CaptionAnchor(show), Quaternion.identity);
			show.Caption.SetText(Wrap(text, _captionWrap.Value), _captionSize.Value);
			show.Caption.ScaleAnimation(true);
		}
	}

	private static string Glitch(string text, float cook)
	{
		if (cook < 0.15f || string.IsNullOrEmpty(text))
		{
			return text;
		}
		string[] array = text.Split(' ');
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < array.Length; i++)
		{
			string text2 = array[i];
			if (text2.Length > 2 && Random.value < cook * 0.7f)
			{
				text2 = text2[0] + "-" + text2;
			}
			if (cook > 0.5f)
			{
				StringBuilder stringBuilder2 = new StringBuilder();
				string text3 = text2;
				foreach (char c in text3)
				{
					stringBuilder2.Append((char.IsLetter(c) && Random.value < (cook - 0.5f) * 0.6f) ? '-' : c);
				}
				text2 = stringBuilder2.ToString();
			}
			if (i > 0)
			{
				stringBuilder.Append(' ');
			}
			stringBuilder.Append(text2);
		}
		if (cook > 0.35f && Random.value < cook)
		{
			stringBuilder.Append("...");
		}
		return stringBuilder.ToString();
	}

	private static string Wrap(string text, int maxChars)
	{
		if (maxChars <= 0 || text.Length <= maxChars)
		{
			return text;
		}
		int num = text.Length / 2;
		int num2 = -1;
		for (int i = 0; i < text.Length; i++)
		{
			if (text[i] == ' ' && (num2 < 0 || Mathf.Abs(i - num) < Mathf.Abs(num2 - num)))
			{
				num2 = i;
			}
		}
		if (num2 >= 0)
		{
			return text.Substring(0, num2) + "\n" + text.Substring(num2 + 1);
		}
		return text;
	}

	private void HideCaption(FishShow show)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)show.Caption == (Object)null))
		{
			GameObject gameObject = ((Component)show.Caption).gameObject;
			show.Caption = null;
			LeanTween.cancel(gameObject);
			LeanTween.scale(gameObject, Vector3.zero, 0.12f).setEase((LeanTweenType)26).setDestroyOnComplete(true);
		}
	}

	private void UpdateCaption(FishShow show)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)show.Caption == (Object)null))
		{
			if (!show.Talking)
			{
				HideCaption(show);
			}
			else
			{
				((Component)show.Caption).transform.position = CaptionAnchor(show);
			}
		}
	}

	private Vector3 CaptionAnchor(FishShow show)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab