using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Voice; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("MimicMonster")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MimicMonster")] [assembly: AssemblyTitle("MimicMonster")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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; } } } public class EnemyMimic : MonoBehaviour { public enum State { Spawn, Idle, Roam, Stalk, SeekCorpse, Impersonate, Hunt, Jumpscare, Leave, Despawn, Stun } public bool debugSpawn; [Space] public State currentState; private bool stateImpulse; internal float stateTimer; [Space] public Enemy enemy; private PhotonView photonView; [Space] public SpringQuaternion horizontalRotationSpring; private Quaternion horizontalRotationTarget = Quaternion.identity; private float pitCheckTimer; private Vector3 leavePosition; [Header("Roam / Stalk")] public float roamSpeed = 3.5f; public float roamAcceleration = 8f; public float stalkSpeed = 2f; public float stalkAcceleration = 4f; public float lureHoldDistance = 8.5f; public float stalkTimeoutMax = 20f; private PlayerAvatar stalkTargetPlayer; private Vector3 stalkPoint; public float isolationWeight = 1f; public float proximityWeight = 0.6f; public float isolationDistanceCap = 30f; private float stalkTimer; [Header("SeekCorpse / Impersonate")] public float corpseDetectionRadius = 20f; public float corpseReachDistance = 1.5f; public float impersonateDuration = 2f; public Transform mimicVisualsRoot; public Transform disguiseRigParent; public GameObject disguiseRigTemplate; private GameObject disguiseRigInstance; private PlayerCosmetics disguiseCosmetics; private SkinnedMeshRenderer[] mimicRenderers; public float disguiseSwayCycle = 1.6f; public float disguiseSwayLeanDegrees = 3f; public float disguiseSwayBobMeters = 0.02f; private float disguiseSwayTime; private PlayerDeathHead corpseTarget; private static readonly HashSet ClaimedHeads = new HashSet(); [Header("Hunt")] public float huntSpeed = 4.5f; public float huntAcceleration = 10f; public float huntProximityRevealDistance = 2.5f; [Header("Voice Mimicry")] public float voiceLureMinInterval = 12f; public float voiceLureMaxInterval = 24f; private float voiceLureTimer; private PlayerAvatar huntTarget; [Header("Jumpscare")] public Transform jumpscareFaceTransform; public HurtCollider hurtCollider; private float hurtColliderTimer; public Sound soundJumpscareSting; public AudioClip[] footstepClips; public AudioClip[] heavyFootstepClips; public AudioClip[] servoClips; private AudioSource footstepSource; private float footstepTimer; private bool footstepAltServo; private Vector3 footLastPos; private bool footPosInit; private Vector3 jumpscareLockPos; private bool jumpscareLockSet; private Vector3 mimicJumpscareLockPos; private Coroutine jumpscareVictimCo; private Transform footBoneL; private Transform footBoneR; private float footPrevYL; private float footPrevYR; private bool footDescL; private bool footDescR; private float footCdL; private float footCdR; public float jumpscareAnimDuration = 1.2f; public float jumpscareWindupDuration = 1f; public string jumpscareAnimatorTrigger = "Jumpscare"; public Animator mimicAnimator; private PlayerAvatar jumpscareTarget; private bool jumpscareKillDone; private static bool loggedAnimParams; private Vector3 nativeLastPos; private bool nativeLastPosInit; private Transform jumpscareHeadBone; private static bool loggedAimBone; public bool debugForceSpawn; public float pounceRange = 7f; public float stalkDetectionRange = 22f; public static void ClearRunStatics() { ClaimedHeads.Clear(); } private void Awake() { photonView = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)mimicVisualsRoot)) { mimicRenderers = ((Component)mimicVisualsRoot).GetComponentsInChildren(true); } } private void Start() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy == (Object)null) { enemy = ((Component)this).GetComponent(); } if ((Object)(object)enemy == (Object)null) { return; } if (enemy.HasStateSpawn && (Object)(object)enemy.StateSpawn != (Object)null && enemy.StateSpawn.OnSpawn != null) { enemy.StateSpawn.OnSpawn.AddListener(new UnityAction(OnSpawn)); } if (enemy.HasHealth && (Object)(object)enemy.Health != (Object)null) { if (enemy.Health.onDeath != null) { enemy.Health.onDeath.AddListener(new UnityAction(OnDeath)); } if (enemy.Health.onHurt != null) { enemy.Health.onHurt.AddListener(new UnityAction(OnHurt)); } } if (enemy.HasStateInvestigate && (Object)(object)enemy.StateInvestigate != (Object)null && enemy.StateInvestigate.onInvestigateTriggered != null) { enemy.StateInvestigate.onInvestigateTriggered.AddListener(new UnityAction(OnInvestigate)); } if (!loggedAnimParams && Object.op_Implicit((Object)(object)mimicAnimator) && (Object)(object)mimicAnimator.runtimeAnimatorController != (Object)null) { loggedAnimParams = true; StringBuilder stringBuilder = new StringBuilder("[EnemyMimic][AnimParams] native mimicAnimator params: "); AnimatorControllerParameter[] parameters = mimicAnimator.parameters; foreach (AnimatorControllerParameter val in parameters) { stringBuilder.Append(val.name).Append('(').Append(val.type) .Append(") "); } Debug.Log((object)stringBuilder.ToString(), (Object)(object)this); } if (Object.op_Implicit((Object)(object)mimicAnimator)) { mimicAnimator.cullingMode = (AnimatorCullingMode)0; } jumpscareWindupDuration = 3f; jumpscareAnimDuration = 0.6f; } private void Update() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 HurtColliderTimer(); DisguiseSwayLogic(); NativeLocomotionTick(); FootstepTick(); if (SemiFunc.IsMasterClientOrSingleplayer()) { if (enemy.IsStunned()) { UpdateState(State.Stun); } if ((int)enemy.CurrentState == 11 && !enemy.IsStunned()) { UpdateState(State.Despawn); } HorizontalRotationLogic(); VoiceLureTick(); switch (currentState) { case State.Spawn: StateSpawn(); break; case State.Idle: StateIdle(); break; case State.Roam: StateRoam(); break; case State.Stalk: StateStalk(); break; case State.SeekCorpse: StateSeekCorpse(); break; case State.Impersonate: StateImpersonate(); break; case State.Hunt: StateHunt(); break; case State.Jumpscare: StateJumpscare(); break; case State.Leave: StateLeave(); break; case State.Despawn: StateDespawn(); break; case State.Stun: StateStun(); break; } } } private void StateSpawn() { if (stateImpulse) { stateImpulse = false; stateTimer = 1f; } stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Idle); } } private void StateIdle() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = Random.Range(14f, 28f); enemy.NavMeshAgent.Warp(((Component)enemy.Rigidbody).transform.position, false); enemy.NavMeshAgent.ResetPath(); } if (SemiFunc.EnemySpawnIdlePause()) { return; } PlayerDeathHead val = TryFindCorpse(corpseDetectionRadius); if ((Object)(object)val != (Object)null) { ClaimCorpse(val); UpdateState(State.SeekCorpse); } else { if (PounceCheck()) { return; } PlayerAvatar val2 = DetectStalkTarget(); if ((Object)(object)val2 != (Object)null) { stalkTargetPlayer = val2; UpdateState(State.Stalk); return; } stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Roam); } if (SemiFunc.EnemyForceLeave(enemy)) { UpdateState(State.Leave); } } } private void StateRoam() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = 1f; bool flag = false; LevelPoint val = null; float num = -1f; for (int i = 0; i < 6; i++) { LevelPoint val2 = SemiFunc.LevelPointGet(((Component)this).transform.position, 8f, 40f); if (!Object.op_Implicit((Object)(object)val2)) { continue; } float num2 = float.MaxValue; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (!((Object)(object)item == (Object)null) && !item.isDisabled) { float num3 = Vector3.Distance(((Component)val2).transform.position, ((Component)item).transform.position); if (num3 < num2) { num2 = num3; } } } if (num2 == float.MaxValue) { num2 = 999f; } if (num2 > num) { num = num2; val = val2; } } if (!Object.op_Implicit((Object)(object)val)) { val = SemiFunc.LevelPointGet(((Component)this).transform.position, 0f, 999f); } NavMeshHit val3 = default(NavMeshHit); if (Object.op_Implicit((Object)(object)val) && NavMesh.SamplePosition(((Component)val).transform.position + Random.insideUnitSphere * 3f, ref val3, 5f, -1) && Physics.Raycast(((NavMeshHit)(ref val3)).position, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }))) { enemy.NavMeshAgent.UpdateAgent(roamSpeed, roamAcceleration); enemy.NavMeshAgent.SetDestination(((NavMeshHit)(ref val3)).position); flag = true; } if (!flag) { return; } pitCheckTimer = 0.1f; enemy.Rigidbody.notMovingTimer = 0f; } else { PlayerDeathHead val4 = TryFindCorpse(corpseDetectionRadius); if ((Object)(object)val4 != (Object)null) { ClaimCorpse(val4); UpdateState(State.SeekCorpse); return; } if (enemy.Rigidbody.notMovingTimer > 1f) { stateTimer -= Time.deltaTime; } if (PitCheckLogic()) { enemy.NavMeshAgent.ResetPath(); } if (stateTimer <= 0f || !enemy.NavMeshAgent.HasPath()) { UpdateState(State.Idle); } } if (SemiFunc.EnemyForceLeave(enemy)) { UpdateState(State.Leave); } } private void StateStalk() { //IL_0129: 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_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: 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) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = 1f; stalkTimer = stalkTimeoutMax; enemy.NavMeshAgent.UpdateAgent(stalkSpeed, stalkAcceleration); pitCheckTimer = 0.1f; enemy.Rigidbody.notMovingTimer = 0f; voiceLureTimer = Random.Range(2.5f, 4.5f); } if (PounceCheck()) { return; } if (!Object.op_Implicit((Object)(object)stalkTargetPlayer) || stalkTargetPlayer.isDisabled) { PlayerDeathHead val = TryFindCorpse(corpseDetectionRadius); if ((Object)(object)val != (Object)null) { ClaimCorpse(val); UpdateState(State.SeekCorpse); } else { UpdateState(State.Roam); } return; } PlayerDeathHead val2 = TryFindCorpse(corpseDetectionRadius); if ((Object)(object)val2 != (Object)null) { ClaimCorpse(val2); UpdateState(State.SeekCorpse); return; } stalkTimer -= Time.deltaTime; if (stalkTimer <= 0f) { UpdateState(State.Roam); return; } if (SemiFunc.PerSecond(1f, (Object)(object)this)) { if (Vector3.Distance(((Component)this).transform.position, ((Component)stalkTargetPlayer).transform.position) <= stalkDetectionRange && IsIsolated(stalkTargetPlayer)) { stalkTimer = stalkTimeoutMax; } Vector3 destination; if (enemy.HasOnScreen && enemy.OnScreen.OnScreenAny) { LevelPoint val3 = SemiFunc.LevelPointGetPlayerDistance(((Component)this).transform.position, 8f, 20f, false); destination = (Object.op_Implicit((Object)(object)val3) ? ((Component)val3).transform.position : ((Component)stalkTargetPlayer).transform.position); } else { Vector3 position = ((Component)stalkTargetPlayer).transform.position; Vector3 val4 = ((Component)this).transform.position - position; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude < 0.01f) { val4 = ((Component)this).transform.forward; } destination = position + ((Vector3)(ref val4)).normalized * lureHoldDistance; } enemy.NavMeshAgent.SetDestination(destination); } if (enemy.Rigidbody.notMovingTimer > 1f) { stateTimer -= Time.deltaTime; } PitCheckLogic(); if (SemiFunc.EnemyForceLeave(enemy)) { UpdateState(State.Leave); } } private void StateSeekCorpse() { //IL_009f: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = 8f; if ((Object)(object)corpseTarget == (Object)null) { corpseTarget = TryFindCorpse(corpseDetectionRadius); if ((Object)(object)corpseTarget != (Object)null) { ClaimCorpse(corpseTarget); } } if ((Object)(object)corpseTarget == (Object)null) { UpdateState(State.Idle); return; } enemy.NavMeshAgent.UpdateAgent(huntSpeed, huntAcceleration); enemy.NavMeshAgent.SetDestination(((Component)corpseTarget).transform.position); pitCheckTimer = 0.1f; enemy.Rigidbody.notMovingTimer = 0f; return; } if ((Object)(object)corpseTarget == (Object)null || !corpseTarget.triggered || corpseTarget.overrideSpectated) { ReleaseCorpseClaim(); UpdateState(State.Idle); return; } if (SemiFunc.PerSecond(2f, (Object)(object)this)) { enemy.NavMeshAgent.SetDestination(((Component)corpseTarget).transform.position); } if (enemy.Rigidbody.notMovingTimer > 1f) { stateTimer -= Time.deltaTime; } if (PitCheckLogic()) { enemy.NavMeshAgent.ResetPath(); } if (Vector3.Distance(((Component)this).transform.position, ((Component)corpseTarget).transform.position) <= corpseReachDistance) { UpdateState(State.Impersonate); } else if (stateTimer <= 0f || !enemy.NavMeshAgent.HasPath()) { ReleaseCorpseClaim(); UpdateState(State.Idle); } } private void StateImpersonate() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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) if (stateImpulse) { stateImpulse = false; stateTimer = impersonateDuration; enemy.NavMeshAgent.Warp(((Component)enemy.Rigidbody).transform.position, false); enemy.NavMeshAgent.ResetPath(); if ((Object)(object)corpseTarget == (Object)null || (Object)(object)corpseTarget.playerAvatar == (Object)null || (Object)(object)corpseTarget.playerCosmetics == (Object)null) { ReleaseCorpseClaim(); UpdateState(State.Idle); return; } List cosmeticEquippedRaw = corpseTarget.playerCosmetics.cosmeticEquippedRaw; int[] colorsEquipped = corpseTarget.playerCosmetics.colorsEquipped; if (SemiFunc.IsMultiplayer()) { photonView.RPC("ImpersonateRPC", (RpcTarget)0, new object[2] { cosmeticEquippedRaw.ToArray(), colorsEquipped }); } else { ImpersonateRPC(cosmeticEquippedRaw.ToArray(), colorsEquipped); } } else { stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Hunt); } } } [PunRPC] private void ImpersonateRPC(int[] cosmeticIds, int[] colorIds, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info)) { if (Object.op_Implicit((Object)(object)mimicVisualsRoot)) { ((Component)mimicVisualsRoot).gameObject.SetActive(false); } SetupDisguiseRig(new List(cosmeticIds), colorIds); } } private void SetupDisguiseRig(List cosmeticIds, int[] colorIds) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)disguiseRigParent != (Object)null) ? disguiseRigParent : (((Object)(object)mimicVisualsRoot != (Object)null && (Object)(object)mimicVisualsRoot.parent != (Object)null) ? mimicVisualsRoot.parent : ((Component)this).transform)); GameObject val2 = disguiseRigTemplate; if ((Object)(object)val2 == (Object)null) { val2 = FindLiveAvatarVisualsRig(); } if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)null) { Debug.LogWarning((object)"EnemyMimic: no disguise rig template and no live player rig to clone - Impersonate cannot build a disguise.", (Object)(object)this); return; } try { if (!Object.op_Implicit((Object)(object)disguiseRigInstance)) { disguiseRigParent = val; ((Component)disguiseRigParent).gameObject.SetActive(false); disguiseRigInstance = Object.Instantiate(val2, disguiseRigParent); disguiseRigInstance.transform.localPosition = Vector3.zero; disguiseRigInstance.transform.localRotation = Quaternion.identity; PhotonView[] componentsInChildren = disguiseRigInstance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } PlayerNameChecker[] componentsInChildren2 = disguiseRigInstance.GetComponentsInChildren(true); foreach (PlayerNameChecker val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null) { Object.Destroy((Object)(object)val3); } } PlayerAvatarVisuals[] componentsInChildren3 = disguiseRigInstance.GetComponentsInChildren(true); foreach (PlayerAvatarVisuals val4 in componentsInChildren3) { if ((Object)(object)val4 != (Object)null) { ((Behaviour)val4).enabled = false; val4.playerAvatar = null; } } disguiseCosmetics = disguiseRigInstance.GetComponentInChildren(true); if ((Object)(object)disguiseCosmetics != (Object)null) { disguiseCosmetics.firstSetup = false; } ((Component)disguiseRigParent).gameObject.SetActive(true); if ((Object)(object)disguiseRigInstance.GetComponent() == (Object)null) { disguiseRigInstance.AddComponent(); } } if (!Object.op_Implicit((Object)(object)disguiseCosmetics)) { Debug.LogError((object)"EnemyMimic: disguiseRigTemplate has no PlayerCosmetics component anywhere in its hierarchy - cannot apply corpse identity.", (Object)(object)this); return; } if (disguiseCosmetics.cosmeticParents == null || disguiseCosmetics.cosmeticParents.Count == 0) { Debug.LogError((object)"EnemyMimic: disguiseRigTemplate's PlayerCosmetics.cosmeticParents is empty - SetupCosmetics will NRE inside InstantiateCosmetic() (confirmed failure mode, DECISIONS.md 21:5x). Wire cosmeticParents on the template prefab in the Editor before Impersonate can work.", (Object)(object)this); return; } disguiseCosmetics.SetupCosmetics(false, true, cosmeticIds); disguiseCosmetics.SetupColors(false, colorIds); Renderer[] componentsInChildren4 = disguiseRigInstance.GetComponentsInChildren(true); foreach (Renderer val5 in componentsInChildren4) { if (!((Object)(object)val5 == (Object)null)) { val5.shadowCastingMode = (ShadowCastingMode)1; val5.forceRenderingOff = false; } } if (Object.op_Implicit((Object)(object)disguiseRigInstance)) { disguiseRigInstance.SetActive(true); } } catch (Exception ex) { Debug.LogError((object)("EnemyMimic: disguise rig setup threw (cloned-rig detached-state?) - disguise skipped this attempt: " + ex)); } } private GameObject FindLiveAvatarVisualsRig() { PlayerAvatar[] array = Object.FindObjectsOfType(); foreach (PlayerAvatar val in array) { if (!((Object)(object)val == (Object)null)) { PlayerCosmetics componentInChildren = ((Component)val).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.cosmeticParents != null && componentInChildren.cosmeticParents.Count > 0 && (Object)(object)componentInChildren.playerAvatarVisuals != (Object)null) { return ((Component)componentInChildren.playerAvatarVisuals).gameObject; } } } return null; } public void DebugForceVoiceLure() { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.photonView == (Object)null) { Debug.LogError((object)"[EnemyMimic] DebugForceVoiceLure: no local PlayerAvatar."); return; } int num = 0; foreach (MimicVoiceCapture item in MimicVoiceCapture.All) { if ((Object)(object)item != (Object)null && item.IsLocalOwned) { num = item.SnippetCount + item.ChatLineCount; break; } } Debug.Log((object)$"[EnemyMimic] DebugForceVoiceLure: local='{((Object)instance).name}' has {num} captured snippet(s)/chat-line(s). Requesting playback from Mimic view {photonView.ViewID}. If 0, talk into your mic (or send a TTS-chat line) first, then press again."); if (num == 0) { foreach (MimicVoiceCapture item2 in MimicVoiceCapture.All) { if ((Object)(object)item2 != (Object)null && item2.IsLocalOwned) { item2.InjectDebugSnippet(); break; } } Debug.Log((object)"[EnemyMimic] DebugForceVoiceLure: no real captured voice -> injected a synthetic test snippet so the Mimic-body playback can be verified without a mic."); } int viewID = photonView.ViewID; int viewID2 = instance.photonView.ViewID; MimicVoicePlayback.SoloFallbackMimic = ((Component)this).gameObject; if (SemiFunc.IsMultiplayer()) { photonView.RPC("VoiceLureRequestRPC", (RpcTarget)0, new object[2] { viewID2, viewID }); } else { VoiceLureRequestRPC(viewID2, viewID); } } public void DebugForceTTSLure() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.photonView == (Object)null) { Debug.LogError((object)"[EnemyMimic] DebugForceTTSLure: no local PlayerAvatar."); return; } foreach (MimicVoiceCapture item in MimicVoiceCapture.All) { if ((Object)(object)item != (Object)null && item.IsLocalOwned) { item.InjectDebugChatLine(); break; } } int viewID = photonView.ViewID; int viewID2 = instance.photonView.ViewID; MimicVoicePlayback.SoloFallbackMimic = ((Component)this).gameObject; Debug.Log((object)$"[EnemyMimic] DebugForceTTSLure: forcing a TTS-chat fallback lure from Mimic view {viewID}."); if (SemiFunc.IsMultiplayer()) { photonView.RPC("VoiceLureRequestRPC", (RpcTarget)0, new object[2] { viewID2, viewID }); } else { VoiceLureRequestRPC(viewID2, viewID); } } public void DebugForceImpersonate(PlayerAvatar targetPlayer) { if ((Object)(object)targetPlayer == (Object)null || (Object)(object)targetPlayer.playerCosmetics == (Object)null) { Debug.LogError((object)"EnemyMimic.DebugForceImpersonate: targetPlayer or its playerCosmetics is null - cannot force a disguise.", (Object)(object)this); return; } List cosmeticEquippedRaw = targetPlayer.playerCosmetics.cosmeticEquippedRaw; int[] colorsEquipped = targetPlayer.playerCosmetics.colorsEquipped; if (Object.op_Implicit((Object)(object)mimicVisualsRoot)) { ((Component)mimicVisualsRoot).gameObject.SetActive(false); } SetupDisguiseRig(cosmeticEquippedRaw, colorsEquipped); currentState = State.Impersonate; stateImpulse = false; stateTimer = impersonateDuration; string text = "(no animator)"; if (Object.op_Implicit((Object)(object)mimicAnimator)) { AnimatorClipInfo[] currentAnimatorClipInfo = mimicAnimator.GetCurrentAnimatorClipInfo(0); text = ((currentAnimatorClipInfo.Length != 0 && (Object)(object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip != (Object)null) ? ((Object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip).name : "(no clip)"); } int num = (((Object)(object)disguiseCosmetics != (Object)null && disguiseCosmetics.cosmeticEquipped != null) ? disguiseCosmetics.cosmeticEquipped.Count : 0); Debug.Log((object)$"[EnemyMimic][DebugForceImpersonate] target='{((Object)targetPlayer).name}' rigInstantiated={(Object)(object)disguiseRigInstance != (Object)null} cosmeticsComponentPresent={(Object)(object)disguiseCosmetics != (Object)null} cosmeticIdsRead={cosmeticEquippedRaw?.Count ?? 0} cosmeticsActuallyApplied={num} animatorClip={text} nextTransition=Hunt in {impersonateDuration:F1}s (then proximity<={huntProximityRevealDistance:F1}m auto-triggers Jumpscare)", (Object)(object)this); } private void StateHunt() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = 1f; huntTarget = SemiFunc.PlayerGetNearestPlayerAvatarWithinRange(999f, ((Component)this).transform.position, false, default(LayerMask)); if ((Object)(object)huntTarget == (Object)null) { UpdateState(State.Leave); return; } enemy.NavMeshAgent.UpdateAgent(huntSpeed, huntAcceleration); pitCheckTimer = 0.1f; enemy.Rigidbody.notMovingTimer = 0f; } if ((Object)(object)huntTarget == (Object)null || huntTarget.isDisabled) { huntTarget = SemiFunc.PlayerGetNearestPlayerAvatarWithinRange(999f, ((Component)this).transform.position, false, default(LayerMask)); if ((Object)(object)huntTarget == (Object)null) { UpdateState(State.Leave); return; } } enemy.NavMeshAgent.SetDestination(((Component)huntTarget).transform.position); if (enemy.Rigidbody.notMovingTimer > 1f) { stateTimer -= Time.deltaTime; } if (PitCheckLogic()) { enemy.NavMeshAgent.ResetPath(); } if (Vector3.Distance(((Component)this).transform.position, ((Component)huntTarget).transform.position) <= huntProximityRevealDistance) { jumpscareTarget = huntTarget; UpdateState(State.Jumpscare); } else if (SemiFunc.EnemyForceLeave(enemy)) { UpdateState(State.Leave); } } private void StateJumpscare() { //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024e: 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_00a2: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; stateTimer = jumpscareWindupDuration; jumpscareKillDone = false; enemy.NavMeshAgent.Warp(((Component)enemy.Rigidbody).transform.position, false); enemy.NavMeshAgent.ResetPath(); if ((Object)(object)jumpscareTarget == (Object)null || jumpscareTarget.isDisabled) { UpdateState(State.Hunt); return; } Vector3 val = ((jumpscareTarget.isLocal && Object.op_Implicit((Object)(object)Camera.main)) ? ((Component)Camera.main).transform.forward : ((Component)jumpscareTarget).transform.forward); val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = ((Component)this).transform.position - ((Component)jumpscareTarget).transform.position; } val.y = 0f; ((Vector3)(ref val)).Normalize(); Vector3 val2 = ((Component)jumpscareTarget).transform.position + val * 1.7f; NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(val2, ref val3, 2.5f, -1)) { val2 = ((NavMeshHit)(ref val3)).position; } enemy.NavMeshAgent.Warp(val2, false); ((Component)this).transform.position = val2; mimicJumpscareLockPos = val2; Vector3 val4 = ((Component)jumpscareTarget).transform.position - val2; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude > 0.001f) { horizontalRotationTarget = Quaternion.LookRotation(((Vector3)(ref val4)).normalized); ((Component)this).transform.rotation = horizontalRotationTarget; } jumpscareLockSet = false; int viewID = jumpscareTarget.photonView.ViewID; if (SemiFunc.IsMultiplayer()) { photonView.RPC("JumpscarePresentationRPC", (RpcTarget)0, new object[1] { viewID }); } else { JumpscarePresentationRPC(viewID); } return; } stateTimer -= Time.deltaTime; enemy.NavMeshAgent.ResetPath(); enemy.NavMeshAgent.Warp(mimicJumpscareLockPos, false); ((Component)this).transform.position = mimicJumpscareLockPos; if (stateTimer > 0f) { return; } if (!jumpscareKillDone) { jumpscareKillDone = true; stateTimer = jumpscareAnimDuration; if ((Object)(object)jumpscareTarget == (Object)null || jumpscareTarget.isDisabled) { UpdateState(State.Hunt); return; } int viewID2 = jumpscareTarget.photonView.ViewID; if (SemiFunc.IsMultiplayer()) { photonView.RPC("JumpscareKillRPC", (RpcTarget)0, new object[1] { viewID2 }); } else { JumpscareKillRPC(viewID2); } } else { if (Object.op_Implicit((Object)(object)hurtCollider)) { ((Component)hurtCollider).gameObject.SetActive(false); } ReleaseCorpseClaim(); corpseTarget = null; UpdateState(State.SeekCorpse); } } [PunRPC] private void JumpscarePresentationRPC(int targetViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: 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_0062: 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_020d: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.MasterOnlyRPC(info)) { return; } PlayerAvatar val = null; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (item.photonView.ViewID == targetViewId) { val = item; break; } } jumpscareTarget = val; if ((Object)(object)val == (Object)null) { return; } Vector3 jumpscareAimPoint = GetJumpscareAimPoint(); if (val.isLocal && Object.op_Implicit((Object)(object)CameraAim.Instance)) { CameraAim.Instance.AimTargetSet(jumpscareAimPoint, jumpscareWindupDuration + jumpscareAnimDuration + 0.3f, 90f, ((Component)this).gameObject, 100); CameraAim.Instance.OverrideAimStop(); if (jumpscareVictimCo != null) { ((MonoBehaviour)this).StopCoroutine(jumpscareVictimCo); } jumpscareLockSet = false; jumpscareVictimCo = ((MonoBehaviour)this).StartCoroutine(JumpscareVictimDriveCo()); } if (Object.op_Implicit((Object)(object)mimicVisualsRoot)) { ((Component)mimicVisualsRoot).gameObject.SetActive(true); } if (Object.op_Implicit((Object)(object)disguiseRigInstance)) { disguiseRigInstance.SetActive(false); } if (Object.op_Implicit((Object)(object)mimicAnimator) && !string.IsNullOrEmpty(jumpscareAnimatorTrigger)) { mimicAnimator.cullingMode = (AnimatorCullingMode)0; mimicAnimator.speed = 1f; mimicAnimator.ResetTrigger(jumpscareAnimatorTrigger); mimicAnimator.Play("Jumpscare", 0, 0f); mimicAnimator.Update(0f); mimicAnimator.SetTrigger(jumpscareAnimatorTrigger); string arg = "(none)"; AnimatorClipInfo[] currentAnimatorClipInfo = mimicAnimator.GetCurrentAnimatorClipInfo(0); if (currentAnimatorClipInfo != null && currentAnimatorClipInfo.Length != 0 && (Object)(object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip != (Object)null) { arg = ((Object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip).name; } Debug.Log((object)$"[EnemyMimic][Jumpscare] revealed native model, played Jumpscare (resulting clip='{arg}') trigger='{jumpscareAnimatorTrigger}' aimPoint={jumpscareAimPoint}", (Object)(object)this); } if (soundJumpscareSting != null) { soundJumpscareSting.Play(((Component)this).transform.position, 1f, 1f, 1f, 1f); } } private Vector3 GetJumpscareAimPoint() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)jumpscareHeadBone == (Object)null) { jumpscareHeadBone = FindDeepChild(((Object)(object)mimicVisualsRoot != (Object)null) ? mimicVisualsRoot : ((Component)this).transform, "head_jnt"); if ((Object)(object)jumpscareHeadBone == (Object)null) { jumpscareHeadBone = FindDeepChild(((Component)this).transform, "head_jnt"); } } if (!loggedAimBone) { loggedAimBone = true; Debug.Log((object)($"[EnemyMimic][AimBone] head_jnt found={(Object)(object)jumpscareHeadBone != (Object)null} " + (((Object)(object)jumpscareHeadBone != (Object)null) ? $"pos={jumpscareHeadBone.position}" : "(falling back)"))); } if (Object.op_Implicit((Object)(object)jumpscareHeadBone)) { return jumpscareHeadBone.position; } if (Object.op_Implicit((Object)(object)jumpscareFaceTransform)) { return jumpscareFaceTransform.position; } return ((Component)this).transform.position + Vector3.up * 1.7f; } private static Transform FindDeepChild(Transform root, string name) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if ((Object)(object)root == (Object)null) { return null; } if (((Object)root).name == name) { return root; } foreach (Transform item in root) { Transform val = FindDeepChild(item, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private IEnumerator JumpscareVictimDriveCo() { float t = jumpscareWindupDuration + jumpscareAnimDuration + 0.1f; while (t > 0f) { t -= Time.deltaTime; if (Object.op_Implicit((Object)(object)CameraAim.Instance)) { CameraAim.Instance.OverrideAimStop(); CameraAim.Instance.AimTargetSet(GetJumpscareAimPoint(), 0.25f, 90f, ((Component)this).gameObject, 100); } if (Object.op_Implicit((Object)(object)PlayerController.instance) && Object.op_Implicit((Object)(object)PlayerController.instance.rb)) { Rigidbody rb = PlayerController.instance.rb; if (!jumpscareLockSet) { jumpscareLockPos = rb.position; jumpscareLockSet = true; } Vector3 position = rb.position; position.x = jumpscareLockPos.x; position.z = jumpscareLockPos.z; if (Object.op_Implicit((Object)(object)jumpscareHeadBone) && Object.op_Implicit((Object)(object)jumpscareTarget) && Object.op_Implicit((Object)(object)jumpscareTarget.PlayerVisionTarget)) { float y = jumpscareTarget.PlayerVisionTarget.VisionTransform.position.y; float num = jumpscareHeadBone.position.y - y; if (num > 0.03f) { position.y += Mathf.Min(num, 2f) * 0.4f; } } rb.position = position; rb.velocity = Vector3.zero; } yield return null; } jumpscareVictimCo = null; } [PunRPC] private void JumpscareKillRPC(int targetViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ea: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.MasterOnlyRPC(info)) { return; } PlayerAvatar val = null; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (item.photonView.ViewID == targetViewId) { val = item; break; } } if (!((Object)(object)val == (Object)null)) { if (Object.op_Implicit((Object)(object)hurtCollider)) { ((Component)hurtCollider).transform.position = val.PlayerVisionTarget.VisionTransform.position; Transform transform = ((Component)hurtCollider).transform; Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized); ((Component)hurtCollider).gameObject.SetActive(true); hurtColliderTimer = jumpscareAnimDuration; Debug.Log((object)$"[EnemyMimic][JumpscareKill] hurtCollider ENABLED at {((Component)hurtCollider).transform.position} vs target '{((Object)val).name}' (playerKill collider fired; expect PlayerHurt/death this frame)", (Object)(object)this); } else { Debug.LogError((object)"[EnemyMimic][JumpscareKill] hurtCollider is NULL - prefab has no playerKill HurtCollider child, so NO KILL will land. This is the C3 gap."); } } } private void StateLeave() { //IL_0115: 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_0063: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { enemy.NavMeshAgent.Warp(((Component)enemy.Rigidbody).transform.position, false); enemy.NavMeshAgent.ResetPath(); if (!enemy.EnemyParent.playerClose) { UpdateState(State.Idle); return; } bool flag = false; LevelPoint val = SemiFunc.LevelPointGetPlayerDistance(((Component)this).transform.position, 25f, 50f, false); if (!Object.op_Implicit((Object)(object)val)) { val = SemiFunc.LevelPointGetFurthestFromPlayer(((Component)this).transform.position, 5f); } NavMeshHit val2 = default(NavMeshHit); if (Object.op_Implicit((Object)(object)val) && NavMesh.SamplePosition(((Component)val).transform.position, ref val2, 5f, -1) && Physics.Raycast(((NavMeshHit)(ref val2)).position, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }))) { leavePosition = ((NavMeshHit)(ref val2)).position; flag = true; } if (!flag) { return; } stateImpulse = false; stateTimer = 5f; } enemy.NavMeshAgent.SetDestination(leavePosition); if (enemy.Rigidbody.notMovingTimer > 2f) { stateTimer -= Time.deltaTime; } if (PitCheckLogic()) { stateImpulse = true; } else if (stateTimer <= 0f || Vector3.Distance(((Component)this).transform.position, leavePosition) < 1f) { UpdateState(State.Idle); } } private void StateDespawn() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (stateImpulse) { stateImpulse = false; enemy.NavMeshAgent.Warp(((Component)enemy.Rigidbody).transform.position, false); enemy.NavMeshAgent.ResetPath(); ReleaseCorpseClaim(); } } private void StateStun() { if (!enemy.IsStunned()) { UpdateState(State.Idle); } } public void OnSpawn() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!debugForceSpawn && SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.PlayerGetAll().Count < 2) { Debug.Log((object)"[EnemyMimic] no-solo-spawn: <2 players, despawning this natural spawn (design: no solo spawn).", (Object)(object)this); enemy.EnemyParent.Despawn(); } else if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.EnemySpawn(enemy)) { if (SemiFunc.IsMultiplayer()) { photonView.RPC("ResetVisualsRPC", (RpcTarget)0, Array.Empty()); } else { ResetVisualsRPC(); } ReleaseCorpseClaim(); UpdateState(State.Spawn); } } [PunRPC] private void ResetVisualsRPC(PhotonMessageInfo info = default(PhotonMessageInfo)) { if (Object.op_Implicit((Object)(object)mimicVisualsRoot)) { ((Component)mimicVisualsRoot).gameObject.SetActive(true); } if (Object.op_Implicit((Object)(object)disguiseRigInstance)) { Object.Destroy((Object)(object)disguiseRigInstance); disguiseRigInstance = null; disguiseCosmetics = null; } } public void OnHurt() { if (Object.op_Implicit((Object)(object)enemy) && enemy.HasHealth && (Object)(object)enemy.Health != (Object)null) { Debug.Log((object)$"[EnemyMimic][OnHurt] healthCurrent={enemy.Health.healthCurrent}/{enemy.Health.health} (damage landed - Mimic IS weapon-vulnerable)", (Object)(object)this); } if (SemiFunc.IsMasterClientOrSingleplayer() && currentState == State.Leave) { UpdateState(State.Idle); } } public void OnDeath() { if (SemiFunc.IsMasterClientOrSingleplayer()) { ReleaseCorpseClaim(); enemy.EnemyParent.Despawn(); } } public void OnInvestigate() { //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) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer() && enemy.Rigidbody.timeSinceStun > 1.5f && (currentState == State.Idle || currentState == State.Roam || currentState == State.Stalk)) { stalkPoint = enemy.StateInvestigate.onInvestigateTriggeredPosition; stalkTargetPlayer = FindPlayerNearPoint(stalkPoint); if ((Object)(object)stalkTargetPlayer != (Object)null) { UpdateState(State.Stalk); } } } private void UpdateState(State _state) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer() && _state != currentState) { Debug.Log((object)$"[EnemyMimic][State] {currentState} -> {_state} (view {photonView.ViewID}, disguised={Object.op_Implicit((Object)(object)disguiseRigInstance)})"); currentState = _state; stateImpulse = true; stateTimer = 0f; if (GameManager.Multiplayer()) { photonView.RPC("UpdateStateRPC", (RpcTarget)0, new object[1] { currentState }); } else { UpdateStateRPC(currentState); } } } [PunRPC] private void UpdateStateRPC(State _state, PhotonMessageInfo _info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(_info)) { currentState = _state; } } private void HorizontalRotationLogic() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_0111: 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 (currentState == State.Jumpscare && Object.op_Implicit((Object)(object)jumpscareTarget)) { Vector3 val = ((Component)jumpscareTarget).transform.position - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { horizontalRotationTarget = Quaternion.LookRotation(((Vector3)(ref val)).normalized); } horizontalRotationSpring.speed = 25f; horizontalRotationSpring.damping = 0.85f; } else { Vector3 val2 = Vector3.zero; if ((Object)(object)enemy.NavMeshAgent != (Object)null && (Object)(object)enemy.NavMeshAgent.Agent != (Object)null && enemy.NavMeshAgent.Agent.isOnNavMesh) { val2 = enemy.NavMeshAgent.Agent.desiredVelocity; } if (((Vector3)(ref val2)).magnitude < 0.5f && enemy.HasRigidbody) { val2 = enemy.Rigidbody.velocity; } val2.y = 0f; if (((Vector3)(ref val2)).magnitude > 0.6f) { horizontalRotationTarget = Quaternion.LookRotation(((Vector3)(ref val2)).normalized); horizontalRotationSpring.speed = ((currentState == State.Stalk) ? 4f : 6f); horizontalRotationSpring.damping = 0.7f; } } ((Component)this).transform.rotation = SemiFunc.SpringQuaternionGet(horizontalRotationSpring, horizontalRotationTarget, -1f); } private bool PitCheckLogic() { //IL_0020: 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_0052: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0089: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f1: Unknown result type (might be due to invalid IL or missing references) if (pitCheckTimer <= 0f) { Vector3 normalized = ((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized; if (((Vector3)(ref normalized)).magnitude > 0.1f) { pitCheckTimer = 0.5f; Vector3 normalized2 = ((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized; normalized2.y = 0f; bool num = Physics.Raycast(((Component)this).transform.position + normalized2 + Vector3.up * 1f, Vector3.down, 5f, LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct())); if (!num) { enemy.NavMeshAgent.Warp(((Component)this).transform.position - normalized2 * 0.5f, false); enemy.NavMeshAgent.ResetPath(); enemy.NavMeshAgent.Agent.velocity = Vector3.zero; } return !num; } } pitCheckTimer -= Time.deltaTime; return false; } private void FootstepTick() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_004b: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (footstepClips == null || footstepClips.Length == 0 || currentState == State.Jumpscare) { return; } Vector3 position = ((Component)this).transform.position; if (!footPosInit) { footLastPos = position; footPosInit = true; return; } Vector3 val = position - footLastPos; val.y = 0f; footLastPos = position; float num = Mathf.Max(Time.deltaTime, 1E-05f); float num2 = ((Vector3)(ref val)).magnitude / num; if (num2 > 20f) { return; } footCdL -= num; footCdR -= num; if (!(num2 < 0.4f)) { Transform root = (((Object)(object)mimicVisualsRoot != (Object)null) ? mimicVisualsRoot : ((Component)this).transform); if ((Object)(object)footBoneL == (Object)null) { footBoneL = FindDeepChild(root, "L_foot_jnt"); } if ((Object)(object)footBoneR == (Object)null) { footBoneR = FindDeepChild(root, "R_foot_jnt"); } ProcessFootPlant(footBoneL, ref footPrevYL, ref footDescL, ref footCdL, num2); ProcessFootPlant(footBoneR, ref footPrevYR, ref footDescR, ref footCdR, num2); } } private void ProcessFootPlant(Transform foot, ref float prevY, ref bool descending, ref float cooldown, float spd) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)foot == (Object)null) { return; } float y = foot.position.y; float num = y - prevY; prevY = y; if (num < -0.0004f) { descending = true; } else if (descending && num > 0.0004f && cooldown <= 0f) { descending = false; cooldown = 0.14f; EnsureFootstepSource(); bool flag = spd > 3.2f && heavyFootstepClips != null && heavyFootstepClips.Length != 0; AudioClip[] array = (flag ? heavyFootstepClips : footstepClips); footstepSource.PlayOneShot(array[Random.Range(0, array.Length)], flag ? 0.3f : 0.2f); if (servoClips != null && servoClips.Length != 0) { footstepSource.PlayOneShot(servoClips[Random.Range(0, servoClips.Length)], 0.15f); } } } private void EnsureFootstepSource() { if (!((Object)(object)footstepSource != (Object)null)) { footstepSource = ((Component)this).gameObject.AddComponent(); footstepSource.spatialBlend = 1f; footstepSource.minDistance = 2f; footstepSource.maxDistance = 32f; footstepSource.rolloffMode = (AudioRolloffMode)1; footstepSource.playOnAwake = false; footstepSource.dopplerLevel = 0f; } } private void NativeLocomotionTick() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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) if (!Object.op_Implicit((Object)(object)mimicAnimator) || currentState == State.Jumpscare) { return; } if (!Object.op_Implicit((Object)(object)mimicVisualsRoot) || !((Component)mimicVisualsRoot).gameObject.activeInHierarchy) { nativeLastPosInit = false; return; } Vector3 position = ((Component)this).transform.position; if (!nativeLastPosInit) { nativeLastPos = position; nativeLastPosInit = true; return; } Vector3 val = position - nativeLastPos; val.y = 0f; nativeLastPos = position; float num = Mathf.Max(Time.deltaTime, 1E-05f); float num2 = ((Vector3)(ref val)).magnitude / num; if (!(num2 > 20f)) { mimicAnimator.SetFloat("Speed", num2, 0.3f, num); if (Object.op_Implicit((Object)(object)enemy)) { mimicAnimator.SetBool("Stunned", enemy.IsStunned()); } } } private void DisguiseSwayLogic() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)disguiseRigInstance) && disguiseRigInstance.activeInHierarchy) { disguiseSwayTime += Time.deltaTime; float num = disguiseSwayTime / disguiseSwayCycle * (MathF.PI * 2f); float num2 = Mathf.Sin(num) * disguiseSwayLeanDegrees; float num3 = Mathf.Abs(Mathf.Sin(num)) * disguiseSwayBobMeters; disguiseRigInstance.transform.localRotation = Quaternion.Euler(0f, 0f, num2); disguiseRigInstance.transform.localPosition = new Vector3(0f, num3, 0f); } } private void HurtColliderTimer() { if (hurtColliderTimer > 0f) { hurtColliderTimer -= Time.deltaTime; if (hurtColliderTimer <= 0f && Object.op_Implicit((Object)(object)hurtCollider)) { ((Component)hurtCollider).gameObject.SetActive(false); } } } private PlayerDeathHead TryFindCorpse(float maxDistance) { //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) PlayerDeathHead result = null; float num = maxDistance; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (!item.isDisabled) { continue; } PlayerDeathHead playerDeathHead = item.playerDeathHead; if (Object.op_Implicit((Object)(object)playerDeathHead) && playerDeathHead.triggered && !playerDeathHead.overrideSpectated && !ClaimedHeads.Contains(playerDeathHead)) { float num2 = Vector3.Distance(((Component)enemy.Rigidbody).transform.position, ((Component)playerDeathHead).transform.position); if (num2 < num) { num = num2; result = playerDeathHead; } } } return result; } private void ClaimCorpse(PlayerDeathHead head) { corpseTarget = head; ClaimedHeads.Add(head); } private void ReleaseCorpseClaim() { if ((Object)(object)corpseTarget != (Object)null) { ClaimedHeads.Remove(corpseTarget); } corpseTarget = null; } private PlayerAvatar FindPlayerNearPoint(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(point, 1.5f, LayerMask.GetMask(new string[1] { "Player" }) + LayerMask.GetMask(new string[1] { "PhysGrabObject" })); foreach (Collider val in array) { if (((Component)val).CompareTag("Player")) { PlayerController componentInParent = ((Component)val).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent)) { return componentInParent.playerAvatarScript; } PlayerAvatar componentInParent2 = ((Component)val).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent2)) { return componentInParent2; } } else { PlayerTumble componentInParent3 = ((Component)val).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent3)) { return componentInParent3.playerAvatar; } } } return null; } private PlayerAvatar SelectBestLureTarget() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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) List list = SemiFunc.PlayerGetList(); PlayerAvatar result = null; float num = float.MinValue; foreach (PlayerAvatar item in list) { if ((Object)(object)item == (Object)null || item.isDisabled) { continue; } float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position); float num3 = float.MaxValue; foreach (PlayerAvatar item2 in list) { if (!((Object)(object)item2 == (Object)null) && !((Object)(object)item2 == (Object)(object)item) && !item2.isDisabled) { float num4 = Vector3.Distance(((Component)item).transform.position, ((Component)item2).transform.position); if (num4 < num3) { num3 = num4; } } } if (num3 == float.MaxValue) { num3 = isolationDistanceCap; } float num5 = Mathf.Min(num3, isolationDistanceCap); float num6 = 0f - num2; float num7 = isolationWeight * num5 + proximityWeight * num6; if (num7 > num) { num = num7; result = item; } } return result; } private PlayerAvatar DetectStalkTarget() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar val = SelectBestLureTarget(); if ((Object)(object)val == (Object)null) { return null; } if (Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > stalkDetectionRange) { return null; } if (!IsIsolated(val)) { return null; } return val; } private bool PounceCheck() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar val = SelectBestLureTarget(); if ((Object)(object)val == (Object)null) { return false; } if (Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > pounceRange) { return false; } if (!IsIsolated(val)) { return false; } huntTarget = val; UpdateState(State.Hunt); return true; } private bool IsIsolated(PlayerAvatar p) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null) { return false; } float num = float.MaxValue; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)p) && !item.isDisabled) { float num2 = Vector3.Distance(((Component)p).transform.position, ((Component)item).transform.position); if (num2 < num) { num = num2; } } } return num > isolationDistanceCap * 0.5f; } private void VoiceLureTick() { //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) if (voiceLureTimer > 0f) { voiceLureTimer -= Time.deltaTime; return; } voiceLureTimer = Random.Range(voiceLureMinInterval, voiceLureMaxInterval); PlayerAvatar val = null; val = ((currentState == State.Impersonate && (Object)(object)corpseTarget != (Object)null && (Object)(object)corpseTarget.playerAvatar != (Object)null) ? corpseTarget.playerAvatar : ((currentState == State.Hunt && (Object)(object)huntTarget != (Object)null) ? huntTarget : ((currentState != State.Stalk || !((Object)(object)stalkTargetPlayer != (Object)null)) ? SelectBestLureTarget() : stalkTargetPlayer))); if ((Object)(object)val == (Object)null || (Object)(object)val.photonView == (Object)null) { return; } if (debugForceSpawn && !MimicVoiceCapture.VoiceViablePlayers.Contains(val.photonView.ViewID)) { foreach (MimicVoiceCapture item in MimicVoiceCapture.All) { if ((Object)(object)item != (Object)null && item.IsLocalOwned && (Object)(object)item.PlayerAvatarRef == (Object)(object)val) { item.InjectDebugSnippet(); break; } } } if (currentState != State.Impersonate && currentState != State.Hunt && !MimicVoiceCapture.VoiceViablePlayers.Contains(val.photonView.ViewID)) { PlayerAvatar val2 = null; foreach (PlayerAvatar item2 in SemiFunc.PlayerGetList()) { if (!((Object)(object)item2 == (Object)null) && !item2.isDisabled && !((Object)(object)item2.photonView == (Object)null) && MimicVoiceCapture.VoiceViablePlayers.Contains(item2.photonView.ViewID)) { val2 = item2; break; } } if ((Object)(object)val2 == (Object)null) { return; } val = val2; } int viewID = photonView.ViewID; int viewID2 = val.photonView.ViewID; MimicVoicePlayback.SoloFallbackMimic = ((Component)this).gameObject; if (SemiFunc.IsMultiplayer()) { photonView.RPC("VoiceLureRequestRPC", (RpcTarget)0, new object[2] { viewID2, viewID }); } else { VoiceLureRequestRPC(viewID2, viewID); } } [PunRPC] private void VoiceLureRequestRPC(int playerViewId, int enemyViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info)) { MimicVoiceCapture.RequestCaptureForMimic(playerViewId, enemyViewId); } } } public class MimicDisguiseAnimDriver : MonoBehaviour { private Animator anim; private Vector3 lastPos; private bool moving; private bool sprinting; private static readonly string[] ClearBools = new string[10] { "Crouching", "Crawling", "Grabbing", "Jumping", "Falling", "Sliding", "Tumbling", "TumblingMove", "Turning", "Sprinting" }; private void OnEnable() { //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) anim = ((Component)this).GetComponent(); if ((Object)(object)anim == (Object)null) { anim = ((Component)this).GetComponentInChildren(true); } if ((Object)(object)anim == (Object)null) { ((Behaviour)this).enabled = false; return; } anim.cullingMode = (AnimatorCullingMode)0; anim.speed = 1f; anim.Rebind(); anim.Update(0f); string[] clearBools = ClearBools; foreach (string text in clearBools) { anim.SetBool(text, false); } moving = false; sprinting = false; lastPos = ((Component)this).transform.position; } private void Update() { //IL_0015: 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_0020: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)anim == (Object)null) { return; } Vector3 val = ((Component)this).transform.position - lastPos; val.y = 0f; lastPos = ((Component)this).transform.position; float num = Mathf.Max(Time.deltaTime, 1E-05f); float num2 = ((Vector3)(ref val)).magnitude / num; if (num2 > 20f) { return; } if (moving) { if (num2 < 0.15f) { moving = false; } } else if (num2 > 0.35f) { moving = true; } anim.SetBool("Moving", moving); bool flag = moving && num2 > 4f; if (flag && !sprinting) { anim.SetTrigger("SprintingImpulse"); } if (!flag && sprinting) { anim.ResetTrigger("SprintingImpulse"); } sprinting = flag; anim.SetBool("Sprinting", flag); } } public class MimicVoiceCapture : MonoBehaviour { private PlayerAvatar playerAvatar; private PhotonView view; private const int SampleRate = 48000; private const float SnippetSeconds = 2.5f; private const int MaxSnippets = 6; private float[] captureBuffer; private int capturePos; private bool capturing; private readonly List snippets = new List(); private float recaptureCooldown; private readonly List rxChunks = new List(); private int rxExpected; private int rxEnemyViewId; internal static readonly List All = new List(); private const int MaxChatLines = 6; private readonly List chatLines = new List(); internal static readonly HashSet VoiceViablePlayers = new HashSet(); private bool reportedViable; internal bool IsLocalOwned { get { if ((Object)(object)view != (Object)null) { if (SemiFunc.IsMultiplayer()) { return view.IsMine; } return true; } return false; } } internal int SnippetCount => snippets.Count; internal PlayerAvatar PlayerAvatarRef => playerAvatar; internal int ChatLineCount => chatLines.Count; private void Awake() { playerAvatar = ((Component)this).GetComponent(); view = ((Component)this).GetComponent(); All.Add(this); } internal static void RequestCaptureForMimic(int playerViewId, int enemyViewId) { foreach (MimicVoiceCapture item in All) { if ((Object)(object)item != (Object)null && (Object)(object)item.view != (Object)null && item.view.ViewID == playerViewId) { item.BroadcastRandomSnippet(enemyViewId); return; } } Debug.LogWarning((object)$"[MimicVoice] No capture instance found for player view {playerViewId}."); } private void OnDestroy() { All.Remove(this); } private void Update() { if (recaptureCooldown > 0f) { recaptureCooldown -= Time.deltaTime; } } internal void InjectDebugSnippet() { int num = 96000; float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / 48000f; float num3 = 180f + 40f * Mathf.Sin(num2 * 6f); array[i] = 0.45f * (Mathf.Sin(MathF.PI * 2f * num3 * num2) + 0.4f * Mathf.Sin(MathF.PI * 2f * num3 * 2f * num2)) * (0.6f + 0.4f * Mathf.Sin(num2 * 10f)); } if (snippets.Count >= 6) { snippets.RemoveAt(0); } snippets.Add(array); ReportViable(); Debug.Log((object)"[MimicVoice] DEBUG: injected a synthetic 2s voice snippet (no mic needed) - press the lure to hear it from the Mimic's body."); } internal void InjectDebugChatLine() { snippets.Clear(); CaptureChatLine("hey, I found a bunch of loot back here - come help me carry it"); Debug.Log((object)"[MimicVoice] DEBUG: seeded a synthetic TTS-chat line + cleared the voice ring - press the lure to hear the Mimic SPEAK it (TTS fallback rung)."); } internal void CaptureChatLine(string text) { if (!string.IsNullOrWhiteSpace(text)) { if (chatLines.Count >= 6) { chatLines.RemoveAt(0); } chatLines.Add(text); Debug.Log((object)string.Format("[MimicVoice] captured TTS-chat line #{0} of local player (\"{1}\").", chatLines.Count, (text.Length > 40) ? (text.Substring(0, 40) + "...") : text)); ReportViable(); } } private void ReportViable() { if (!reportedViable && !((Object)(object)view == (Object)null) && (snippets.Count != 0 || chatLines.Count != 0)) { reportedViable = true; int viewID = view.ViewID; VoiceViablePlayers.Add(viewID); if (SemiFunc.IsMultiplayer()) { view.RPC("VoiceViableRPC", (RpcTarget)0, new object[1] { viewID }); } } } [PunRPC] private void VoiceViableRPC(int playerViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { VoiceViablePlayers.Add(playerViewId); } internal void ProcessVoiceData(short[] voiceData) { if (!IsLocalOwned || (Object)(object)playerAvatar == (Object)null || (Object)(object)playerAvatar.voiceChat == (Object)null) { return; } if (playerAvatar.voiceChat.isTalking && !capturing && recaptureCooldown <= 0f) { capturing = true; captureBuffer = new float[120000]; capturePos = 0; } if (!capturing) { return; } int num = Mathf.Min(voiceData.Length, captureBuffer.Length - capturePos); for (int i = 0; i < num; i++) { captureBuffer[capturePos + i] = (float)voiceData[i] / 32768f; } capturePos += num; if (capturePos >= captureBuffer.Length) { capturing = false; recaptureCooldown = 8f; if (snippets.Count >= 6) { snippets.RemoveAt(0); } snippets.Add(captureBuffer); captureBuffer = null; Debug.Log((object)$"[MimicVoice] captured snippet #{snippets.Count} of local player voice ({2.5f:F1}s)."); ReportViable(); } } internal void BroadcastRandomSnippet(int enemyViewId) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (snippets.Count == 0) { if (chatLines.Count > 0) { BroadcastRandomChatLine(enemyViewId); } else { Debug.Log((object)"[MimicVoice] lure requested for this player but no mic snippets OR TTS-chat lines captured yet (normal in solo / before anyone talks or types)."); } return; } float[] array = snippets[Random.Range(0, snippets.Count)]; byte[] array2 = new byte[array.Length * 2]; for (int i = 0; i < array.Length; i++) { short num = (short)(Mathf.Clamp(array[i], -1f, 1f) * 32767f); array2[i * 2] = (byte)(num & 0xFF); array2[i * 2 + 1] = (byte)((num >> 8) & 0xFF); } int num2 = (array2.Length + 8192 - 1) / 8192; if (SemiFunc.IsMultiplayer()) { ((MonoBehaviour)this).StartCoroutine(SendChunksPaced(array2, num2, 8192, enemyViewId)); return; } for (int j = 0; j < num2; j++) { int num3 = Mathf.Min(8192, array2.Length - j * 8192); byte[] array3 = new byte[num3]; Array.Copy(array2, j * 8192, array3, 0, num3); VoiceChunkRPC(array3, j, num2, 48000, enemyViewId); } Debug.Log((object)$"[MimicVoice] broadcast snippet in {num2} chunk(s) for Mimic view {enemyViewId} (solo, inline)."); } private IEnumerator SendChunksPaced(byte[] bytes, int total, int chunkSize, int enemyViewId) { for (int c = 0; c < total; c++) { int num = Mathf.Min(chunkSize, bytes.Length - c * chunkSize); byte[] array = new byte[num]; Array.Copy(bytes, c * chunkSize, array, 0, num); if ((Object)(object)view == (Object)null) { yield break; } view.RPC("VoiceChunkRPC", (RpcTarget)0, new object[5] { array, c, total, 48000, enemyViewId }); if ((c & 1) == 1) { yield return (object)new WaitForSecondsRealtime(0.09f); } } Debug.Log((object)$"[MimicVoice] broadcast snippet in {total} paced chunk(s) for Mimic view {enemyViewId}."); } private void BroadcastRandomChatLine(int enemyViewId) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (chatLines.Count != 0) { string text = chatLines[Random.Range(0, chatLines.Count)]; int num = 0; if (SemiFunc.IsMultiplayer()) { view.RPC("TTSChatRPC", (RpcTarget)0, new object[3] { text, num, enemyViewId }); } else { TTSChatRPC(text, num, enemyViewId); } Debug.Log((object)$"[MimicVoice] broadcast TTS-chat line for Mimic view {enemyViewId}: {((text.Length > 40) ? text.Substring(0, 40) : text)}"); } } [PunRPC] private void TTSChatRPC(string text, int voiceIndex, int enemyViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMultiplayer() || SemiFunc.OwnerOnlyRPC(info, view)) { MimicTTSPlayback.Speak(text, voiceIndex, enemyViewId); } } [PunRPC] private void VoiceChunkRPC(byte[] chunk, int chunkIndex, int totalChunks, int sampleRate, int enemyViewId, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer() && !SemiFunc.OwnerOnlyRPC(info, view)) { return; } if (chunkIndex == 0) { rxChunks.Clear(); rxExpected = totalChunks; rxEnemyViewId = enemyViewId; } if (chunkIndex >= rxExpected) { return; } while (rxChunks.Count <= chunkIndex) { rxChunks.Add(null); } rxChunks[chunkIndex] = chunk; if (rxChunks.Count < rxExpected) { return; } foreach (byte[] rxChunk in rxChunks) { if (rxChunk == null) { return; } } int num = 0; foreach (byte[] rxChunk2 in rxChunks) { num += rxChunk2.Length; } byte[] array = new byte[num]; int num2 = 0; foreach (byte[] rxChunk3 in rxChunks) { Array.Copy(rxChunk3, 0, array, num2, rxChunk3.Length); num2 += rxChunk3.Length; } rxChunks.Clear(); MimicVoicePlayback.PlayOnMimic(array, sampleRate, rxEnemyViewId, playerAvatar); } } public static class MimicVoicePlayback { public static GameObject SoloFallbackMimic; public static void PlayOnMimic(byte[] audioData, int sampleRate, int enemyViewId, PlayerAvatar anyAvatarForMixer) { //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) PhotonView val = PhotonView.Find(enemyViewId); GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : SoloFallbackMimic); if ((Object)(object)val2 == (Object)null) { Debug.LogWarning((object)$"[MimicVoice] playback: Mimic view {enemyViewId} not found and no solo fallback - dropping snippet."); return; } int num = audioData.Length / 2; float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = (float)(short)(audioData[i * 2] | (audioData[i * 2 + 1] << 8)) / 32768f; } array = LowPass(array, 4500f, sampleRate); EdgeFade(array, (int)((float)sampleRate * 0.02f)); AudioClip val3 = AudioClip.Create("MimicVoiceLure", array.Length, 1, sampleRate, false); val3.SetData(array, 0); Transform val4 = val2.transform.Find("MimicVoiceSource"); if ((Object)(object)val4 == (Object)null) { GameObject val5 = new GameObject("MimicVoiceSource"); val5.transform.SetParent(val2.transform, false); val4 = val5.transform; } AudioSource val6 = ((Component)val4).GetComponent(); if ((Object)(object)val6 == (Object)null) { val6 = ((Component)val4).gameObject.AddComponent(); } val6.clip = val3; val6.volume = 0.9f; val6.spatialBlend = 1f; val6.dopplerLevel = 0.5f; val6.minDistance = 1f; val6.maxDistance = 20f; val6.rolloffMode = (AudioRolloffMode)1; if ((Object)(object)anyAvatarForMixer != (Object)null && (Object)(object)anyAvatarForMixer.voiceChat != (Object)null && (Object)(object)anyAvatarForMixer.voiceChat.mixerMicrophoneSound != (Object)null) { val6.outputAudioMixerGroup = anyAvatarForMixer.voiceChat.mixerMicrophoneSound; } val6.Play(); Debug.Log((object)$"[MimicVoice] playing {(float)array.Length / (float)sampleRate:F1}s lure from Mimic view {enemyViewId}."); } private static float[] LowPass(float[] input, float cutoff, int sampleRate) { float num = 1f / (MathF.PI * 2f * cutoff); float num2 = 1f / (float)sampleRate; float num3 = num2 / (num + num2); float[] array = new float[input.Length]; float num4 = 0f; for (int i = 0; i < input.Length; i++) { num4 = (array[i] = num4 + num3 * (input[i] - num4)); } return array; } private static void EdgeFade(float[] data, int fadeSamples) { for (int i = 0; i < fadeSamples && i < data.Length; i++) { float num = (float)i / (float)fadeSamples; data[i] *= num; data[data.Length - 1 - i] *= num; } } } [HarmonyPatch(typeof(PlayerAvatar), "Awake")] internal static class MimicVoice_PlayerAvatarAwakePatch { private static void Postfix(PlayerAvatar __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(LocalVoiceFramed), "PushDataAsync")] internal static class MimicVoice_PushDataPatch { private static void Prefix(short[] buf) { foreach (MimicVoiceCapture item in MimicVoiceCapture.All) { if ((Object)(object)item != (Object)null && item.IsLocalOwned) { item.ProcessVoiceData(buf); break; } } } } [HarmonyPatch(typeof(TTSVoice), "TTSSpeakNow")] internal static class MimicVoice_TTSCapturePatch { private static void Postfix(TTSVoice __instance, string text) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.playerAvatar == (Object)null || string.IsNullOrWhiteSpace(text)) { return; } foreach (MimicVoiceCapture item in MimicVoiceCapture.All) { if ((Object)(object)item != (Object)null && item.IsLocalOwned && (Object)(object)item.PlayerAvatarRef == (Object)(object)__instance.playerAvatar) { item.CaptureChatLine(text); break; } } } } public static class MimicTTSPlayback { private static readonly Dictionary perMimic = new Dictionary(); public static void ClearRunStatics() { perMimic.Clear(); } public static void Speak(string text, int voiceIndex, int enemyViewId) { if (string.IsNullOrWhiteSpace(text)) { return; } PhotonView val = PhotonView.Find(enemyViewId); GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : MimicVoicePlayback.SoloFallbackMimic); if ((Object)(object)val2 == (Object)null) { Debug.LogWarning((object)$"[MimicVoice] TTS-chat: Mimic view {enemyViewId} not found and no solo fallback."); return; } TTSVoice orCreate = GetOrCreate(val2, enemyViewId); if ((Object)(object)orCreate == (Object)null) { Debug.LogWarning((object)"[MimicVoice] TTS-chat: no TTSVoice template to clone (no live player TTSVoice found)."); return; } orCreate.setVoice(Mathf.Clamp(voiceIndex, 0, 1)); orCreate.TTSSpeakNow(text, false); Debug.Log((object)string.Format("[MimicVoice] Mimic speaking TTS-chat line from its body (view {0}): \"{1}\".", enemyViewId, (text.Length > 40) ? (text.Substring(0, 40) + "...") : text)); } private static TTSVoice GetOrCreate(GameObject mimic, int enemyViewId) { //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) if (perMimic.TryGetValue(enemyViewId, out var value) && (Object)(object)value != (Object)null) { return value; } TTSVoice val = null; TTSVoice[] array = Object.FindObjectsOfType(); TTSVoice[] array2 = array; foreach (TTSVoice val2 in array2) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.playerAvatar != (Object)null && val2.voices != null && val2.voices.Length != 0) { val = val2; break; } } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)$"[MimicVoice] TTS template scan: {array.Length} TTSVoice object(s) in scene."); array2 = array; foreach (TTSVoice val3 in array2) { if ((Object)(object)val3 != (Object)null) { Debug.LogWarning((object)$"[MimicVoice] TTSVoice on '{((Object)((Component)val3).gameObject).name}': playerAvatar={(Object)(object)val3.playerAvatar != (Object)null}, voices={((val3.voices != null) ? val3.voices.Length : (-1))}"); } } array2 = array; foreach (TTSVoice val4 in array2) { if ((Object)(object)val4 != (Object)null && val4.voices != null && val4.voices.Length != 0) { val = val4; break; } } if ((Object)(object)val == (Object)null) { return null; } Debug.Log((object)"[MimicVoice] TTS template: relaxed match (voices-only, playerAvatar ignored) succeeded."); } GameObject val5 = Object.Instantiate(((Component)val).gameObject, mimic.transform); val5.transform.localPosition = Vector3.up * 1.8f; PhotonView[] componentsInChildren = val5.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } TTSVoice val6 = val5.GetComponent(); if ((Object)(object)val6 == (Object)null) { val6 = val5.GetComponentInChildren(true); } if ((Object)(object)val6 == (Object)null) { Object.Destroy((Object)(object)val5); return null; } val6.playerAvatar = null; AudioSource component = ((Component)val6).GetComponent(); if ((Object)(object)component != (Object)null) { component.spatialBlend = 1f; component.minDistance = 1f; component.maxDistance = 20f; component.rolloffMode = (AudioRolloffMode)1; } perMimic[enemyViewId] = val6; return val6; } } [HarmonyPatch(typeof(TTSVoice), "Update")] internal static class MimicVoice_TTSUpdateGuard { private static bool Prefix(TTSVoice __instance) { if (!((Object)(object)__instance == (Object)null)) { return (Object)(object)__instance.playerAvatar != (Object)null; } return true; } } namespace MimicMonster { [BepInPlugin("jonathan.mimicmonster", "MimicMonster", "1.0.0")] public class MimicMonsterPlugin : BaseUnityPlugin { private void Awake() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) ((BaseUnityPlugin)this).Logger.LogInfo((object)"MimicMonster script assembly loaded (EnemyMimic available for bundle deserialization)."); try { new Harmony("jonathan.mimicmonster").PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MimicMonster Harmony patches applied (voice capture + frame feed)."); SceneManager.sceneLoaded += delegate { MimicVoiceCapture.VoiceViablePlayers.Clear(); EnemyMimic.ClearRunStatics(); MimicTTSPlayback.ClearRunStatics(); }; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("MimicMonster Harmony PatchAll failed - voice mimicry will be inert: " + ex.Message)); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }