using System; using System.Collections; 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 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", "1.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 = "1.0.0"; internal static ManualLogSource Log; internal static PingoEnemyPlugin Instance; internal static AssetBundle? Bundle; internal static AudioClip? PingoClip; internal static EnemyType? RegisteredEnemyType; internal static Texture2D? LuigiBodyTexture; internal static Texture2D? LuigiBodyNormalTexture; internal static Texture2D? LuigiEyeTexture; internal static Texture2D? LuigiEye1Texture; internal static Texture2D? LuigiEye2Texture; private static ConfigEntry spawnWeight; private static ConfigEntry enableDebugSpawnKey; private static ConfigEntry forceSpawnAfterLanding; private static ConfigEntry minimumVisualHeight; private static ConfigEntry forceTestSpawnInFrontOfPlayer; private static ConfigEntry forceVisibleFallbackBody; private static bool spawnedAfterLanding; private float nextDebugSpawnAllowedAt; 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; 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("Spawning", "SpawnWeight", 175, "Normal LethalLib spawn weight for Pingo. Default is roughly x5 a common enemy weight."); enableDebugSpawnKey = ((BaseUnityPlugin)this).Config.Bind("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("Testing", "ForceSpawnAfterLanding", false, "If true, the host spawns one Pingo near the local player after the ship lands."); forceTestSpawnInFrontOfPlayer = ((BaseUnityPlugin)this).Config.Bind("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("Visuals", "MinimumVisualHeight", 2.1f, "Minimum world-space height for Pingo's visible model. A player is roughly this height."); forceVisibleFallbackBody = ((BaseUnityPlugin)this).Config.Bind("Visuals", "ForceVisibleFallbackBody", false, "If true, adds a simple player-sized visible body so Pingo can never be invisible while testing."); } private static bool DebugSpawnKeyPressed() { if (Input.GetKeyDown((KeyCode)287)) { return true; } Keyboard current = Keyboard.current; if (current == null) { return false; } return ((ButtonControl)current.f6Key).wasPressedThisFrame; } 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("pingo") : null); AssetBundle? bundle2 = Bundle; LuigiBodyTexture = ((bundle2 != null) ? bundle2.LoadAsset("pc02_body") : null); AssetBundle? bundle3 = Bundle; LuigiBodyNormalTexture = ((bundle3 != null) ? bundle3.LoadAsset("pc02_body_nml") : null); AssetBundle? bundle4 = Bundle; LuigiEyeTexture = ((bundle4 != null) ? bundle4.LoadAsset("pc02_eye") : null); AssetBundle? bundle5 = Bundle; LuigiEye1Texture = ((bundle5 != null) ? bundle5.LoadAsset("Luigi_eye_1") : null); AssetBundle? bundle6 = Bundle; LuigiEye2Texture = ((bundle6 != null) ? bundle6.LoadAsset("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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00ec: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown AssetBundle? bundle = Bundle; GameObject val = ((bundle != null) ? bundle.LoadAsset("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"; EnemyType val2 = ScriptableObject.CreateInstance(); ((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()).enemyType = val2; TerminalNode val3 = ScriptableObject.CreateInstance(); val3.creatureName = "Pingo"; val3.displayText = "Pingo\n\nNo mata, no persigue y no se mueve. Solo se queda en la sala haciendo ruido con cada vez mas insistencia.\n"; val3.clearPreviousText = true; val3.maxCharactersToType = 2000; TerminalKeyword val4 = ScriptableObject.CreateInstance(); val4.word = "pingo"; val4.isVerb = false; RegisteredEnemyType = val2; Enemies.RegisterEnemy(val2, Mathf.Max(0, spawnWeight.Value), (LevelTypes)(-1), val3, val4); } internal static bool SpawnPingoNearLocalPlayer(string reason) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) 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; } Vector3 val2 = GetSafeSpawnPositionInFrontOfPlayer(val); NavMeshHit val3 = default(NavMeshHit); if (!ForceTestSpawnInFrontOfPlayer && NavMesh.SamplePosition(val2, ref val3, 8f, -1)) { val2 = ((NavMeshHit)(ref val3)).position; } else if (!ForceTestSpawnInFrontOfPlayer) { Log.LogWarning((object)$"Could not find nearby NavMesh for Pingo debug spawn; using raw position {val2}."); } float num = ((Component)val).transform.eulerAngles.y + 180f; RoundManager.Instance.SpawnEnemyGameObject(val2, num, -1, RegisteredEnemyType); Log.LogInfo((object)("Spawned Pingo near local player for " + reason + ".")); return true; } 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() == (Object)null) { prefab.AddComponent(); } ((EnemyAI)(prefab.GetComponent() ?? prefab.AddComponent())).enemyType = null; NavMeshAgent obj = prefab.GetComponent() ?? prefab.AddComponent(); obj.speed = 0f; obj.angularSpeed = 0f; obj.acceleration = 0f; obj.stoppingDistance = 0f; obj.updatePosition = false; obj.updateRotation = false; AudioSource obj2 = prefab.GetComponent() ?? prefab.AddComponent(); 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(true); GameObject val2; if ((Object)(object)val == (Object)null) { val2 = new GameObject("PingoScanNode"); val2.transform.SetParent(prefab.transform, false); val = val2.AddComponent(); } 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() ?? val2.AddComponent(); ((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 AudioSource? source; private float nextNoiseAt; private float aliveForSeconds; private float nearPlayerSeconds; private float accumulatedIntervalReduction; private int minimumIntervalPlayCount; public override void Start() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).Start(); source = ((Component)this).GetComponent(); 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; 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(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(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = obj.GetComponent(); 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(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(); StopMoving(); } public override void Update() { ((EnemyAI)this).Update(); StopMoving(); if (!((NetworkBehaviour)this).IsOwner || (Object)(object)source == (Object)null || (Object)(object)PingoEnemyPlugin.PingoClip == (Object)null) { 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; PlayPingoClientRpc(Mathf.Clamp01(1f - num / 16f), CalculateNearVolumeScale(), num, nearPlayerSeconds); if (flag) { accumulatedIntervalReduction = 0f; minimumIntervalPlayCount = 0; PingoEnemyPlugin.Log.LogInfo((object)"Pingo overlap loop played 30 times at minimum interval; resetting interval ramp."); } } public override void HitEnemy(int force = 1, PlayerControllerB? playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { } [ClientRpc] private void PlayPingoClientRpc(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(true); GameObject val2; if ((Object)(object)val == (Object)null) { val2 = new GameObject("PingoScanNode"); val2.transform.SetParent(((Component)this).transform, false); val = val2.AddComponent(); } 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() ?? val2.AddComponent(); ((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 StopMoving() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null)) { base.agent.speed = 0f; base.agent.velocity = Vector3.zero; base.agent.isStopped = true; } } } [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"); } } }