Decompiled source of REPO Gachi Billboard Encounter v0.1.0

BepInEx\plugins\Prile.GachiBillboardEncounter\RepoGachiBillboardEncounter.dll

Decompiled 3 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RepoGachiBillboardEncounter;

[BepInPlugin("prile.repo.gachi_billboard_encounter", "REPO Gachi Billboard Encounter", "0.1.0")]
public sealed class RepoGachiBillboardEncounterPlugin : BaseUnityPlugin
{
	public const string ModGuid = "prile.repo.gachi_billboard_encounter";

	public const string ModName = "REPO Gachi Billboard Encounter";

	public const string ModVersion = "0.1.0";

	internal static RepoGachiBillboardEncounterPlugin Instance;

	internal ConfigEntry<bool> ModEnabled;

	internal ConfigEntry<KeyboardShortcut> ForceSpawnHotkey;

	internal ConfigEntry<float> InitialSpawnDelay;

	internal ConfigEntry<float> SpawnIntervalSeconds;

	internal ConfigEntry<float> SpawnDistance;

	internal ConfigEntry<float> SpawnSideOffset;

	internal ConfigEntry<float> SpawnHeightOffset;

	internal ConfigEntry<float> ChaseSpeed;

	internal ConfigEntry<float> CatchDistance;

	internal ConfigEntry<float> MaxEncounterDuration;

	internal ConfigEntry<float> BillboardWidth;

	internal ConfigEntry<float> BillboardHeight;

	internal ConfigEntry<float> BobAmplitude;

	internal ConfigEntry<float> BobFrequency;

	internal ConfigEntry<float> MusicVolumeFar;

	internal ConfigEntry<float> MusicVolumeNear;

	internal ConfigEntry<float> MusicDistanceMax;

	internal ConfigEntry<float> GlitchDuration;

	internal ConfigEntry<float> SlowMultiplier;

	internal ConfigEntry<float> SlowDuration;

	internal ConfigEntry<float> LookSpeedMultiplier;

	internal ConfigEntry<float> InputLockDuration;

	internal ConfigEntry<float> PushbackForce;

	internal ConfigEntry<float> TumbleForce;

	internal ConfigEntry<float> TumbleUpwardForce;

	internal ConfigEntry<float> TumbleDuration;

	internal ConfigEntry<bool> DropInventoryOnCatch;

	internal ConfigEntry<float> LightPulseDuration;

	internal ConfigEntry<float> LightPulseMultiplier;

	internal ConfigEntry<string> PortraitPath;

	internal ConfigEntry<string> MusicPath;

	internal ManualLogSource LogSource => ((BaseUnityPlugin)this).Logger;

