Decompiled source of PingoEnemy v2.0.0

BepInEx\plugins\PingoEnemy\PingoEnemy.dll

Decompiled 2 months 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PingoEnemy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PingoEnemy")]
[assembly: AssemblyTitle("PingoEnemy")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PingoEnemy
{
	[BepInPlugin("JLeonL.PingoEnemy", "Pingo Enemy", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class PingoEnemyPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "JLeonL.PingoEnemy";

		public const string PluginName = "Pingo Enemy";

		public const string PluginVersion = "2.0.0";

		internal static ManualLogSource Log;

		internal static PingoEnemyPlugin Instance;

		internal static AssetBundle? Bundle;

		internal static AudioClip? PingoClip;

		internal static EnemyType? RegisteredEnemyType;

		internal static GameObject? RegisteredEnemyPrefab;

		internal static Texture2D? LuigiBodyTexture;

		internal static Texture2D? LuigiBodyNormalTexture;

		internal static Texture2D? LuigiEyeTexture;

		internal static Texture2D? LuigiEye1Texture;

		internal static Texture2D? LuigiEye2Texture;

		private static ConfigEntry<int> spawnWeight;

		private static ConfigEntry<bool> enableDebugSpawnKey;

		private static ConfigEntry<bool> forceSpawnAfterLanding;

		private static ConfigEntry<float> minimumVisualHeight;

		private static ConfigEntry<bool> forceTestSpawnInFrontOfPlayer;

		private static ConfigEntry<bool> forceVisibleFallbackBody;

		private static bool spawnedAfterLanding;

		private float nextDebugSpawnAllowedAt;

		private static bool debugSpawnKeyWasDown;

		internal static bool ForceSpawnAfterLandingEnabled => forceSpawnAfterLanding.Value;

		internal static float MinimumVisualHeight => Mathf.Max(1.8f, minimumVisualHeight.Value);

		internal static bool ForceTestSpawnInFrontOfPlayer => forceTestSpawnInFrontOfPlayer.Value;

		internal static bool ForceVisibleFallbackBody => forceVisibleFallbackBody.Value;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			Harmony.CreateAndPatchAll(typeof(PingoEnemyPlugin).Assembly, "JLeonL.PingoEnemy");
			try
			{
				LoadAssets();
				((MonoBehaviour)this).StartCoroutine(LoadAudioFromDisk());
				RegisterEnemy();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Pingo Enemy loaded.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("Failed to load {0}: {1}", "Pingo Enemy", arg));
			}
		}

		private void Update()
		{
			if (enableDebugSpawnKey.Value && DebugSpawnKeyPressed() && Time.time >= nextDebugSpawnAllowedAt)
			{
				nextDebugSpawnAllowedAt = Time.time + 1f;
				Log.LogInfo((object)"Detected Pingo debug spawn hotkey F6.");
				SpawnPingoNearLocalPlayer("debug hotkey");
			}
			if (forceSpawnAfterLanding.Value && !spawnedAfterLanding && !((Object)(object)StartOfRound.Instance == (Object)null) && StartOfRound.Instance.shipHasLanded)
			{
				spawnedAfterLanding = true;
				SpawnPingoNearLocalPlayer("force spawn after landing");
			}
		}

		internal static void ResetForcedSpawnForNewRound()
		{
			spawnedAfterLanding = false;
			Log.LogInfo((object)"Reset Pingo forced spawn state for new round.");
		}

		internal static void TryForceSpawnAfterLanding(string reason)
		{
			if (!ForceSpawnAfterLandingEnabled)
			{
				Log.LogInfo((object)("Skipped forced Pingo spawn for " + reason + ": config disabled."));
				return;
			}
			if (spawnedAfterLanding)
			{
				Log.LogInfo((object)("Skipped forced Pingo spawn for " + reason + ": already spawned this round."));
				return;
			}
			spawnedAfterLanding = true;
			SpawnPingoNearLocalPlayer(reason);
		}

		private void BindConfig()
		{
			spawnWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "SpawnWeight", 175, "Normal LethalLib spawn weight for Pingo. Default is roughly x5 a common enemy weight.");
			enableDebugSpawnKey = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "EnableDebugSpawnKey", false, "If true, the host can press F6 in a round to spawn Pingo near the local player.");
			forceSpawnAfterLanding = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "ForceSpawnAfterLanding", false, "If true, the host spawns one Pingo near the local player after the ship lands.");
			forceTestSpawnInFrontOfPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "ForceTestSpawnInFrontOfPlayer", true, "If true, forced/debug spawns appear directly in front of the local player instead of snapping to dungeon NavMesh.");
			minimumVisualHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "MinimumVisualHeight", 2.1f, "Minimum world-space height for Pingo's visible model. A player is roughly this height.");
			forceVisibleFallbackBody = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "ForceVisibleFallbackBody", false, "If true, adds a simple player-sized visible body so Pingo can never be invisible while testing.");
		}

		private static bool DebugSpawnKeyPressed()
		{
			Keyboard current = Keyboard.current;
			bool flag = Input.GetKey((KeyCode)287) || (current != null && ((ButtonControl)current.f6Key).isPressed) || (current != null && ((ButtonControl)current.f6Key).wasPressedThisFrame);
			bool result = flag && !debugSpawnKeyWasDown;
			debugSpawnKeyWasDown = flag;
			return result;
		}

		private static void LoadAssets()
		{
			string text = Path.Combine(Path.GetDirectoryName(typeof(PingoEnemyPlugin).Assembly.Location), "pingoenemyassets");
			if (File.Exists(text))
			{
				Bundle = AssetBundle.LoadFromFile(text);
				AssetBundle? bundle = Bundle;
				PingoClip = ((bundle != null) ? bundle.LoadAsset<AudioClip>("pingo") : null);
				AssetBundle? bundle2 = Bundle;
				LuigiBodyTexture = ((bundle2 != null) ? bundle2.LoadAsset<Texture2D>("pc02_body") : null);
				AssetBundle? bundle3 = Bundle;
				LuigiBodyNormalTexture = ((bundle3 != null) ? bundle3.LoadAsset<Texture2D>("pc02_body_nml") : null);
				AssetBundle? bundle4 = Bundle;
				LuigiEyeTexture = ((bundle4 != null) ? bundle4.LoadAsset<Texture2D>("pc02_eye") : null);
				AssetBundle? bundle5 = Bundle;
				LuigiEye1Texture = ((bundle5 != null) ? bundle5.LoadAsset<Texture2D>("Luigi_eye_1") : null);
				AssetBundle? bundle6 = Bundle;
				LuigiEye2Texture = ((bundle6 != null) ? bundle6.LoadAsset<Texture2D>("Luigi_Eye2") : null);
				Log.LogInfo((object)(((Object)(object)Bundle == (Object)null) ? ("Failed to load AssetBundle from " + text) : ("Loaded AssetBundle from " + text)));
				Log.LogInfo((object)(((Object)(object)PingoClip == (Object)null) ? "AssetBundle did not contain an AudioClip named 'pingo'." : ("Loaded AudioClip '" + ((Object)PingoClip).name + "' from AssetBundle.")));
				Log.LogInfo((object)$"Loaded texture assets: body={(Object)(object)LuigiBodyTexture != (Object)null}; normal={(Object)(object)LuigiBodyNormalTexture != (Object)null}; pcEye={(Object)(object)LuigiEyeTexture != (Object)null}; luigiEye1={(Object)(object)LuigiEye1Texture != (Object)null}; luigiEye2={(Object)(object)LuigiEye2Texture != (Object)null}.");
			}
			else
			{
				Log.LogWarning((object)("Missing AssetBundle at " + text + "; Pingo will use the fallback prefab."));
			}
			if ((Object)(object)PingoClip == (Object)null)
			{
				Log.LogInfo((object)"No AssetBundle audio found. Falling back to direct pingo.mp3 loading.");
			}
		}

		private static IEnumerator LoadAudioFromDisk()
		{
			if ((Object)(object)PingoClip != (Object)null)
			{
				yield break;
			}
			string text = Path.Combine(Path.GetDirectoryName(typeof(PingoEnemyPlugin).Assembly.Location), "pingo.mp3");
			if (!File.Exists(text))
			{
				Log.LogWarning((object)("Missing audio file: " + text));
				yield break;
			}
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(text).AbsoluteUri, (AudioType)13);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Log.LogWarning((object)("Could not load pingo.mp3: " + request.error));
					yield break;
				}
				PingoClip = DownloadHandlerAudioClip.GetContent(request);
				((Object)PingoClip).name = "pingo";
				Log.LogInfo((object)"Loaded pingo.mp3 directly from plugin folder.");
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static void RegisterEnemy()
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			AssetBundle? bundle = Bundle;
			GameObject val = ((bundle != null) ? bundle.LoadAsset<GameObject>("PingoEnemy") : null);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"AssetBundle did not contain a GameObject named 'PingoEnemy'; using fallback prefab.");
				val = CreatePlaceholderPrefab();
			}
			else
			{
				Log.LogInfo((object)("Loaded enemy prefab '" + ((Object)val).name + "' from AssetBundle."));
			}
			EnsureEnemyComponents(val);
			((Object)val).name = "Pingo";
			RegisteredEnemyPrefab = val;
			EnemyType val2 = ScriptableObject.CreateInstance<EnemyType>();
			((Object)val2).name = "Pingo";
			val2.enemyName = "Pingo";
			val2.enemyPrefab = val;
			val2.MaxCount = 1;
			val2.PowerLevel = 0f;
			val2.probabilityCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 1f)
			});
			val2.numberSpawnedFalloff = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 1f)
			});
			val2.isOutsideEnemy = false;
			val2.isDaytimeEnemy = false;
			val2.normalizedTimeInDayToLeave = 1f;
			val2.stunTimeMultiplier = 1f;
			val2.canSeeThroughFog = false;
			((EnemyAI)val.GetComponent<PingoEnemyAI>()).enemyType = val2;
			TerminalNode val3 = ScriptableObject.CreateInstance<TerminalNode>();
			val3.creatureName = "Pingo";
			val3.displayText = "Pingo\n\nNo mata, pero ahora patrulla el interior y persigue a los jugadores que ve mientras hace ruido cada vez con mas insistencia.\n";
			val3.clearPreviousText = true;
			val3.maxCharactersToType = 2000;
			TerminalKeyword val4 = ScriptableObject.CreateInstance<TerminalKeyword>();
			val4.word = "pingo";
			val4.isVerb = false;
			RegisteredEnemyType = val2;
			Enemies.RegisterEnemy(val2, Mathf.Max(0, spawnWeight.Value), (LevelTypes)(-1), val3, val4);
			TryRegisterNetworkPrefab("RegisterEnemy");
		}

		internal static void TryRegisterNetworkPrefab(string reason)
		{
			if ((Object)(object)RegisteredEnemyPrefab == (Object)null)
			{
				Log.LogWarning((object)("Cannot register Pingo network prefab for " + reason + ": prefab is null."));
				return;
			}
			NetworkObject component = RegisteredEnemyPrefab.GetComponent<NetworkObject>();
			if ((Object)(object)component == (Object)null)
			{
				Log.LogWarning((object)("Cannot register Pingo network prefab for " + reason + ": prefab has no NetworkObject."));
				return;
			}
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				Log.LogInfo((object)("Deferred Pingo network prefab registration for " + reason + ": NetworkManager.Singleton is null."));
				return;
			}
			try
			{
				NetworkManager.Singleton.AddNetworkPrefab(RegisteredEnemyPrefab);
				Log.LogInfo((object)$"Registered Pingo network prefab with Netcode for {reason}. prefab={((Object)RegisteredEnemyPrefab).name}; networkObject={(Object)(object)component != (Object)null}");
			}
			catch (Exception ex)
			{
				string text = ex.Message ?? string.Empty;
				if (text.IndexOf("already", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("duplicate", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Log.LogInfo((object)("Pingo network prefab was already registered for " + reason + "."));
				}
				else
				{
					Log.LogWarning((object)$"Could not register Pingo network prefab for {reason}: {ex}");
				}
			}
		}

		internal static bool SpawnPingoNearLocalPlayer(string reason)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || (!NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer))
			{
				Log.LogInfo((object)("Ignored Pingo spawn request from non-host client: " + reason));
				return false;
			}
			if ((Object)(object)RoundManager.Instance == (Object)null)
			{
				Log.LogInfo((object)("Ignored Pingo spawn request before a round manager exists: " + reason));
				return false;
			}
			if ((Object)(object)RegisteredEnemyType == (Object)null)
			{
				Log.LogWarning((object)("Cannot spawn Pingo for " + reason + ": enemy type is not registered."));
				return false;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)("Cannot spawn Pingo for " + reason + ": no local player."));
				return false;
			}
			if (!TryGetInteriorSpawnPosition(val, out var spawnPosition))
			{
				Log.LogWarning((object)("Cannot spawn Pingo for " + reason + ": no interior NavMesh spawn position was found."));
				return false;
			}
			NavMeshHit val2 = default(NavMeshHit);
			if (NavMesh.SamplePosition(spawnPosition, ref val2, 8f, -1))
			{
				spawnPosition = ((NavMeshHit)(ref val2)).position;
				float num = ((Component)val).transform.eulerAngles.y + 180f;
				RoundManager.Instance.SpawnEnemyGameObject(spawnPosition, num, -1, RegisteredEnemyType);
				Log.LogInfo((object)("Spawned Pingo near local player for " + reason + "."));
				return true;
			}
			Log.LogWarning((object)$"Cannot spawn Pingo for {reason}: chosen interior position has no nearby NavMesh ({spawnPosition}).");
			return false;
		}

		private static bool TryGetInteriorSpawnPosition(PlayerControllerB player, out Vector3 spawnPosition)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			RoundManager instance = RoundManager.Instance;
			if (instance?.insideAINodes != null && instance.insideAINodes.Length != 0)
			{
				Transform closestNode = instance.GetClosestNode(((Component)player).transform.position, false);
				if ((Object)(object)closestNode != (Object)null)
				{
					spawnPosition = closestNode.position;
					Log.LogInfo((object)$"Pingo interior test spawn selected closest indoor AI node: {spawnPosition}.");
					return true;
				}
				for (int i = 0; i < instance.insideAINodes.Length; i++)
				{
					GameObject val = instance.insideAINodes[i];
					if (!((Object)(object)val == (Object)null))
					{
						spawnPosition = val.transform.position;
						Log.LogInfo((object)$"Pingo interior test spawn selected fallback indoor AI node: {spawnPosition}.");
						return true;
					}
				}
			}
			if (player.isInsideFactory)
			{
				spawnPosition = GetSafeSpawnPositionInFrontOfPlayer(player);
				Log.LogInfo((object)$"Pingo interior test spawn selected player-front position inside factory: {spawnPosition}.");
				return true;
			}
			spawnPosition = Vector3.zero;
			return false;
		}

		private static Vector3 GetSafeSpawnPositionInFrontOfPlayer(PlayerControllerB player)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00e9: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			Camera gameplayCamera = player.gameplayCamera;
			Vector3 val = (((Object)(object)gameplayCamera != (Object)null) ? ((Component)gameplayCamera).transform.position : (((Component)player).transform.position + Vector3.up * 1.6f));
			Vector3 val2 = (((Object)(object)gameplayCamera != (Object)null) ? ((Component)gameplayCamera).transform.forward : ((Component)player).transform.forward);
			val2.y = 0f;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = ((Component)player).transform.forward;
			}
			Vector3 val3 = val + ((Vector3)(ref val2)).normalized * 3f;
			val3.y = val.y + 1f;
			RaycastHit val4 = default(RaycastHit);
			if (Physics.Raycast(val3, Vector3.down, ref val4, 12f, StartOfRound.Instance.collidersAndRoomMaskAndDefault))
			{
				val3 = ((RaycastHit)(ref val4)).point + Vector3.up * 0.05f;
			}
			else
			{
				val3.y = ((Component)player).transform.position.y + 0.05f;
			}
			Log.LogInfo((object)$"Pingo safe test spawn position: player={((Component)player).transform.position}; spawn={val3}; forceInFront={ForceTestSpawnInFrontOfPlayer}.");
			return val3;
		}

		private static GameObject CreatePlaceholderPrefab()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)1);
			((Object)obj).name = "Pingo";
			obj.transform.localScale = new Vector3(0.8f, 1.25f, 0.8f);
			Object.DontDestroyOnLoad((Object)(object)obj);
			obj.SetActive(false);
			return obj;
		}

		private static void EnsureEnemyComponents(GameObject prefab)
		{
			if ((Object)(object)prefab.GetComponent<NetworkObject>() == (Object)null)
			{
				prefab.AddComponent<NetworkObject>();
			}
			(prefab.GetComponent<NetworkTransform>() ?? prefab.AddComponent<NetworkTransform>()).Interpolate = true;
			((EnemyAI)(prefab.GetComponent<PingoEnemyAI>() ?? prefab.AddComponent<PingoEnemyAI>())).enemyType = null;
			NavMeshAgent obj = prefab.GetComponent<NavMeshAgent>() ?? prefab.AddComponent<NavMeshAgent>();
			obj.speed = 2.2f;
			obj.angularSpeed = 360f;
			obj.acceleration = 10f;
			obj.stoppingDistance = 1.4f;
			obj.updatePosition = true;
			obj.updateRotation = false;
			AudioSource obj2 = prefab.GetComponent<AudioSource>() ?? prefab.AddComponent<AudioSource>();
			obj2.playOnAwake = false;
			obj2.spatialize = false;
			obj2.spatializePostEffects = false;
			obj2.spatialBlend = 1f;
			obj2.rolloffMode = (AudioRolloffMode)1;
			obj2.minDistance = 4f;
			obj2.maxDistance = 35f;
			EnsureScanNode(prefab);
		}

		private static void EnsureScanNode(GameObject prefab)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			ScanNodeProperties val = prefab.GetComponentInChildren<ScanNodeProperties>(true);
			GameObject val2;
			if ((Object)(object)val == (Object)null)
			{
				val2 = new GameObject("PingoScanNode");
				val2.transform.SetParent(prefab.transform, false);
				val = val2.AddComponent<ScanNodeProperties>();
			}
			else
			{
				val2 = ((Component)val).gameObject;
			}
			((Object)val2).name = "PingoScanNode";
			val2.transform.localPosition = Vector3.up * 1.15f;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = Vector3.one;
			int num = LayerMask.NameToLayer("ScanNode");
			if (num >= 0)
			{
				val2.layer = num;
			}
			SphereCollider obj = val2.GetComponent<SphereCollider>() ?? val2.AddComponent<SphereCollider>();
			((Collider)obj).isTrigger = true;
			obj.radius = 1.25f;
			val.headerText = "Pingo";
			val.subText = "Enemy";
			val.nodeType = 1;
			val.creatureScanID = -1;
			val.minRange = 1;
			val.maxRange = 80;
			val.requiresLineOfSight = false;
		}
	}
	public sealed class PingoEnemyAI : EnemyAI
	{
		private const float BaseInterval = 16f;

		private const float MinimumInterval = 1.25f;

		private const float SameRoomMultiplier = 0.45f;

		private const float LookingMultiplier = 0.55f;

		private const float NearVolumeRadius = 18f;

		private const float NearVolumeStepSeconds = 10f;

		private const float NearVolumeStepGain = 0.1f;

		private const float OverlapRampStartSeconds = 60f;

		private const float IntervalReductionPerNearPlay = 0.1f;

		private const float OverlapMinimumInterval = 0.1f;

		private const int MinimumIntervalPlaysBeforeReset = 30;

		private const float WanderSpeed = 1.6f;

		private const float ChaseSpeed = 3.2f;

		private const float RotationSpeed = 8f;

		private const float TargetScanInterval = 0.5f;

		private const float ChasePathRefreshInterval = 0.2f;

		private const float WanderRefreshInterval = 4f;

		private const float TargetCooldownSeconds = 30f;

		private const float VisionRange = 45f;

		private const float VisionDotThreshold = 0.15f;

		private const float LoseTargetDistance = 70f;

		private const float ExplosionWarningSeconds = 1f;

		private const float ExplosionKillRadius = 3f;

		private const int ExplosionDamage = 200;

		private AudioSource? source;

		private float nextNoiseAt;

		private float aliveForSeconds;

		private float nearPlayerSeconds;

		private float accumulatedIntervalReduction;

		private int minimumIntervalPlayCount;

		private PlayerControllerB? currentPursuitTarget;

		private readonly Dictionary<ulong, float> targetCooldownUntil = new Dictionary<ulong, float>();

		private float nextTargetScanAt;

		private float nextChasePathRefreshAt;

		private float nextWanderRefreshAt;

		private Vector3 lastPosition;

		private Transform? leftUpperArm;

		private Transform? rightUpperArm;

		private Transform? leftForearm;

		private Transform? rightForearm;

		private Transform? leftThigh;

		private Transform? rightThigh;

		private Transform? leftCalf;

		private Transform? rightCalf;

		private Transform? leftFoot;

		private Transform? rightFoot;

		private Transform? spine;

		private Transform? head;

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

		private float walkCycle;

		private float visualMovementSpeed;

		private bool explosionCharging;

		private float explosionAt;

		public override void Start()
		{
			//IL_00b0: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).Start();
			source = ((Component)this).GetComponent<AudioSource>();
			if ((Object)(object)source != (Object)null && (Object)(object)PingoEnemyPlugin.PingoClip != (Object)null)
			{
				source.clip = PingoEnemyPlugin.PingoClip;
				source.spatialize = false;
				source.spatializePostEffects = false;
				source.volume = 1f;
			}
			((Object)((Component)this).gameObject).name = "Pingo";
			EnsureRuntimeScanNode();
			base.movingTowardsTargetPlayer = false;
			nextNoiseAt = Time.time + 3f;
			nextTargetScanAt = Time.time;
			nextWanderRefreshAt = Time.time;
			lastPosition = ((Component)this).transform.position;
			ConfigureAgentForMovement(1.6f);
			((EnemyAI)this).SetEnemyOutside(false);
			base.isOutside = false;
			CacheLuigiBones();
			ApplyProceduralPose(0f, 0f);
			EnsureVisibleFallbackBody();
			ApplyLuigiMaterials();
			PingoEnemyPlugin.Log.LogInfo((object)$"PingoEnemyAI started at {((Component)this).transform.position}; hasAudio={(Object)(object)PingoEnemyPlugin.PingoClip != (Object)null}; isOwner={((NetworkBehaviour)this).IsOwner}.");
			((MonoBehaviour)this).StartCoroutine(NormalizeVisualsAfterSpawn());
		}

		private void ApplyLuigiMaterials()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren.Length == 0)
			{
				PingoEnemyPlugin.Log.LogWarning((object)"Cannot apply Luigi materials: Pingo has no renderers.");
				return;
			}
			Material body = CreateOpaqueMaterial("Pingo_Luigi_Body_Runtime", PingoEnemyPlugin.LuigiBodyTexture, PingoEnemyPlugin.LuigiBodyNormalTexture, Color.white);
			Material eyes = CreateEyeMaterial("Pingo_Luigi_Eyes_Runtime", PingoEnemyPlugin.LuigiEyeTexture);
			Material skin = CreateOpaqueMaterial("Pingo_Luigi_Skin_Runtime", null, null, new Color(1f, 0.72f, 0.52f, 1f));
			Material gloves = CreateOpaqueMaterial("Pingo_Luigi_Gloves_Runtime", null, null, Color.white);
			Material shoes = CreateOpaqueMaterial("Pingo_Luigi_Shoes_Runtime", null, null, new Color(0.35f, 0.16f, 0.06f, 1f));
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					string slotName = (((Object)(object)sharedMaterials[j] != (Object)null) ? ((Object)sharedMaterials[j]).name.ToLowerInvariant() : string.Empty);
					string rendererName = ((Object)val).name.ToLowerInvariant();
					sharedMaterials[j] = ChooseLuigiMaterial(rendererName, slotName, j, body, eyes, skin, gloves, shoes);
				}
				val.sharedMaterials = sharedMaterials;
				val.enabled = true;
			}
			PingoEnemyPlugin.Log.LogInfo((object)$"Applied runtime Luigi materials to {componentsInChildren.Length} renderer(s).");
		}

		private static Material ChooseLuigiMaterial(string rendererName, string slotName, int materialIndex, Material body, Material eyes, Material skin, Material gloves, Material shoes)
		{
			string text = rendererName + " " + slotName;
			if (rendererName == "eye" || text.Contains("eye"))
			{
				return eyes;
			}
			if (rendererName.StartsWith("newluigi_m1shape") && materialIndex >= 3 && materialIndex <= 6)
			{
				return eyes;
			}
			if (text.Contains("hand") || text.Contains("glove"))
			{
				return gloves;
			}
			if (text.Contains("shoe") || text.Contains("boot"))
			{
				return shoes;
			}
			if (text.Contains("skin") || text.Contains("face") || text.Contains("head") || text.Contains("nose") || text.Contains("ear"))
			{
				return skin;
			}
			return body;
		}

		private static Material CreateOpaqueMaterial(string name, Texture2D? baseTexture, Texture2D? normalTexture, Color color)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0032: 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)
			Material val = new Material(Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"))
			{
				name = name,
				color = color
			};
			SetColor(val, "_BaseColor", color);
			SetColor(val, "_Color", color);
			SetFloat(val, "_SurfaceType", 0f);
			SetFloat(val, "_BlendMode", 0f);
			SetFloat(val, "_AlphaCutoffEnable", 0f);
			SetFloat(val, "_TransparentSortPriority", 0f);
			val.renderQueue = -1;
			if ((Object)(object)baseTexture != (Object)null)
			{
				SetTexture(val, "_BaseColorMap", (Texture)(object)baseTexture);
				SetTexture(val, "_MainTex", (Texture)(object)baseTexture);
			}
			if ((Object)(object)normalTexture != (Object)null)
			{
				SetTexture(val, "_NormalMap", (Texture)(object)normalTexture);
				SetTexture(val, "_BumpMap", (Texture)(object)normalTexture);
				val.EnableKeyword("_NORMALMAP");
			}
			return val;
		}

		private static Material CreateEyeMaterial(string name, Texture2D? eyeTexture)
		{
			//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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_006f: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: 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)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			ConfigureEyeTexture(eyeTexture);
			Shader obj = Shader.Find("HDRP/Unlit") ?? Shader.Find("Unlit/Texture") ?? Shader.Find("HDRP/Lit") ?? Shader.Find("Standard");
			Color color = default(Color);
			((Color)(ref color))..ctor(0.8f, 0.8f, 0.8f, 1f);
			Material val = new Material(obj)
			{
				name = name,
				color = color
			};
			SetColor(val, "_BaseColor", color);
			SetColor(val, "_Color", color);
			SetColor(val, "_UnlitColor", color);
			SetFloat(val, "_SurfaceType", 0f);
			SetFloat(val, "_BlendMode", 0f);
			SetFloat(val, "_AlphaCutoffEnable", 0f);
			SetFloat(val, "_Smoothness", 0.35f);
			SetFloat(val, "_Metallic", 0f);
			val.renderQueue = -1;
			if ((Object)(object)eyeTexture != (Object)null)
			{
				SetTexture(val, "_BaseColorMap", (Texture)(object)eyeTexture);
				SetTexture(val, "_UnlitColorMap", (Texture)(object)eyeTexture);
				SetTexture(val, "_MainTex", (Texture)(object)eyeTexture);
				SetTexture(val, "_EmissionMap", (Texture)(object)eyeTexture);
				SetTexture(val, "_EmissiveColorMap", (Texture)(object)eyeTexture);
				SetTextureScale(val, "_BaseColorMap", Vector2.one);
				SetTextureScale(val, "_UnlitColorMap", Vector2.one);
				SetTextureScale(val, "_MainTex", Vector2.one);
				SetTextureOffset(val, "_BaseColorMap", Vector2.zero);
				SetTextureOffset(val, "_UnlitColorMap", Vector2.zero);
				SetTextureOffset(val, "_MainTex", Vector2.zero);
			}
			if (val.HasProperty("_EmissiveColor"))
			{
				val.SetColor("_EmissiveColor", new Color(0.18f, 0.18f, 0.18f, 1f));
			}
			SetColor(val, "_EmissionColor", new Color(0.18f, 0.18f, 0.18f, 1f));
			if (val.HasProperty("_EmissiveIntensity"))
			{
				val.SetFloat("_EmissiveIntensity", 0.2f);
			}
			val.EnableKeyword("_EMISSION");
			return val;
		}

		private static void ConfigureEyeTexture(Texture2D? texture)
		{
			if (!((Object)(object)texture == (Object)null))
			{
				((Texture)texture).wrapMode = (TextureWrapMode)0;
				((Texture)texture).wrapModeU = (TextureWrapMode)0;
				((Texture)texture).wrapModeV = (TextureWrapMode)0;
				((Texture)texture).filterMode = (FilterMode)1;
			}
		}

		private static void SetTexture(Material material, string property, Texture texture)
		{
			if (material.HasProperty(property))
			{
				material.SetTexture(property, texture);
			}
		}

		private static void SetTextureScale(Material material, string property, Vector2 scale)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty(property))
			{
				material.SetTextureScale(property, scale);
			}
		}

		private static void SetTextureOffset(Material material, string property, Vector2 offset)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty(property))
			{
				material.SetTextureOffset(property, offset);
			}
		}

		private static void SetColor(Material material, string property, Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty(property))
			{
				material.SetColor(property, color);
			}
		}

		private static void SetFloat(Material material, string property, float value)
		{
			if (material.HasProperty(property))
			{
				material.SetFloat(property, value);
			}
		}

		private void EnsureVisibleFallbackBody()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_00db: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (PingoEnemyPlugin.ForceVisibleFallbackBody && !((Object)(object)((Component)this).transform.Find("PingoVisibleFallbackBody") != (Object)null))
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)1);
				((Object)obj).name = "PingoVisibleFallbackBody";
				obj.transform.SetParent(((Component)this).transform, false);
				obj.transform.localPosition = Vector3.up * (PingoEnemyPlugin.MinimumVisualHeight * 0.5f);
				obj.transform.localRotation = Quaternion.identity;
				obj.transform.localScale = new Vector3(0.75f, PingoEnemyPlugin.MinimumVisualHeight * 0.5f, 0.75f);
				Collider component = obj.GetComponent<Collider>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				Renderer component2 = obj.GetComponent<Renderer>();
				if ((Object)(object)component2 != (Object)null)
				{
					Material val = new Material(Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"));
					val.color = new Color(0.1f, 0.8f, 0.25f, 1f);
					component2.material = val;
					component2.enabled = true;
				}
				PingoEnemyPlugin.Log.LogInfo((object)$"Added visible fallback body to Pingo. height={PingoEnemyPlugin.MinimumVisualHeight:0.00}; root={((Component)this).transform.position}.");
			}
		}

		private IEnumerator NormalizeVisualsAfterSpawn()
		{
			yield return null;
			Renderer[] renderers = ((Component)this).GetComponentsInChildren<Renderer>(true);
			if (renderers.Length == 0)
			{
				PingoEnemyPlugin.Log.LogWarning((object)"Pingo spawned with no renderers. The model will not be visible.");
				yield break;
			}
			Bounds bounds = renderers[0].bounds;
			for (int i = 1; i < renderers.Length; i++)
			{
				((Bounds)(ref bounds)).Encapsulate(renderers[i].bounds);
			}
			PingoEnemyPlugin.Log.LogInfo((object)$"Pingo visual bounds before normalize: center={((Bounds)(ref bounds)).center}; size={((Bounds)(ref bounds)).size}; rootScale={((Component)this).transform.localScale}.");
			if (((Bounds)(ref bounds)).size.y > 0.01f && ((Bounds)(ref bounds)).size.y < PingoEnemyPlugin.MinimumVisualHeight)
			{
				float scaleFactor = PingoEnemyPlugin.MinimumVisualHeight / ((Bounds)(ref bounds)).size.y;
				Transform transform = ((Component)this).transform;
				transform.localScale *= scaleFactor;
				yield return null;
				bounds = renderers[0].bounds;
				for (int j = 1; j < renderers.Length; j++)
				{
					((Bounds)(ref bounds)).Encapsulate(renderers[j].bounds);
				}
				PingoEnemyPlugin.Log.LogInfo((object)$"Scaled Pingo visual by {scaleFactor:0.00} to meet minimum height {PingoEnemyPlugin.MinimumVisualHeight:0.00}. New size={((Bounds)(ref bounds)).size}; rootScale={((Component)this).transform.localScale}.");
			}
			float y = ((Component)this).transform.position.y;
			if (!(((Bounds)(ref bounds)).min.y < y - 0.05f))
			{
				yield break;
			}
			float num = y - ((Bounds)(ref bounds)).min.y;
			Renderer[] array = renderers;
			for (int k = 0; k < array.Length; k++)
			{
				Transform transform2 = ((Component)array[k]).transform;
				if (!((Object)(object)transform2 == (Object)(object)((Component)this).transform))
				{
					transform2.position += Vector3.up * num;
				}
			}
			PingoEnemyPlugin.Log.LogInfo((object)$"Lifted Pingo visual renderers by {num:0.00} so the model is not below the floor.");
		}

		public override void DoAIInterval()
		{
			((EnemyAI)this).DoAIInterval();
			if (((NetworkBehaviour)this).IsServer)
			{
				UpdateServerMovement(forceDecision: true);
			}
		}

		public override void Update()
		{
			((EnemyAI)this).Update();
			if (((NetworkBehaviour)this).IsServer)
			{
				EnsureAgentOnInteriorNavMesh();
				if (explosionCharging)
				{
					StopForExplosionWarning();
				}
				else
				{
					UpdateServerMovement(forceDecision: false);
				}
			}
			RotateTowardsAttentionOrMovement();
			UpdateProceduralWalkAnimation();
			if ((Object)(object)source == (Object)null || (Object)(object)PingoEnemyPlugin.PingoClip == (Object)null)
			{
				return;
			}
			if ((Object)(object)source.clip == (Object)null)
			{
				source.clip = PingoEnemyPlugin.PingoClip;
			}
			if (explosionCharging)
			{
				if (Time.time >= explosionAt)
				{
					DetonatePingoExplosion();
				}
				return;
			}
			aliveForSeconds += Time.deltaTime;
			UpdateNearPlayerVolumeTimer();
			if (Time.time < nextNoiseAt)
			{
				return;
			}
			float num = CalculateNoiseInterval();
			bool num2 = nearPlayerSeconds >= 60f;
			bool flag = false;
			if (num2)
			{
				num = Mathf.Max(0.1f, num - accumulatedIntervalReduction);
				accumulatedIntervalReduction += 0.1f;
				if (num <= 0.101f)
				{
					minimumIntervalPlayCount++;
					if (minimumIntervalPlayCount >= 30)
					{
						flag = true;
					}
				}
				else
				{
					minimumIntervalPlayCount = 0;
				}
			}
			else
			{
				accumulatedIntervalReduction = 0f;
				minimumIntervalPlayCount = 0;
			}
			nextNoiseAt = Time.time + num;
			PlayPingoLocal(Mathf.Clamp01(1f - num / 16f), CalculateNearVolumeScale(), num, nearPlayerSeconds);
			if (flag)
			{
				StartExplosionWarning();
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB? playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
		}

		private void PlayPingoLocal(float intensity, float volumeScale, float nextInterval, float nearbySeconds)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)source == (Object)null) && !((Object)(object)PingoEnemyPlugin.PingoClip == (Object)null))
			{
				source.pitch = Random.Range(0.94f, 1.06f);
				source.volume = 1f;
				float num = Mathf.Lerp(0.45f, 1f, intensity) * Mathf.Max(1f, volumeScale);
				source.PlayOneShot(PingoEnemyPlugin.PingoClip, num);
				PingoEnemyPlugin.Log.LogInfo((object)$"Pingo played sound. intensity={intensity:0.00}; volumeScale={volumeScale:0.00}; finalVolume={num:0.00}; nextInterval={nextInterval:0.00}; nearbySeconds={nearbySeconds:0.0}; position={((Component)this).transform.position}.");
			}
		}

		private void UpdateNearPlayerVolumeTimer()
		{
			if (AnyPlayerWithinDistance(18f))
			{
				nearPlayerSeconds += Time.deltaTime;
			}
		}

		private void EnsureRuntimeScanNode()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			ScanNodeProperties val = ((Component)this).GetComponentInChildren<ScanNodeProperties>(true);
			GameObject val2;
			if ((Object)(object)val == (Object)null)
			{
				val2 = new GameObject("PingoScanNode");
				val2.transform.SetParent(((Component)this).transform, false);
				val = val2.AddComponent<ScanNodeProperties>();
			}
			else
			{
				val2 = ((Component)val).gameObject;
			}
			((Object)val2).name = "PingoScanNode";
			val2.transform.localPosition = Vector3.up * 1.15f;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = Vector3.one;
			int num = LayerMask.NameToLayer("ScanNode");
			if (num >= 0)
			{
				val2.layer = num;
			}
			SphereCollider obj = val2.GetComponent<SphereCollider>() ?? val2.AddComponent<SphereCollider>();
			((Collider)obj).isTrigger = true;
			obj.radius = 1.25f;
			val.headerText = "Pingo";
			val.subText = "Enemy";
			val.nodeType = 1;
			val.creatureScanID = -1;
			val.minRange = 1;
			val.maxRange = 80;
			val.requiresLineOfSight = false;
		}

		private float CalculateNearVolumeScale()
		{
			float num = Mathf.Floor(nearPlayerSeconds / 10f);
			return 1f + num * 0.1f;
		}

		private float CalculateNoiseInterval()
		{
			//IL_005a: 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)
			float num = Mathf.Clamp01(aliveForSeconds / 600f);
			float num2 = Mathf.Lerp(16f, 4f, num);
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead)
				{
					float num3 = Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position);
					if (num3 <= 18f)
					{
						num2 *= 0.45f;
					}
					if (num3 <= 35f && PlayerIsLookingAtPingo(val))
					{
						num2 *= 0.55f;
					}
				}
			}
			return Mathf.Max(1.25f, num2);
		}

		private bool AnyPlayerWithinDistance(float maxDistance)
		{
			//IL_004d: 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)
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return false;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead && Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) <= maxDistance)
				{
					return true;
				}
			}
			return false;
		}

		private bool PlayerIsLookingAtPingo(PlayerControllerB player)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			Camera gameplayCamera = player.gameplayCamera;
			if ((Object)(object)gameplayCamera == (Object)null)
			{
				return false;
			}
			Vector3 val = ((Component)this).transform.position + Vector3.up - ((Component)gameplayCamera).transform.position;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			return Vector3.Dot(((Component)gameplayCamera).transform.forward, normalized) > 0.75f;
		}

		private void UpdateServerMovement(bool forceDecision)
		{
			((EnemyAI)this).SetEnemyOutside(false);
			base.isOutside = false;
			if ((Object)(object)currentPursuitTarget != (Object)null && !IsValidTarget(currentPursuitTarget, requireVisible: false))
			{
				ClearPursuitTarget("target became invalid");
			}
			if ((Object)(object)currentPursuitTarget == (Object)null && (forceDecision || Time.time >= nextTargetScanAt))
			{
				nextTargetScanAt = Time.time + 0.5f;
				PlayerControllerB val = FindVisibleTarget();
				if ((Object)(object)val != (Object)null)
				{
					BeginPursuit(val);
				}
			}
			if ((Object)(object)currentPursuitTarget != (Object)null)
			{
				ChaseCurrentTarget();
			}
			else
			{
				WanderInsideFactory(forceDecision);
			}
		}

		private void BeginPursuit(PlayerControllerB player)
		{
			currentPursuitTarget = player;
			base.targetPlayer = player;
			base.movingTowardsTargetPlayer = true;
			((EnemyAI)this).SetMovingTowardsTargetPlayer(player);
			ConfigureAgentForMovement(3.2f);
			nextChasePathRefreshAt = 0f;
			PingoEnemyPlugin.Log.LogInfo((object)$"Pingo started chasing player {player.playerClientId}.");
		}

		private void ChaseCurrentTarget()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)currentPursuitTarget == (Object)null || (Object)(object)base.agent == (Object)null)
			{
				return;
			}
			ConfigureAgentForMovement(3.2f);
			if (!(Time.time < nextChasePathRefreshAt))
			{
				nextChasePathRefreshAt = Time.time + 0.2f;
				if (Vector3.Distance(((Component)this).transform.position, ((Component)currentPursuitTarget).transform.position) > 70f)
				{
					ClearPursuitTarget("target too far away");
				}
				else if (!((EnemyAI)this).SetDestinationToPosition(((Component)currentPursuitTarget).transform.position, true))
				{
					ClearPursuitTarget("no valid path to target");
				}
			}
		}

		private void FinishPursuitCycle()
		{
			if ((Object)(object)currentPursuitTarget != (Object)null)
			{
				targetCooldownUntil[currentPursuitTarget.playerClientId] = Time.time + 30f;
				PingoEnemyPlugin.Log.LogInfo((object)$"Pingo finished chase cycle for player {currentPursuitTarget.playerClientId}; cooldown={30f:0}s.");
			}
			ClearPursuitTarget("sound loop reset");
			nextTargetScanAt = Time.time;
			nextWanderRefreshAt = Time.time;
		}

		private void StartExplosionWarning()
		{
			if (!explosionCharging)
			{
				explosionCharging = true;
				explosionAt = Time.time + 1f;
				if (((NetworkBehaviour)this).IsServer)
				{
					StopForExplosionWarning();
				}
				PingoEnemyPlugin.Log.LogInfo((object)$"Pingo reached maximum sound accumulation; exploding in {1f:0.0}s.");
			}
		}

		private void StopForExplosionWarning()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null))
			{
				base.agent.ResetPath();
				base.agent.velocity = Vector3.zero;
				base.agent.isStopped = true;
			}
		}

		private void DetonatePingoExplosion()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if (explosionCharging)
			{
				explosionCharging = false;
				Landmine.SpawnExplosion(((Component)this).transform.position, true, 3f, 3f, 200, 0f, (GameObject)null, false);
				if (((NetworkBehaviour)this).IsServer)
				{
					DamagePlayersInExplosionRadius();
					FinishPursuitCycle();
				}
				ResetSoundRampCycle();
				ConfigureAgentForMovement(1.6f);
				PingoEnemyPlugin.Log.LogInfo((object)$"Pingo exploded. killRadius={3f:0.0}; position={((Component)this).transform.position}.");
			}
		}

		private void DamagePlayersInExplosionRadius()
		{
			//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_007c: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead)
				{
					float num = Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position);
					if (!(num > 3f))
					{
						Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
						Vector3 val3 = ((Vector3)(ref val2)).normalized * 20f + Vector3.up * 8f;
						val.DamagePlayer(200, true, true, (CauseOfDeath)3, 0, false, val3);
						PingoEnemyPlugin.Log.LogInfo((object)$"Pingo explosion damaged player {val.playerClientId}; distance={num:0.00}.");
					}
				}
			}
		}

		private void ResetSoundRampCycle()
		{
			aliveForSeconds = 0f;
			nearPlayerSeconds = 0f;
			accumulatedIntervalReduction = 0f;
			minimumIntervalPlayCount = 0;
			nextNoiseAt = Time.time + 16f;
		}

		private void ClearPursuitTarget(string reason)
		{
			if ((Object)(object)currentPursuitTarget != (Object)null)
			{
				PingoEnemyPlugin.Log.LogInfo((object)$"Pingo stopped chasing player {currentPursuitTarget.playerClientId}: {reason}.");
			}
			currentPursuitTarget = null;
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			ConfigureAgentForMovement(1.6f);
		}

		private PlayerControllerB? FindVisibleTarget()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return null;
			}
			PlayerControllerB result = null;
			float num = float.MaxValue;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (IsValidTarget(val, requireVisible: true))
				{
					float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private bool IsValidTarget(PlayerControllerB? player, bool requireVisible)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !player.isPlayerControlled || player.isPlayerDead || !player.isInsideFactory || player.isInHangarShipRoom)
			{
				return false;
			}
			if (targetCooldownUntil.TryGetValue(player.playerClientId, out var value) && Time.time < value)
			{
				return false;
			}
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position);
			if (num > 70f || (requireVisible && num > 45f))
			{
				return false;
			}
			if (requireVisible)
			{
				return CanSeePlayer(player, num);
			}
			return true;
		}

		private bool CanSeePlayer(PlayerControllerB player, float distance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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)
			Vector3 val = ((Component)this).transform.position + Vector3.up * 1.35f;
			Vector3 val2 = ((Component)player).transform.position + Vector3.up * 1.2f;
			Vector3 val3 = val2 - val;
			if (distance > 1f && Vector3.Dot(((Component)this).transform.forward, ((Vector3)(ref val3)).normalized) < 0.15f)
			{
				return false;
			}
			int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-1));
			return !Physics.Linecast(val, val2, num, (QueryTriggerInteraction)1);
		}

		private void WanderInsideFactory(bool forceDecision)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null) && (forceDecision || !(Time.time < nextWanderRefreshAt) || !base.agent.hasPath || !(base.agent.remainingDistance > 1.5f)))
			{
				ConfigureAgentForMovement(1.6f);
				nextWanderRefreshAt = Time.time + 4f;
				Vector3? val = ChooseWanderDestination();
				if (val.HasValue)
				{
					((EnemyAI)this).SetDestinationToPosition(val.Value, true);
				}
			}
		}

		private void EnsureAgentOnInteriorNavMesh()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null) && !base.agent.isOnNavMesh)
			{
				Vector3? val = ChooseWanderDestination();
				NavMeshHit val2 = default(NavMeshHit);
				if (val.HasValue && NavMesh.SamplePosition(val.Value, ref val2, 12f, -1))
				{
					base.agent.Warp(((NavMeshHit)(ref val2)).position);
					((Component)this).transform.position = ((NavMeshHit)(ref val2)).position;
					PingoEnemyPlugin.Log.LogInfo((object)$"Warped Pingo onto interior NavMesh at {((NavMeshHit)(ref val2)).position}.");
				}
			}
		}

		private Vector3? ChooseWanderDestination()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).GetAINodes();
			if (base.allAINodes == null || base.allAINodes.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < 12; i++)
			{
				GameObject val = base.allAINodes[Random.Range(0, base.allAINodes.Length)];
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 position = val.transform.position;
					if (!(Vector3.Distance(((Component)this).transform.position, position) < 3f))
					{
						return position;
					}
				}
			}
			Transform val2 = ((EnemyAI)this).ChooseClosestNodeToPosition(((Component)this).transform.position, false, 0);
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return val2.position;
		}

		private void ConfigureAgentForMovement(float speed)
		{
			if (!((Object)(object)base.agent == (Object)null))
			{
				base.agent.speed = speed;
				base.agent.angularSpeed = 360f;
				base.agent.acceleration = 10f;
				base.agent.stoppingDistance = (((Object)(object)currentPursuitTarget != (Object)null) ? 1.7f : 0.5f);
				base.agent.updatePosition = true;
				base.agent.updateRotation = false;
				base.agent.isStopped = false;
			}
		}

		private void RotateTowardsAttentionOrMovement()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)this).transform.position - lastPosition;
			val.y = 0f;
			lastPosition = ((Component)this).transform.position;
			visualMovementSpeed = ((Vector3)(ref val)).magnitude / Mathf.Max(Time.deltaTime, 0.001f);
			Vector3? val2 = GetAttentionDirection();
			if (!val2.HasValue && ((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				val2 = ((Vector3)(ref val)).normalized;
			}
			if (val2.HasValue)
			{
				Quaternion val3 = Quaternion.LookRotation(val2.Value, Vector3.up);
				((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val3, Time.deltaTime * 12f);
			}
		}

		private Vector3? GetAttentionDirection()
		{
			//IL_0040: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = currentPursuitTarget;
			if ((Object)(object)val == (Object)null || val.isPlayerDead || !val.isPlayerControlled)
			{
				val = FindClosestPlayerForAttention();
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
			val2.y = 0f;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
			{
				return null;
			}
			return ((Vector3)(ref val2)).normalized;
		}

		private PlayerControllerB? FindClosestPlayerForAttention()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return null;
			}
			PlayerControllerB result = null;
			float num = float.MaxValue;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead && val.isInsideFactory)
				{
					float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position);
					if (!(num2 > 45f) && !(num2 >= num))
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private void CacheLuigiBones()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			bindRotations.Clear();
			Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				bindRotations[val] = val.localRotation;
				switch (((Object)val).name)
				{
				case "L_upperarm":
					leftUpperArm = val;
					break;
				case "R_upperarm":
					rightUpperArm = val;
					break;
				case "L_forearm":
					leftForearm = val;
					break;
				case "R_forearm":
					rightForearm = val;
					break;
				case "L_thigh":
					leftThigh = val;
					break;
				case "R_thigh":
					rightThigh = val;
					break;
				case "L_calf":
					leftCalf = val;
					break;
				case "R_calf":
					rightCalf = val;
					break;
				case "L_foot":
					leftFoot = val;
					break;
				case "R_foot":
					rightFoot = val;
					break;
				case "spine00":
					spine = val;
					break;
				case "head":
					head = val;
					break;
				}
			}
			PingoEnemyPlugin.Log.LogInfo((object)$"Cached Luigi bones for procedural animation. arms={(Object)(object)leftUpperArm != (Object)null && (Object)(object)rightUpperArm != (Object)null}; legs={(Object)(object)leftThigh != (Object)null && (Object)(object)rightThigh != (Object)null}.");
		}

		private void UpdateProceduralWalkAnimation()
		{
			if (bindRotations.Count != 0)
			{
				float num = Mathf.Clamp01(visualMovementSpeed / 1.6f);
				walkCycle += Time.deltaTime * Mathf.Lerp(1.5f, 7f, num);
				ApplyProceduralPose(Mathf.Sin(walkCycle), num);
			}
		}

		private void ApplyProceduralPose(float stride, float movingAmount)
		{
			//IL_001c: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			float num = stride * 18f * movingAmount;
			SetBoneRotation(leftUpperArm, new Vector3(num, -8f, -54f));
			SetBoneRotation(rightUpperArm, new Vector3(0f - num, 8f, -54f));
			SetBoneRotation(leftForearm, new Vector3(0f, -4f, -8f));
			SetBoneRotation(rightForearm, new Vector3(0f, 4f, -8f));
			SetBoneRotation(leftThigh, new Vector3(stride * 28f * movingAmount, 0f, 0f));
			SetBoneRotation(rightThigh, new Vector3((0f - stride) * 28f * movingAmount, 0f, 0f));
			SetBoneRotation(leftCalf, new Vector3(Mathf.Max(0f, 0f - stride) * 22f * movingAmount, 0f, 0f));
			SetBoneRotation(rightCalf, new Vector3(Mathf.Max(0f, stride) * 22f * movingAmount, 0f, 0f));
			SetBoneRotation(leftFoot, new Vector3(-8f * movingAmount, 0f, 0f));
			SetBoneRotation(rightFoot, new Vector3(-8f * movingAmount, 0f, 0f));
			SetBoneRotation(spine, new Vector3(0f, stride * 2f * movingAmount, 0f));
			SetBoneRotation(head, new Vector3(0f, (0f - stride) * 3f * movingAmount, 0f));
		}

		private void SetBoneRotation(Transform? bone, Vector3 eulerOffset)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bone == (Object)null) && bindRotations.TryGetValue(bone, out var value))
			{
				bone.localRotation = value * Quaternion.Euler(eulerOffset);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("StartGame")]
		private static void StartGamePostfix()
		{
			PingoEnemyPlugin.ResetForcedSpawnForNewRound();
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnShipLandedMiscEvents")]
		private static void OnShipLandedMiscEventsPostfix()
		{
			PingoEnemyPlugin.Log.LogInfo((object)"StartOfRound.OnShipLandedMiscEvents fired; checking forced Pingo spawn.");
			PingoEnemyPlugin.TryForceSpawnAfterLanding("OnShipLandedMiscEvents");
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal static class GameNetworkManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix()
		{
			PingoEnemyPlugin.TryRegisterNetworkPrefab("GameNetworkManager.Start");
		}
	}
}