	private void Awake()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c3: Expected O, but got Unknown
		//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the encounter.");
		ForceSpawnHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ForceSpawnHotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Spawn the mob immediately for testing.");
		InitialSpawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "InitialSpawnDelay", 8f, "Delay before the first spawn after gameplay becomes available.");
		SpawnIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnIntervalSeconds", 18f, "Respawn interval for the mob.");
		SpawnDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnDistance", 16f, "Distance in front of the player where the mob appears.");
		SpawnSideOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnSideOffset", 5f, "Random sideways offset when spawning.");
		SpawnHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnHeightOffset", 1.4f, "Height offset of the billboard relative to the player.");
		ChaseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Encounter", "ChaseSpeed", 4.6f, "How fast the billboard moves toward the player.");
		CatchDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Encounter", "CatchDistance", 1.9f, "Distance at which the catch action triggers.");
		MaxEncounterDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Encounter", "MaxEncounterDuration", 18f, "Maximum lifetime of one encounter.");
		BillboardWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Billboard", "Width", 2.6f, "Billboard width.");
		BillboardHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Billboard", "Height", 3.5f, "Billboard height.");
		BobAmplitude = ((BaseUnityPlugin)this).Config.Bind<float>("Billboard", "BobAmplitude", 0.18f, "Vertical bob amplitude.");
		BobFrequency = ((BaseUnityPlugin)this).Config.Bind<float>("Billboard", "BobFrequency", 6.5f, "Vertical bob frequency.");
		MusicVolumeFar = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "FarVolume", 0.07f, "Music volume when the mob is far away.");
		MusicVolumeNear = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "NearVolume", 0.6f, "Music volume when the mob is near.");
		MusicDistanceMax = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxDistance", 28f, "Maximum distance used for music fading.");
		GlitchDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "GlitchDuration", 1.2f, "How long the panic/glitch effect lasts.");
		SlowMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "SlowMultiplier", 0.35f, "Movement slow multiplier on catch.");
		SlowDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "SlowDuration", 2f, "Duration of the slow effect.");
		LookSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "LookSpeedMultiplier", 0.45f, "Look sensitivity multiplier during the panic effect.");
		InputLockDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "InputLockDuration", 0.5f, "Short stun duration.");
		PushbackForce = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "PushbackForce", 14f, "Pushback force applied to the player.");
		TumbleForce = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "TumbleForce", 9f, "Force applied when tumbling the player.");
		TumbleUpwardForce = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "TumbleUpwardForce", 2.5f, "Additional upward force during tumble.");
		TumbleDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "TumbleDuration", 1.5f, "How long the tumble override stays active.");
		DropInventoryOnCatch = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "DropInventoryOnCatch", false, "Drop the full inventory on catch instead of only forcing unequip/release.");
		LightPulseDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "LightPulseDuration", 1f, "Duration of scene light flashes.");
		LightPulseMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "LightPulseMultiplier", 1.8f, "Intensity multiplier for scene light flashes.");
		string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty, "Assets");
		PortraitPath = ((BaseUnityPlugin)this).Config.Bind<string>("Assets", "PortraitPath", Path.Combine(path, "portrait.png"), "Portrait file loaded onto the billboard. The mod auto-crops and rescales it.");
		MusicPath = ((BaseUnityPlugin)this).Config.Bind<string>("Assets", "MusicPath", Path.Combine(path, "Gachi_-_AssClap_Right_version_74549050.mp3"), "Music file played during the encounter.");
		GameObject val = new GameObject("RepoGachiEncounterController");
		Object.DontDestroyOnLoad((Object)val);
		((Object)val).hideFlags = (HideFlags)61;
		val.AddComponent<GachiEncounterController>().Initialize(this);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"REPO Gachi Billboard Encounter loaded.");
	}
}
internal sealed class GachiEncounterController : MonoBehaviour
{
	private RepoGachiBillboardEncounterPlugin _plugin;

	private float _spawnCountdown = -1f;

	private bool _assetsRequested;

	private Texture2D _portraitTexture;

	private AudioClip _musicClip;

	private GachiBillboardEnemy _activeEncounter;

	public void Initialize(RepoGachiBillboardEncounterPlugin plugin)
	{
		_plugin = plugin;
	}

	private void OnEnable()
	{
		SceneManager.sceneLoaded += OnSceneLoaded;
	}

	private void OnDisable()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene _, LoadSceneMode __)
	{
		if ((Object)(object)_activeEncounter != (Object)null)
		{
			_activeEncounter.ForceCleanup();
			_activeEncounter = null;
		}
		_spawnCountdown = -1f;
	}

	private void Update()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_plugin == (Object)null || !_plugin.ModEnabled.Value)
		{
			return;
		}
		KeyboardShortcut value = _plugin.ForceSpawnHotkey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown() && IsGameplayReady())
		{
			SpawnEncounter(forced: true);
		}
		if ((Object)(object)_activeEncounter != (Object)null)
		{
			return;
		}
		if (!IsGameplayReady())
		{
			_spawnCountdown = -1f;
			return;
		}
		if (!_assetsRequested)
		{
			_assetsRequested = true;
			((MonoBehaviour)this).StartCoroutine(LoadAssetsCoroutine());
		}
		if (_spawnCountdown < 0f)
		{
			_spawnCountdown = _plugin.InitialSpawnDelay.Value;
		}
		_spawnCountdown -= Time.deltaTime;
		if (_spawnCountdown <= 0f)
		{
			SpawnEncounter(forced: false);
		}
	}

	private bool IsGameplayReady()
	{
		if ((Object)(object)PlayerController.instance != (Object)null && (Object)(object)PlayerAvatar.instance != (Object)null)
		{
			return (Object)(object)Camera.main != (Object)null;
		}
		return false;
	}

	private IEnumerator LoadAssetsCoroutine()
	{
		yield return null;
		_portraitTexture = LoadPortraitTexture(_plugin.PortraitPath.Value) ?? CreateFallbackTexture();
		string text = ResolvePath(_plugin.MusicPath.Value);
		if (File.Exists(text))
		{
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(ToFileUri(text), (AudioType)13);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result == 1)
				{
					_musicClip = DownloadHandlerAudioClip.GetContent(request);
					((Object)_musicClip).name = "AssClap";
				}
				else
				{
					_plugin.LogSource.LogWarning((object)("Failed to load music: " + request.error));
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}
		else
		{
			_plugin.LogSource.LogWarning((object)("Music file not found: " + text));
		}
	}

	private void SpawnEncounter(bool forced)
	{
		//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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: 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)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: 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 (IsGameplayReady())
		{
			PlayerAvatar instance = PlayerAvatar.instance;
			Transform val = (((Object)(object)instance.PlayerVisionTarget != (Object)null) ? instance.PlayerVisionTarget.VisionTransform : ((Component)instance).transform);
			Vector3 val2 = Vector3.ProjectOnPlane((((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : val).forward, Vector3.up);
			Vector3 val3 = ((Vector3)(ref val2)).normalized;
			if (((Vector3)(ref val3)).sqrMagnitude < 0.001f)
			{
				val3 = Vector3.forward;
			}
			val2 = Vector3.Cross(Vector3.up, val3);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			float num = Random.Range(0f - _plugin.SpawnSideOffset.Value, _plugin.SpawnSideOffset.Value);
			Vector3 spawnPosition = val.position + val3 * _plugin.SpawnDistance.Value + normalized * num;
			spawnPosition.y = val.position.y + _plugin.SpawnHeightOffset.Value;
			GachiBillboardEnemy gachiBillboardEnemy = new GameObject("GachiBillboardEnemy").AddComponent<GachiBillboardEnemy>();
			gachiBillboardEnemy.Setup(this, _plugin, spawnPosition, _portraitTexture ?? CreateFallbackTexture(), _musicClip);
			_activeEncounter = gachiBillboardEnemy;
			PulseLights(_plugin.LightPulseDuration.Value * 0.6f, _plugin.LightPulseMultiplier.Value);
			ShowEncounterText(forced ? "TEST SPAWN" : "GACHI INCOMING");
		}
	}

	internal void NotifyEncounterFinished(GachiBillboardEnemy encounter)
	{
		if ((Object)(object)_activeEncounter == (Object)(object)encounter)
		{
			_activeEncounter = null;
			_spawnCountdown = _plugin.SpawnIntervalSeconds.Value;
		}
	}

	internal void PulseLights(float duration, float multiplier)
	{
		((MonoBehaviour)this).StartCoroutine(PulseLightsCoroutine(duration, multiplier));
	}

	internal void ShowEncounterText(string text)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)MissionUI.instance != (Object)null)
		{
			MissionUI.instance.MissionText(text, new Color(1f, 0.72f, 0.16f), Color.white, 1.25f);
		}
	}

	private IEnumerator PulseLightsCoroutine(float duration, float multiplier)
	{
		Light[] array = Object.FindObjectsOfType<Light>();
		Dictionary<Light, float> originals = new Dictionary<Light, float>();
		foreach (Light val in array)
		{
			if ((Object)(object)val != (Object)null)
			{
				originals[val] = val.intensity;
			}
		}
		float elapsed = 0f;
		while (elapsed < duration)
		{
			elapsed += Time.deltaTime;
			float num = 0.5f + Mathf.Sin(elapsed * 24f) * 0.5f;
			float num2 = Mathf.Lerp(1f, multiplier, num);
			foreach (KeyValuePair<Light, float> item in originals)
			{
				if ((Object)(object)item.Key != (Object)null)
				{
					item.Key.intensity = item.Value * num2;
				}
			}
			yield return null;
		}
		foreach (KeyValuePair<Light, float> item2 in originals)
		{
			if ((Object)(object)item2.Key != (Object)null)
			{
				item2.Key.intensity = item2.Value;
			}
		}
	}

	private Texture2D LoadPortraitTexture(string configuredPath)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		string text = ResolvePath(configuredPath);
		if (!File.Exists(text))
		{
			_plugin.LogSource.LogWarning((object)("Portrait file not found: " + text));
			return null;
		}
		try
		{
			byte[] array = File.ReadAllBytes(text);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array, false))
			{
				Object.Destroy((Object)(object)val);
				_plugin.LogSource.LogWarning((object)("Could not decode portrait file: " + text));
				return null;
			}
			Texture2D val2 = CenterCropAndResize(val, 512, 512);
			Object.Destroy((Object)(object)val);
			((Object)val2).name = "GachiPortrait";
			((Texture)val2).wrapMode = (TextureWrapMode)1;
			((Texture)val2).filterMode = (FilterMode)1;
			return val2;
		}
		catch (Exception ex)
		{
			_plugin.LogSource.LogWarning((object)("Portrait load failed: " + ex.Message));
			return null;
		}
	}

	private static Texture2D CenterCropAndResize(Texture2D source, int width, int height)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
		float num = (float)((Texture)source).width / (float)((Texture)source).height;
		float num2 = (float)width / (float)height;
		int num3 = ((Texture)source).width;
		int num4 = ((Texture)source).height;
		float num5 = 0f;
		float num6 = 0f;
		if (num > num2)
		{
			num3 = Mathf.RoundToInt((float)((Texture)source).height * num2);
			num5 = (float)(((Texture)source).width - num3) * 0.5f;
		}
		else
		{
			num4 = Mathf.RoundToInt((float)((Texture)source).width / num2);
			num6 = (float)(((Texture)source).height - num4) * 0.5f;
		}
		for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				float num7 = (num5 + (float)j / (float)(width - 1) * (float)num3) / (float)((Texture)source).width;
				float num8 = (num6 + (float)i / (float)(height - 1) * (float)num4) / (float)((Texture)source).height;
				val.SetPixel(j, i, source.GetPixelBilinear(num7, num8));
			}
		}
		val.Apply();
		return val;
	}

	private static Texture2D CreateFallbackTexture()
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_0058: 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)
		Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0.96f, 0.76f, 0.16f, 1f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0.15f, 0.15f, 0.15f, 1f);
		for (int i = 0; i < ((Texture)val).height; i++)
		{
			for (int j = 0; j < ((Texture)val).width; j++)
			{
				val.SetPixel(j, i, ((j + i) % 2 == 0) ? val2 : val3);
			}
		}
		val.Apply();
		((Texture)val).wrapMode = (TextureWrapMode)1;
		return val;
	}

	private string ResolvePath(string configuredPath)
	{
		if (string.IsNullOrWhiteSpace(configuredPath))
		{
			return string.Empty;
		}
		if (Path.IsPathRooted(configuredPath))
		{
			return configuredPath;
		}
		return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)_plugin).Info.Location) ?? string.Empty, configuredPath));
	}

	private static string ToFileUri(string path)
	{
		return new Uri(path).AbsoluteUri;
	}
}
internal sealed class GachiBillboardEnemy : MonoBehaviour
{
	private GachiEncounterController _controller;

	private RepoGachiBillboardEncounterPlugin _plugin;

	private AudioClip _musicClip;

	private PlayerAvatar _player;

	private Transform _targetTransform;

	private AudioSource _audioSource;

	private GameObject _quad;

	private Material _quadMaterial;

	private bool _caught;

	private bool _cleanupStarted;

	private bool _nearPulseTriggered;

	private float _lifetime;

	private float _bobTime;

	public void Setup(GachiEncounterController controller, RepoGachiBillboardEncounterPlugin plugin, Vector3 spawnPosition, Texture2D portraitTexture, AudioClip musicClip)
	{
		//IL_007c: 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_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Expected O, but got Unknown
		_controller = controller;
		_plugin = plugin;
		_musicClip = musicClip;
		_player = PlayerAvatar.instance;
		_targetTransform = (((Object)(object)_player != (Object)null && (Object)(object)_player.PlayerVisionTarget != (Object)null) ? _player.PlayerVisionTarget.VisionTransform : (((Object)(object)_player != (Object)null) ? ((Component)_player).transform : null));
		((Component)this).transform.position = spawnPosition;
		_quad = GameObject.CreatePrimitive((PrimitiveType)5);
		((Object)_quad).name = "Billboard";
		_quad.transform.SetParent(((Component)this).transform, false);
		_quad.transform.localScale = new Vector3(_plugin.BillboardWidth.Value, _plugin.BillboardHeight.Value, 1f);
		Collider component = _quad.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.Destroy((Object)(object)component);
		}
		_quadMaterial = new Material(Shader.Find("Unlit/Transparent") ?? Shader.Find("Sprites/Default"));
		_quadMaterial.mainTexture = (Texture)(object)portraitTexture;
		MeshRenderer component2 = _quad.GetComponent<MeshRenderer>();
		((Renderer)component2).material = _quadMaterial;
		((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)component2).receiveShadows = false;
		_audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		_audioSource.playOnAwake = false;
		_audioSource.loop = true;
		_audioSource.spatialBlend = 1f;
		_audioSource.rolloffMode = (AudioRolloffMode)1;
		_audioSource.minDistance = 3f;
		_audioSource.maxDistance = _plugin.MusicDistanceMax.Value;
		_audioSource.volume = _plugin.MusicVolumeFar.Value;
		_audioSource.clip = _musicClip;
		if ((Object)(object)_musicClip != (Object)null)
		{
			_audioSource.Play();
		}
	}

	private void Update()
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		if (_cleanupStarted)
		{
			return;
		}
		_lifetime += Time.deltaTime;
		_bobTime += Time.deltaTime;
		if ((Object)(object)_player == (Object)null || (Object)(object)PlayerController.instance == (Object)null || (Object)(object)Camera.main == (Object)null || (Object)(object)_targetTransform == (Object)null)
		{
			FinishEncounter();
			return;
		}
		if (_lifetime > _plugin.MaxEncounterDuration.Value)
		{
			FinishEncounter();
			return;
		}
		Vector3 position = _targetTransform.position;
		Vector3 position2 = ((Component)this).transform.position;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(position.x, position.y + _plugin.SpawnHeightOffset.Value, position.z);
		((Component)this).transform.position = Vector3.MoveTowards(position2, val, _plugin.ChaseSpeed.Value * Time.deltaTime);
		_quad.transform.localPosition = new Vector3(0f, Mathf.Sin(_bobTime * _plugin.BobFrequency.Value) * _plugin.BobAmplitude.Value, 0f);
		Transform transform = ((Component)Camera.main).transform;
		_quad.transform.LookAt(transform.position, Vector3.up);
		_quad.transform.Rotate(0f, 180f, 0f);
		float num = Vector3.Distance(((Component)this).transform.position, position);
		float num2 = 1f - Mathf.Clamp01(num / Mathf.Max(1f, _plugin.MusicDistanceMax.Value));
		if ((Object)(object)_audioSource != (Object)null)
		{
			_audioSource.volume = Mathf.Lerp(_plugin.MusicVolumeFar.Value, _plugin.MusicVolumeNear.Value, num2);
			_audioSource.pitch = Mathf.Lerp(0.95f, 1.08f, num2);
		}
		if (!_nearPulseTriggered && num2 > 0.58f)
		{
			_nearPulseTriggered = true;
			_controller.PulseLights(_plugin.LightPulseDuration.Value * 0.8f, _plugin.LightPulseMultiplier.Value + 0.3f);
			_player.FlashlightFlicker(1.6f);
			_player.PlayerGlitchShort();
		}
		if (!_caught && num <= _plugin.CatchDistance.Value)
		{
			((MonoBehaviour)this).StartCoroutine(CatchSequence());
		}
	}

	private IEnumerator CatchSequence()
	{
		_caught = true;
		_controller.ShowEncounterText("ASSCLAP!");
		_controller.PulseLights(_plugin.LightPulseDuration.Value, _plugin.LightPulseMultiplier.Value + 0.5f);
		PlayerController instance = PlayerController.instance;
		PlayerVoiceChat instance2 = PlayerVoiceChat.instance;
		if ((Object)(object)_player != (Object)null)
		{
			_player.PlayerGlitchShort();
			_player.FlashlightFlicker(2.2f);
			Vector3 val;
			if ((Object)(object)_player.tumble != (Object)null)
			{
				val = ((Component)_player).transform.position - ((Component)this).transform.position;
				Vector3 val2 = ((Vector3)(ref val)).normalized;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
				{
					val2 = -((Component)this).transform.forward;
				}
				_player.tumble.TumbleSet(true, false);
				_player.tumble.TumbleForce(val2 * _plugin.TumbleForce.Value + Vector3.up * _plugin.TumbleUpwardForce.Value);
				_player.tumble.TumbleOverrideTime(_plugin.TumbleDuration.Value);
				_player.tumble.OverrideLookAtCamera(_plugin.GlitchDuration.Value, 18f, 0.7f);
			}
			val = ((Component)_player).transform.position - ((Component)this).transform.position;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			_player.ForceImpulse(normalized * _plugin.PushbackForce.Value);
		}
		if ((Object)(object)instance != (Object)null)
		{
			instance.InputDisable(_plugin.InputLockDuration.Value);
			instance.OverrideSpeed(_plugin.SlowMultiplier.Value, _plugin.SlowDuration.Value);
			instance.OverrideLookSpeed(_plugin.LookSpeedMultiplier.Value, 0.05f, 0.25f, _plugin.SlowDuration.Value);
		}
		if ((Object)(object)instance2 != (Object)null)
		{
			instance2.OverridePitch(1.42f, 0.05f, 0.2f, _plugin.GlitchDuration.Value, 0.18f, 28f);
			instance2.OverrideVolumeStutter(_plugin.GlitchDuration.Value);
			instance2.OverrideHearSelf(0f, _plugin.GlitchDuration.Value);
		}
		TryKnockItemsAway();
		float catchTimer = 0.9f;
		while (catchTimer > 0f)
		{
			catchTimer -= Time.deltaTime;
			if ((Object)(object)_audioSource != (Object)null)
			{
				_audioSource.pitch = Mathf.Lerp(_audioSource.pitch, 1.18f, Time.deltaTime * 10f);
				_audioSource.volume = Mathf.Lerp(_audioSource.volume, _plugin.MusicVolumeNear.Value, Time.deltaTime * 10f);
			}
			yield return null;
		}
		FinishEncounter();
	}

	private void TryKnockItemsAway()
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		Inventory instance = Inventory.instance;
		if ((Object)(object)instance != (Object)null)
		{
			instance.ForceUnequip();
			if (_plugin.DropInventoryOnCatch.Value && (Object)(object)_player != (Object)null && (Object)(object)_player.photonView != (Object)null)
			{
				instance.InventoryDropAll(((Component)_player).transform.position + ((Component)_player).transform.forward + Vector3.up * 0.4f, _player.photonView.ViewID);
			}
		}
		PhysGrabber instance2 = PhysGrabber.instance;
		if ((Object)(object)instance2 == (Object)null || !instance2.grabbed)
		{
			return;
		}
		object? obj = ((object)instance2).GetType().GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance2);
		PhysGrabObject val = (PhysGrabObject)((obj is PhysGrabObject) ? obj : null);
		if ((Object)(object)val != (Object)null)
		{
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null)
			{
				instance2.ReleaseObject(component.ViewID, 0.5f);
			}
		}
	}

	private void FinishEncounter()
	{
		if (!_cleanupStarted)
		{
			_cleanupStarted = true;
			_controller.NotifyEncounterFinished(this);
			if ((Object)(object)_audioSource != (Object)null)
			{
				_audioSource.Stop();
			}
			if ((Object)(object)_quadMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_quadMaterial);
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}

	public void ForceCleanup()
	{
		FinishEncounter();
	}
}