using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using REPOLib.Modules; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Matsu.MergedEnemyMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Matsu.MergedEnemyMod")] [assembly: AssemblyTitle("Matsu.MergedEnemyMod")] [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 Matsu.MergedEnemyMod { internal static class FusionShared { private static ParticleScriptExplosion? _sharedExplosion; private static GameObject? _explosionPrefab; private static readonly List _noPlayers = new List(); private static FieldInfo? _healthCurrentField; private static FieldInfo? _impactDetectorField; private static MethodInfo? _hurtMultiplierMethod; private static FieldInfo? _explSizeField; private static FieldInfo? _explDmgField; private static FieldInfo? _explDmgEnemyField; private const string AuraLightName = "MatsuMutationAura"; private static FieldInfo? _tumbleField; private static FieldInfo? _tumblePhysGrabObjectField; private static FieldInfo? _clientPositionField; private static FieldInfo? _clientPositionCurrentField; private static FieldInfo? _visualPositionField; private static FieldInfo? _isDisabledField; public static List AllPlayers() { GameDirector instance = GameDirector.instance; if (!((Object)(object)instance != (Object)null) || instance.PlayerList == null) { return _noPlayers; } return instance.PlayerList; } public static bool NearestPlayerWithin(Vector3 from, float range) { //IL_001e: 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) foreach (PlayerAvatar item in AllPlayers()) { if (!((Object)(object)item == (Object)null) && Vector3.Distance(from, ((Component)item).transform.position) <= range) { return true; } } return false; } public static List PlayersInRadius(Vector3 center, float radius) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (PlayerAvatar item in AllPlayers()) { if (!((Object)(object)item == (Object)null) && Vector3.Distance(center, ((Component)item).transform.position) <= radius) { list.Add(item); } } return list; } public static PlayerAvatar? NearestPlayer(Vector3 from, float maxDistance) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar result = null; float num = maxDistance; foreach (PlayerAvatar item in AllPlayers()) { if (!((Object)(object)item == (Object)null)) { float num2 = Vector3.Distance(from, ((Component)item).transform.position); if (num2 <= num) { num = num2; result = item; } } } return result; } public static List PhysObjectsInRadius(Vector3 center, float radius) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); Collider[] array = Physics.OverlapSphere(center, radius); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null)) { PhysGrabObject componentInParent = ((Component)val).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.rb != (Object)null && !componentInParent.grabbed && (Object)(object)((Component)componentInParent).GetComponentInParent() == (Object)null) { hashSet.Add(componentInParent); } } } return new List(hashSet); } private static void SetExplField(ParticlePrefabExplosion pe, ref FieldInfo? cache, string name, object val) { try { if ((object)cache == null) { cache = typeof(ParticlePrefabExplosion).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } cache?.SetValue(pe, val); } catch { } } public static ParticlePrefabExplosion? ExplodeAuthoritative(Vector3 pos, float size, int playerDmg, int enemyDmg, PhysGrabObject? ignoreSelf = null, Enemy? enemyHost = null) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) ParticlePrefabExplosion val = null; if ((Object)(object)_sharedExplosion == (Object)null) { _sharedExplosion = Object.FindObjectOfType(true); } if ((Object)(object)_sharedExplosion != (Object)null) { try { val = _sharedExplosion.Spawn(pos, size, playerDmg, enemyDmg, 1f, false, false, 1f); } catch { val = null; } } if ((Object)(object)val == (Object)null) { if ((Object)(object)_explosionPrefab == (Object)null) { _explosionPrefab = Resources.Load("Effects/Part Prefab Explosion"); } if ((Object)(object)_explosionPrefab != (Object)null) { val = Object.Instantiate(_explosionPrefab, pos, Quaternion.identity).GetComponent(); if ((Object)(object)val != (Object)null) { SetExplField(val, ref _explSizeField, "explosionSize", size); SetExplField(val, ref _explDmgField, "explosionDamage", playerDmg); SetExplField(val, ref _explDmgEnemyField, "explosionDamageEnemy", enemyDmg); try { ParticleSystem particleFire = val.particleFire; if (particleFire != null) { particleFire.Play(); } ParticleSystem particleSmoke = val.particleSmoke; if (particleSmoke != null) { particleSmoke.Play(); } if ((Object)(object)val.light != (Object)null) { ((Behaviour)val.light).enabled = true; } } catch { } } } } if ((Object)(object)val != (Object)null && (Object)(object)val.HurtCollider != (Object)null) { try { if ((Object)(object)ignoreSelf != (Object)null && val.HurtCollider.ignoreObjects != null) { val.HurtCollider.ignoreObjects.Add(ignoreSelf); } if ((Object)(object)enemyHost != (Object)null) { val.HurtCollider.enemyHost = enemyHost; } } catch { } } return val; } public static void ApplyMutationGlow(Transform root, Color color) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_006e: 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) if ((Object)(object)root == (Object)null) { return; } try { Transform val = root.Find("MatsuMutationAura"); Light val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).GetComponent(); } else { GameObject val3 = new GameObject("MatsuMutationAura"); val3.transform.SetParent(root, false); val3.transform.localPosition = Vector3.zero; val2 = val3.AddComponent(); val2.type = (LightType)2; val2.shadows = (LightShadows)0; } if ((Object)(object)val2 != (Object)null) { val2.color = color; val2.range = Plugin.MutationAuraRange.Value; val2.intensity = Plugin.MutationAuraIntensity.Value; } } catch { } Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Renderer val4 in componentsInChildren) { if ((Object)(object)val4 == (Object)null) { continue; } Material[] materials = val4.materials; foreach (Material val5 in materials) { if (!((Object)(object)val5 == (Object)null)) { try { val5.SetFloat("_FresnelAmount", 1f); val5.SetFloat("_FresnelScale", 1f); val5.SetFloat("_FresnelPower", 5f); val5.SetFloat("_FresnelBias", 0f); val5.SetColor("_FresnelColor", color); val5.SetFloat("_FresnelEmission", 1f); } catch { } } } } } public static void SetHealthCurrent(EnemyHealth health, int value) { try { if (_healthCurrentField == null) { _healthCurrentField = typeof(EnemyHealth).GetField("healthCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } _healthCurrentField?.SetValue(health, value); } catch { } } public static void BoostThrownImpact(PhysGrabObject obj, float multiplier, float time) { try { if (_impactDetectorField == null) { _impactDetectorField = typeof(PhysGrabObject).GetField("impactDetector", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object obj2 = _impactDetectorField?.GetValue(obj); if (obj2 != null) { if (_hurtMultiplierMethod == null) { _hurtMultiplierMethod = obj2.GetType().GetMethod("PlayerHurtMultiplier", BindingFlags.Instance | BindingFlags.Public); } _hurtMultiplierMethod?.Invoke(obj2, new object[2] { multiplier, time }); } } catch { } } public static bool TryGetSafeRandomPoint(Vector3 from, out Vector3 point) { //IL_001b: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0081: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[1] { "Default" }); NavMeshHit val2 = default(NavMeshHit); RaycastHit val3 = default(RaycastHit); for (int i = 0; i < 16; i++) { LevelPoint val = SemiFunc.LevelPointGet(from, 0f, 9999f); if (!((Object)(object)val == (Object)null) && NavMesh.SamplePosition(((Component)val).transform.position + Random.insideUnitSphere * 3f, ref val2, 5f, -1) && Physics.Raycast(((NavMeshHit)(ref val2)).position + Vector3.up * 0.5f, Vector3.down, ref val3, 3f, mask, (QueryTriggerInteraction)1)) { point = ((RaycastHit)(ref val3)).point + Vector3.up * 0.6f; return true; } } point = from; return false; } public static PhysGrabObject? GetPlayerPhysGrabObject(PlayerAvatar player) { try { if ((object)_tumbleField == null) { _tumbleField = typeof(PlayerAvatar).GetField("tumble", BindingFlags.Instance | BindingFlags.NonPublic); } object obj = _tumbleField?.GetValue(player); if (obj == null) { return null; } if ((object)_tumblePhysGrabObjectField == null) { _tumblePhysGrabObjectField = obj.GetType().GetField("physGrabObject", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj2 = _tumblePhysGrabObjectField?.GetValue(obj); return (PhysGrabObject?)((obj2 is PhysGrabObject) ? obj2 : null); } catch { return null; } } public static void SetPlayerClientPosition(PlayerAvatar player, Vector3 pos) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if ((object)_clientPositionField == null) { _clientPositionField = typeof(PlayerAvatar).GetField("clientPosition", BindingFlags.Instance | BindingFlags.NonPublic); } if ((object)_clientPositionCurrentField == null) { _clientPositionCurrentField = typeof(PlayerAvatar).GetField("clientPositionCurrent", BindingFlags.Instance | BindingFlags.NonPublic); } _clientPositionField?.SetValue(player, pos); _clientPositionCurrentField?.SetValue(player, pos); } catch { } } public static void SetPlayerVisualPosition(PlayerAvatarVisuals visuals, Vector3 pos) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) try { if ((object)_visualPositionField == null) { _visualPositionField = typeof(PlayerAvatarVisuals).GetField("visualPosition", BindingFlags.Instance | BindingFlags.NonPublic); } _visualPositionField?.SetValue(visuals, pos); } catch { } } public static bool IsPlayerDisabled(PlayerAvatar player) { try { if ((object)_isDisabledField == null) { _isDisabledField = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.NonPublic); } return _isDisabledField != null && (bool)(_isDisabledField.GetValue(player) ?? ((object)false)); } catch { return false; } } } public class BoomdayBoyFusion : MonoBehaviour { internal static readonly Color AuraColor = new Color(1f, 0.4f, 0f); private EnemyBirthdayBoy _birthday; private EnemyHealth? _health; private EnemyParent? _self; private Enemy? _enemy; private PhysGrabObject? _selfPhys; private bool _fuseLit; private bool _deathDetonated; private bool _hpDone; private float _fuseTimer; private float _explodeCooldown; private float _balloonTimer; private float _proximityTimer; private float _glowTimer; private readonly List _orderedKeys = new List(); private readonly HashSet _seen = new HashSet(); private void Awake() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) _birthday = ((Component)this).GetComponent(); _self = ((Component)this).GetComponentInParent(); _health = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(); _enemy = ((Component)this).GetComponent() ?? ((Component)this).GetComponentInParent(); _selfPhys = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(true); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value)); } FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } private void Update() { //IL_0030: 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) _glowTimer -= Time.deltaTime; if (_glowTimer <= 0f) { _glowTimer = 2f; FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } _balloonTimer -= Time.deltaTime; if (_balloonTimer <= 0f) { _balloonTimer = 0.2f; SyncAndTintBalloons(); } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } EnsureHpDoubled(); if (_deathDetonated || (Object)(object)_birthday == (Object)null) { return; } HostBalloonContacts(); if (_explodeCooldown > 0f) { _explodeCooldown -= Time.deltaTime; } _proximityTimer -= Time.deltaTime; if (!_fuseLit && _explodeCooldown <= 0f && _proximityTimer <= 0f) { _proximityTimer = 0.25f; if (FusionShared.NearestPlayerWithin(((Component)this).transform.position, Plugin.BoomdayFuseRange.Value)) { _fuseLit = true; _fuseTimer = Plugin.BoomdayFuseTime.Value; } } if (_fuseLit) { _fuseTimer -= Time.deltaTime; if (_fuseTimer <= 0f) { ProximityExplode(); } } } private void EnsureHpDoubled() { if (!_hpDone && !((Object)(object)_health == (Object)null)) { _hpDone = true; FusionShared.SetHealthCurrent(_health, _health.health); } } private void SyncAndTintBalloons() { //IL_004e: 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) if ((Object)(object)_birthday == (Object)null || _birthday.balloons == null) { return; } foreach (KeyValuePair balloon in _birthday.balloons) { if (!((Object)(object)balloon.Value == (Object)null) && _seen.Add(balloon.Key)) { _orderedKeys.Add(balloon.Key); TintBalloon(balloon.Value); } } } private void HostBalloonContacts() { //IL_0049: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00b0: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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) if ((Object)(object)_birthday == (Object)null || _birthday.balloons == null || _orderedKeys.Count == 0) { return; } float value = Plugin.BoomdayBalloonTouchRadius.Value; List list = null; foreach (Vector3 orderedKey in _orderedKeys) { if (!_birthday.balloons.TryGetValue(orderedKey, out var value2) || (Object)(object)value2 == (Object)null) { (list ?? (list = new List())).Add(orderedKey); continue; } Vector3 position = value2.transform.position; if (AnyPlayerWithin(position, value)) { ExplodeBalloon(value2, position); (list ?? (list = new List())).Add(orderedKey); } else if (AnyOtherEnemyWithin(position, value)) { PopBalloon(value2, position); (list ?? (list = new List())).Add(orderedKey); } } if (list == null) { return; } foreach (Vector3 item in list) { ForgetBalloon(item); } } private static bool AnyPlayerWithin(Vector3 pos, float radius) { //IL_001e: 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) foreach (PlayerAvatar item in FusionShared.AllPlayers()) { if (!((Object)(object)item == (Object)null) && Vector3.Distance(pos, ((Component)item).transform.position) <= radius) { return true; } } return false; } private bool AnyOtherEnemyWithin(Vector3 pos, float radius) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) EnemyDirector instance = EnemyDirector.instance; if ((Object)(object)instance == (Object)null || instance.enemiesSpawned == null) { return false; } foreach (EnemyParent item in instance.enemiesSpawned) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)_self) && Vector3.Distance(pos, ((Component)item).transform.position) <= radius) { return true; } } return false; } private void ProximityExplode() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) FusionShared.ExplodeAuthoritative(((Component)this).transform.position, 1.3f, Plugin.BoomdayCoreDamage.Value, 0, _selfPhys, _enemy); AggroNearestPlayer(); StartBalloonChain(); _fuseLit = false; _explodeCooldown = Plugin.BoomdayExplodeCooldown.Value; } public void Detonate() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!_deathDetonated) { _deathDetonated = true; FusionShared.ExplodeAuthoritative(((Component)this).transform.position, 1.6f, Plugin.BoomdayCoreDamage.Value, 0, _selfPhys, _enemy); StartBalloonChain(); } } private void AggroNearestPlayer() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)_birthday == (Object)null)) { PlayerAvatar val = FusionShared.NearestPlayer(((Component)this).transform.position, Plugin.BoomdayFuseRange.Value * 3f); if (!((Object)(object)val == (Object)null)) { _birthday.playerTarget = val; _birthday.UpdateState((State)6); } } } catch { } } private void StartBalloonChain() { //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_0050: 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) if ((Object)(object)_birthday == (Object)null || _orderedKeys.Count == 0) { return; } List list = new List(); foreach (Vector3 orderedKey in _orderedKeys) { if (_birthday.balloons != null && _birthday.balloons.TryGetValue(orderedKey, out var value) && (Object)(object)value != (Object)null) { list.Add(value); _birthday.balloons.Remove(orderedKey); } } _orderedKeys.Clear(); _seen.Clear(); Plugin.Instance.StartBalloonChain(list, Plugin.BoomdayBalloonDamage.Value, ((Object)(object)_birthday != (Object)null) ? _birthday.balloonPopEffect : null); } private void ForgetBalloon(Vector3 key) { //IL_0017: 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_0031: Unknown result type (might be due to invalid IL or missing references) _birthday?.balloons?.Remove(key); _orderedKeys.Remove(key); _seen.Remove(key); } private void ExplodeBalloon(GameObject balloon, Vector3 bp) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) FusionShared.ExplodeAuthoritative(bp, 0.7f, Plugin.BoomdayBalloonDamage.Value, 0); if ((Object)(object)_birthday != (Object)null && (Object)(object)_birthday.balloonPopEffect != (Object)null) { Object.Instantiate(_birthday.balloonPopEffect, bp, Quaternion.identity); } Object.Destroy((Object)(object)balloon); } private void PopBalloon(GameObject balloon, Vector3 bp) { //IL_002c: 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) if ((Object)(object)_birthday != (Object)null && (Object)(object)_birthday.balloonPopEffect != (Object)null) { Object.Instantiate(_birthday.balloonPopEffect, bp, Quaternion.identity); } Object.Destroy((Object)(object)balloon); } private void TintBalloon(GameObject balloon) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_003b: 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_0064: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = balloon.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { MaterialPropertyBlock val2 = new MaterialPropertyBlock(); val.GetPropertyBlock(val2); val2.SetColor("_Color", new Color(1f, 0.45f, 0f)); val2.SetColor("_EmissionColor", new Color(1f, 0.35f, 0f) * 1.5f); val.SetPropertyBlock(val2); } } } } public class PoltergeistFusion : MonoBehaviour { internal static readonly Color AuraColor = new Color(0.35f, 0.8f, 1f); private EnemyHealth? _health; private bool _hpDone; private float _throwCooldown; private float _playerFloatCooldown; private float _fieldTimer; private float _glowTimer; private GameObject? _fieldSphere; private void Awake() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) _health = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value)); } FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); _throwCooldown = Plugin.PoltergeistThrowInterval.Value; _playerFloatCooldown = Plugin.PoltergeistPlayerFloatInterval.Value; } private void Update() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_015c: 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) _glowTimer -= Time.deltaTime; if (_glowTimer <= 0f) { _glowTimer = 2f; FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } EnsureFieldSphere(); if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } EnsureHpDoubled(); _fieldTimer -= Time.deltaTime; if (_fieldTimer <= 0f) { _fieldTimer = 0.25f; foreach (PhysGrabObject item in FusionShared.PhysObjectsInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value)) { if (!((Object)(object)item == (Object)null)) { try { item.OverrideZeroGravity(0.35f); item.OverrideDrag(1f, 0.35f); item.OverrideAngularDrag(1.5f, 0.35f); } catch { } } } } _playerFloatCooldown -= Time.deltaTime; if (_playerFloatCooldown <= 0f) { _playerFloatCooldown = Plugin.PoltergeistPlayerFloatInterval.Value; foreach (PlayerAvatar item2 in FusionShared.PlayersInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value)) { if (!((Object)(object)item2 == (Object)null)) { try { item2.ForceImpulse(Vector3.up * Plugin.PoltergeistPlayerFloatForce.Value); } catch { } } } } _throwCooldown -= Time.deltaTime; if (_throwCooldown <= 0f) { _throwCooldown = Plugin.PoltergeistThrowInterval.Value; ThrowValuableAtPlayer(); } } private void EnsureHpDoubled() { if (!_hpDone && !((Object)(object)_health == (Object)null)) { _hpDone = true; FusionShared.SetHealthCurrent(_health, _health.health); } } private void EnsureFieldSphere() { //IL_00c0: 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_00e5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_fieldSphere != (Object)null) { return; } try { EnemyParent componentInParent = ((Component)this).GetComponentInParent(); EnemyFloaterSphereEffect val = ((componentInParent != null) ? ((Component)componentInParent).GetComponentInChildren(true) : null) ?? ((Component)this).GetComponentInChildren(true); MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); Material val3 = (((Object)(object)val2 != (Object)null) ? ((Renderer)val2).sharedMaterial : null); if (!((Object)(object)val3 == (Object)null)) { GameObject val4 = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)val4).name = "MatsuPoltergeistField"; Collider component = val4.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } MeshRenderer component2 = val4.GetComponent(); ((Renderer)component2).sharedMaterial = val3; ((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component2).receiveShadows = false; val4.transform.SetParent(((Component)this).transform, false); val4.transform.localPosition = Vector3.zero; val4.transform.localScale = Vector3.one * (Plugin.PoltergeistRange.Value * 2f); _fieldSphere = val4; } } catch { _fieldSphere = null; } } private void ThrowValuableAtPlayer() { //IL_0006: 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_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: 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_0099: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar val = FusionShared.NearestPlayer(((Component)this).transform.position, Plugin.PoltergeistRange.Value * 1.5f); if ((Object)(object)val == (Object)null) { return; } PhysGrabObject val2 = null; float num = float.MaxValue; foreach (PhysGrabObject item in FusionShared.PhysObjectsInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value)) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.rb == (Object)null) && !((Object)(object)((Component)item).GetComponentInParent() == (Object)null)) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position); if (num2 < num) { num = num2; val2 = item; } } } if ((Object)(object)val2 == (Object)null || (Object)(object)val2.rb == (Object)null) { return; } Rigidbody rb = val2.rb; EnemyParent componentInParent = ((Component)this).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { Collider[] componentsInChildren = ((Component)componentInParent).GetComponentsInChildren(true); Collider[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren(true); Collider[] array = componentsInChildren; foreach (Collider val3 in array) { if ((Object)(object)val3 == (Object)null) { continue; } Collider[] array2 = componentsInChildren2; foreach (Collider val4 in array2) { if ((Object)(object)val4 != (Object)null) { try { Physics.IgnoreCollision(val3, val4, true); } catch { } } } } } try { val2.ResetMass(); } catch { } float num3 = Mathf.Min(20f * rb.mass, 100f); try { val2.ResetIndestructible(); } catch { } Vector3 val5 = ((Component)val).transform.position + Vector3.up * 1f; Vector3 val6 = Vector3.Lerp(((Component)this).transform.forward, val5 - val2.centerPoint, 0.5f); rb.AddForce(val6 * num3, (ForceMode)1); rb.AddTorque(((Component)val2).transform.right * 0.5f, (ForceMode)1); FusionShared.BoostThrownImpact(val2, 5f, 2f); } } public class CleanupCrewFusion : MonoBehaviour { internal static readonly Color AuraColor = new Color(0.4f, 1f, 0.15f); private static FieldInfo? _headStateField; private EnemyBombThrower _thrower; private EnemyHealth? _health; private bool _hpDone; private float _glowTimer; private int _prevHeadState = -1; private void Awake() { _thrower = ((Component)this).GetComponent(); _health = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value)); } ApplyGlow(); Plugin.GetMeltdownHeadPrefabRef(); } private void Update() { _glowTimer -= Time.deltaTime; if (_glowTimer <= 0f) { _glowTimer = 2f; ApplyGlow(); } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } EnsureHpDoubled(); if (!((Object)(object)_thrower == (Object)null) && !((Object)(object)_thrower.head == (Object)null)) { int num = ReadHeadState(_thrower.head); if (_prevHeadState != -1 && num == 1 && _prevHeadState != 1) { SpawnExtraHeads(); } _prevHeadState = num; } } private void SpawnExtraHeads() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) Transform headSpawnTransform = _thrower.headSpawnTransform; if ((Object)(object)headSpawnTransform == (Object)null) { Plugin.Log.LogWarning((object)"[MeltdownCrew] headSpawnTransform is null; can't spawn extras."); return; } Plugin.Log.LogInfo((object)"[MeltdownCrew] body launched its head — spawning 2 extra heads."); Plugin.SpawnMeltdownHead(headSpawnTransform.position, headSpawnTransform.rotation, headSpawnTransform.forward, Plugin.MeltdownSlowSpeed.Value); Plugin.SpawnMeltdownHead(headSpawnTransform.position, headSpawnTransform.rotation, headSpawnTransform.forward, Plugin.MeltdownFastSpeed.Value); } private void EnsureHpDoubled() { if (!_hpDone && !((Object)(object)_health == (Object)null)) { _hpDone = true; FusionShared.SetHealthCurrent(_health, _health.health); } } private void ApplyGlow() { //IL_0006: 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) FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); if ((Object)(object)_thrower != (Object)null && (Object)(object)_thrower.head != (Object)null) { FusionShared.ApplyMutationGlow(((Component)_thrower.head).transform, AuraColor); } } private static int ReadHeadState(EnemyBombThrowerHead head) { try { if (_headStateField == null) { _headStateField = typeof(EnemyBombThrowerHead).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object obj = _headStateField?.GetValue(head); return (obj != null) ? Convert.ToInt32(obj) : (-1); } catch { return -1; } } } public class MeltdownExtraHead : MonoBehaviour { private PhotonView? _pv; private Rigidbody? _rb; private ParticleScriptExplosion? _explosion; private float _factor = 1f; private bool _launched; private bool _exploding; private float _flightTimer; private float _destroyTimer; private void Awake() { _pv = ((Component)this).GetComponent(); _rb = ((Component)this).GetComponent()?.rb ?? ((Component)this).GetComponent(); _explosion = ((Component)this).GetComponent(); Animator component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } public void Launch(float factor, Vector3 forward) { //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_0049: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) _factor = factor; _flightTimer = Plugin.MeltdownHeadFlightSeconds.Value; _launched = true; if ((Object)(object)_rb != (Object)null) { _rb.isKinematic = false; Vector3 val = Vector3.Lerp(((Vector3)(ref forward)).normalized, Vector3.up, 0.3f); _rb.AddForce(val * 20f, (ForceMode)1); _rb.AddTorque(Vector3.right * 0.25f, (ForceMode)1); } } private void FixedUpdate() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_011c: 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_012e: 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_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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_00ba: 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_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } if (_exploding) { _destroyTimer -= Time.fixedDeltaTime; if (_destroyTimer <= 0f) { DestroySelf(); } } else { if (!_launched || (Object)(object)_rb == (Object)null) { return; } PlayerAvatar val = FusionShared.NearestPlayer(_rb.position, 40f); if ((Object)(object)val != (Object)null) { Vector3 val2 = ((Component)val).transform.position - _rb.position; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude > 0.01f) { _rb.AddForce(((Vector3)(ref val2)).normalized * Plugin.MeltdownHomingForce.Value * Mathf.Max(0.5f, _factor), (ForceMode)0); } } float num = Plugin.MeltdownBaseSpeed.Value * _factor; Vector3 velocity = _rb.velocity; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(velocity.x, 0f, velocity.z); if (((Vector3)(ref val3)).magnitude > num) { val3 = ((Vector3)(ref val3)).normalized * num; _rb.velocity = new Vector3(val3.x, velocity.y, val3.z); } _flightTimer -= Time.fixedDeltaTime; if (_flightTimer <= 0f) { _exploding = true; _destroyTimer = 0.3f; if (SemiFunc.IsMultiplayer() && (Object)(object)_pv != (Object)null) { _pv.RPC("ExplodeRPC", (RpcTarget)0, new object[1] { _rb.position }); } else { ExplodeRPC(_rb.position); } } } } [PunRPC] private void ExplodeRPC(Vector3 pos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) try { ParticleScriptExplosion? explosion = _explosion; if (explosion != null) { explosion.Spawn(pos, 2f, Plugin.MeltdownHeadDamage.Value, 30, 4f, false, false, 1f); } } catch { } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } } private void DestroySelf() { try { if (SemiFunc.IsMultiplayer() && (Object)(object)_pv != (Object)null && _pv.IsMine) { PhotonNetwork.Destroy(((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } catch { Object.Destroy((Object)(object)((Component)this).gameObject); } } } public class PlayerTeleportHelper : MonoBehaviour { private PhotonView? _pv; private PlayerAvatar? _avatar; private void Awake() { _pv = ((Component)this).GetComponent(); _avatar = ((Component)this).GetComponent(); } public static void Trigger(PlayerAvatar player, Vector3 pos, int damage, int enemyIndex) { //IL_005a: 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) PlayerTeleportHelper component = ((Component)player).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component._pv == (Object)null)) { if (SemiFunc.IsMultiplayer()) { component._pv.RPC("TeleportAndHurtRPC", (RpcTarget)0, new object[3] { pos, damage, enemyIndex }); } else { component.TeleportAndHurtRPC(pos, damage, enemyIndex); } } } [PunRPC] private void TeleportAndHurtRPC(Vector3 pos, int damage, int enemyIndex) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_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_0030: 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_00de: 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_006a: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_avatar == (Object)null) { return; } if (SemiFunc.IsMasterClientOrSingleplayer()) { PhysGrabObject playerPhysGrabObject = FusionShared.GetPlayerPhysGrabObject(_avatar); if ((Object)(object)playerPhysGrabObject != (Object)null) { playerPhysGrabObject.Teleport(pos, ((Component)_avatar).transform.rotation); if ((Object)(object)playerPhysGrabObject.rb != (Object)null) { playerPhysGrabObject.rb.velocity = Vector3.zero; playerPhysGrabObject.rb.angularVelocity = Vector3.zero; } } } ((Component)_avatar).transform.position = pos; FusionShared.SetPlayerClientPosition(_avatar, pos); if ((Object)(object)_avatar.playerAvatarVisuals != (Object)null) { ((Component)_avatar.playerAvatarVisuals).transform.position = pos; FusionShared.SetPlayerVisualPosition(_avatar.playerAvatarVisuals, pos); } if (SemiFunc.IsMasterClientOrSingleplayer()) { _avatar.playerHealth.HurtOther(damage, pos, false, enemyIndex, false); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Snatcher] teleport RPC error: {arg}"); } } } [HarmonyPatch(typeof(PlayerAvatar), "Start")] internal static class PlayerAvatar_Start_Patch { private static void Postfix(PlayerAvatar __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Snatcher] PlayerAvatar_Start_Patch error: {arg}"); } } } public class SnatcherFusion : MonoBehaviour { internal static readonly Color AuraColor = new Color(0.6f, 0f, 0.85f); private static FieldInfo? _playerTargetField; private EnemyHidden _hidden; private EnemyParent? _self; private EnemyHealth? _health; private bool _hpDone; private float _glowTimer; private State _prevState; private bool _stateInitialized; private void Awake() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) _hidden = ((Component)this).GetComponent(); _self = ((Component)this).GetComponentInParent(); _health = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value)); } FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } private void Update() { //IL_0030: 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_007a: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_00f3: Unknown result type (might be due to invalid IL or missing references) _glowTimer -= Time.deltaTime; if (_glowTimer <= 0f) { _glowTimer = 2f; FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } EnsureHpDoubled(); if ((Object)(object)_hidden == (Object)null) { return; } State currentState = _hidden.currentState; if (!_stateInitialized) { _prevState = currentState; _stateInitialized = true; } else { if (currentState == _prevState) { return; } if ((int)currentState == 7) { PlayerAvatar playerTarget = GetPlayerTarget(_hidden); if ((Object)(object)playerTarget != (Object)null && !FusionShared.IsPlayerDisabled(playerTarget) && FusionShared.TryGetSafeRandomPoint(((Component)playerTarget).transform.position, out var point)) { int enemyIndex = (((Object)(object)_self != (Object)null && (Object)(object)EnemyDirector.instance != (Object)null) ? EnemyDirector.instance.enemiesSpawned.IndexOf(_self) : (-1)); PlayerTeleportHelper.Trigger(playerTarget, point, Plugin.SnatcherDamage.Value, enemyIndex); Plugin.Log.LogInfo((object)"[Snatcher] Snatched a player to a random spot."); } } _prevState = currentState; } } private void EnsureHpDoubled() { if (!_hpDone && !((Object)(object)_health == (Object)null)) { _hpDone = true; FusionShared.SetHealthCurrent(_health, _health.health); } } private static PlayerAvatar? GetPlayerTarget(EnemyHidden hidden) { try { if ((object)_playerTargetField == null) { _playerTargetField = typeof(EnemyHidden).GetField("playerTarget", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = _playerTargetField?.GetValue(hidden); return (PlayerAvatar?)((obj is PlayerAvatar) ? obj : null); } catch { return null; } } } public class PeeperFusion : MonoBehaviour { internal static readonly Color AuraColor = new Color(1f, 0.1f, 0.1f); private static FieldInfo? _targetPlayerField; private EnemyCeilingEye _eye; private EnemyHealth? _health; private bool _hpDone; private float _glowTimer; private PlayerAvatar? _lastTarget; private float _stareTimer; private void Awake() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) _eye = ((Component)this).GetComponent(); _health = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponentInChildren(); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value)); } FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } private void Update() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 _glowTimer -= Time.deltaTime; if (_glowTimer <= 0f) { _glowTimer = 2f; FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor); } EnsureHpDoubled(); if ((Object)(object)_eye == (Object)null) { return; } PlayerAvatar val = (((int)_eye.currentState == 3) ? GetTarget(_eye) : null); if ((Object)(object)val == (Object)null) { _lastTarget = null; _stareTimer = 0f; return; } if ((Object)(object)val != (Object)(object)_lastTarget) { _lastTarget = val; _stareTimer = 0f; } _stareTimer += Time.deltaTime; if (_stareTimer >= Plugin.DeathgazeStareSeconds.Value) { _stareTimer = 0f; FireBeam(val); } } private void EnsureHpDoubled() { if (!_hpDone && !((Object)(object)_health == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer()) { _hpDone = true; FusionShared.SetHealthCurrent(_health, _health.health); } } private void FireBeam(PlayerAvatar target) { try { SemiLaser clownLaserPrefab = Plugin.GetClownLaserPrefab(); if ((Object)(object)clownLaserPrefab == (Object)null) { return; } Transform source = (((Object)(object)_eye.eyeTransform != (Object)null) ? _eye.eyeTransform : ((Component)this).transform); GameObject val = Object.Instantiate(((Component)clownLaserPrefab).gameObject); val.SetActive(true); SemiLaser component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); return; } HurtCollider componentInChildren = val.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.enemyHost = ((Component)_eye).GetComponent(); componentInChildren.playerKill = false; componentInChildren.playerDamage = Plugin.DeathgazeBeamDamage.Value; componentInChildren.playerDamageCooldown = Plugin.DeathgazeBeamSeconds.Value + 1f; } EnemyParent componentInParent = ((Component)_eye).GetComponentInParent(); Transform ignoreRoot = ((componentInParent != null) ? ((Component)componentInParent).transform : null) ?? ((Component)this).transform; val.AddComponent().Init(component, source, target, Plugin.DeathgazeBeamSeconds.Value, ignoreRoot); } catch (Exception arg) { Plugin.Log.LogError((object)$"[Deathgaze] fire error: {arg}"); } } private static PlayerAvatar? GetTarget(EnemyCeilingEye eye) { try { if ((object)_targetPlayerField == null) { _targetPlayerField = typeof(EnemyCeilingEye).GetField("targetPlayer", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = _targetPlayerField?.GetValue(eye); return (PlayerAvatar?)((obj is PlayerAvatar) ? obj : null); } catch { return null; } } } public class PeeperBeam : MonoBehaviour { private static readonly int DefaultMask = LayerMask.GetMask(new string[1] { "Default" }); private SemiLaser _laser; private Transform _source; private PlayerAvatar? _target; private float _duration; private float _elapsed; private Transform? _ignoreRoot; public void Init(SemiLaser laser, Transform source, PlayerAvatar target, float duration, Transform? ignoreRoot) { _laser = laser; _source = source; _target = target; _duration = duration; _ignoreRoot = ignoreRoot; } private void LateUpdate() { //IL_005c: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) _elapsed += Time.deltaTime; if ((Object)(object)_laser == (Object)null || (Object)(object)_source == (Object)null || (Object)(object)_target == (Object)null || _elapsed >= _duration) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Vector3 position = _source.position; Vector3 val = ((Component)_target).transform.position + Vector3.up * 1f; Vector3 val2 = val - position; float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude < 0.01f) { return; } val2 /= magnitude; Vector3 val3 = val; float num = magnitude; RaycastHit[] array = Physics.RaycastAll(position, val2, magnitude, DefaultMask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val4 = array[i]; if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null) && (!((Object)(object)_ignoreRoot != (Object)null) || !((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(_ignoreRoot)) && ((RaycastHit)(ref val4)).distance < num) { num = ((RaycastHit)(ref val4)).distance; val3 = ((RaycastHit)(ref val4)).point; } } _laser.LaserActive(position, val3, true); } } [BepInPlugin("com.matsu.repomutations", "REPO Mutant Enemies", "0.8.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.matsu.repomutations"; public const string Name = "REPO Mutant Enemies"; public const string Version = "0.8.0"; public static ConfigEntry MutationChancePerLevel; public static ConfigEntry MutationMaxChance; public static ConfigEntry MutationHealthMultiplier; public static ConfigEntry MutationAuraRange; public static ConfigEntry MutationAuraIntensity; public static ConfigEntry BoomdayFuseRange; public static ConfigEntry BoomdayFuseTime; public static ConfigEntry BoomdayExplodeCooldown; public static ConfigEntry BoomdayCoreDamage; public static ConfigEntry BoomdayBalloonDamage; public static ConfigEntry BoomdayBalloonTouchRadius; public static ConfigEntry PoltergeistRange; public static ConfigEntry PoltergeistPlayerFloatInterval; public static ConfigEntry PoltergeistPlayerFloatForce; public static ConfigEntry PoltergeistThrowInterval; public static ConfigEntry MeltdownSlowSpeed; public static ConfigEntry MeltdownFastSpeed; public static ConfigEntry MeltdownBaseSpeed; public static ConfigEntry MeltdownHomingForce; public static ConfigEntry MeltdownHeadFlightSeconds; public static ConfigEntry MeltdownHeadDamage; public static ConfigEntry SnatcherDamage; public static ConfigEntry DeathgazeStareSeconds; public static ConfigEntry DeathgazeBeamSeconds; public static ConfigEntry DeathgazeBeamDamage; public static ConfigEntry DebugSpawnBoomdayKey; public static ConfigEntry DebugSpawnPoltergeistKey; public static ConfigEntry DebugSpawnMeltdownKey; public static ConfigEntry DebugSpawnSnatcherKey; public static ConfigEntry DebugSpawnDeathgazeKey; internal static float ForceFuseUntil; private Harmony _harmony; private static SemiLaser? _clownLaserPrefab; private static bool _clownLaserSearched; private const string MeltdownHeadPrefabId = "Matsu/MeltdownExtraHead"; private static PrefabRef? _meltdownHeadRef; private static bool _meltdownHeadBuilt; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; MutationChancePerLevel = ((BaseUnityPlugin)this).Config.Bind("Mutation", "ChancePerLevel", 0.01f, "Base mutation chance per level (per mutation type). Chance = level x this + pity, where pity grows by (level x this) for every level that type failed to mutate, and resets to 0 once it does."); MutationMaxChance = ((BaseUnityPlugin)this).Config.Bind("Mutation", "MaxChance", 1f, "Upper cap (0..1) for the level-scaled + pity mutation chance."); MutationHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Mutation", "HealthMultiplier", 2f, "Health multiplier applied to every mutated enemy."); MutationAuraRange = ((BaseUnityPlugin)this).Config.Bind("Mutation", "AuraLightRange", 4f, "Range of the coloured aura light attached to every mutated enemy (works even on invisible enemies)."); MutationAuraIntensity = ((BaseUnityPlugin)this).Config.Bind("Mutation", "AuraLightIntensity", 3f, "Brightness of the coloured aura light."); BoomdayFuseRange = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "FuseRange", 4f, "Player distance that lights the fuse."); BoomdayFuseTime = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "FuseTime", 2.5f, "Seconds from fuse lit to an explosion."); BoomdayExplodeCooldown = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "ExplodeCooldown", 4f, "Seconds before a Boomday Boy can explode again. It survives its own blasts (recurring threat)."); BoomdayCoreDamage = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "CoreDamage", 40, "Explosion damage (proximity & death blasts). Uses the game's real explosion."); BoomdayBalloonDamage = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "BalloonDamage", 20, "Per-balloon explosion damage. Uses the game's real explosion."); BoomdayBalloonTouchRadius = ((BaseUnityPlugin)this).Config.Bind("BoomdayBoy", "BalloonTouchRadius", 1.3f, "A balloon explodes when a player comes this close to it (enemies only pop it, no explosion)."); PoltergeistRange = ((BaseUnityPlugin)this).Config.Bind("Poltergeist", "Range", 7.2f, "Radius of the zero-G field and telekinetic reach."); PoltergeistPlayerFloatInterval = ((BaseUnityPlugin)this).Config.Bind("Poltergeist", "PlayerFloatInterval", 1.4f, "Seconds between the light upward nudges that keep players unsteady in the field."); PoltergeistPlayerFloatForce = ((BaseUnityPlugin)this).Config.Bind("Poltergeist", "PlayerFloatForce", 6f, "Strength of the periodic upward nudge on players inside the field."); PoltergeistThrowInterval = ((BaseUnityPlugin)this).Config.Bind("Poltergeist", "ThrowInterval", 2.2f, "Seconds between telekinetic throws. The thrown valuable's own physics impact deals damage (like the Rugrat)."); MeltdownSlowSpeed = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "SlowHeadSpeed", 0.5f, "Speed factor of the sluggish 2nd head in the volley (1 = normal Cleanup Crew head speed)."); MeltdownFastSpeed = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "FastHeadSpeed", 2f, "Speed factor of the frantic 3rd head in the volley (1 = normal Cleanup Crew head speed)."); MeltdownBaseSpeed = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "BaseHeadSpeed", 4f, "Reference horizontal head speed (m/s) that the slow/fast factors scale. The head's speed is capped at this x factor."); MeltdownHomingForce = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "FastHeadHomingForce", 12f, "Extra homing force applied to the fast head per (factor-1) so it actually reaches its higher speed and tracks the player."); MeltdownHeadFlightSeconds = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "HeadFlightSeconds", 7f, "How long each of the two EXTRA heads chases before it detonates. Set to roughly match the vanilla head's own fuse (~7s) so all three explode together — only their movement SPEED differs (0.5x / 2x)."); MeltdownHeadDamage = ((BaseUnityPlugin)this).Config.Bind("MeltdownCrew", "ExtraHeadDamage", 75, "Explosion damage of each extra head (matches the vanilla Cleanup Crew head by default)."); SnatcherDamage = ((BaseUnityPlugin)this).Config.Bind("Snatcher", "Damage", 20, "Damage dealt the instant a Snatcher (mutated Hidden) whisks you away."); DeathgazeStareSeconds = ((BaseUnityPlugin)this).Config.Bind("Deathgaze", "StareSeconds", 7.5f, "Seconds a Deathgaze (mutated Peeper) must hold a player in its stare before it fires a beam."); DeathgazeBeamSeconds = ((BaseUnityPlugin)this).Config.Bind("Deathgaze", "BeamSeconds", 2f, "How long each fired beam lasts."); DeathgazeBeamDamage = ((BaseUnityPlugin)this).Config.Bind("Deathgaze", "BeamDamage", 35, "Damage the beam deals (at most once per beam)."); DebugSpawnBoomdayKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "SpawnBoomdayKey", (KeyCode)290, "Press (host only) to spawn a Boomday Boy in front of your camera."); DebugSpawnPoltergeistKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "SpawnPoltergeistKey", (KeyCode)291, "Press (host only) to spawn a Poltergeist (mutated Mentalist) in front of your camera."); DebugSpawnMeltdownKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "SpawnMeltdownKey", (KeyCode)289, "Press (host only) to spawn a Meltdown Crew (mutated Cleanup Crew) in front of your camera."); DebugSpawnSnatcherKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "SpawnSnatcherKey", (KeyCode)288, "Press (host only) to spawn a Snatcher (mutated Hidden) in front of your camera."); DebugSpawnDeathgazeKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "SpawnDeathgazeKey", (KeyCode)287, "Press (host only) to spawn a Deathgaze (mutated Peeper) in front of your camera."); _harmony = new Harmony("com.matsu.repomutations"); _harmony.PatchAll(); Log.LogInfo((object)string.Format("{0} {1} loaded. Mutation chance = level x {2:P0} + pity. Debug: Boomday Boy (F9), Poltergeist (F10), Meltdown Crew (F8), Snatcher (F7), Deathgaze (F6). Everyone in the lobby must install this mod.", "REPO Mutant Enemies", "0.8.0", MutationChancePerLevel.Value)); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(DebugSpawnBoomdayKey.Value)) { DebugSpawn("Birthday", typeof(EnemyBirthdayBoy), "Boomday Boy"); } if (Input.GetKeyDown(DebugSpawnPoltergeistKey.Value)) { DebugSpawn("Floater", typeof(EnemyFloater), "Poltergeist"); } if (Input.GetKeyDown(DebugSpawnMeltdownKey.Value)) { DebugSpawn("Bomb", typeof(EnemyBombThrower), "Meltdown Crew"); } if (Input.GetKeyDown(DebugSpawnSnatcherKey.Value)) { DebugSpawn("Hidden", typeof(EnemyHidden), "Snatcher"); } if (Input.GetKeyDown(DebugSpawnDeathgazeKey.Value)) { DebugSpawn("Peeper", typeof(EnemyCeilingEye), "Deathgaze"); } } private static void DebugSpawn(string nameContains, Type componentType, string label) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_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_0063: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.IsMasterClientOrSingleplayer()) { Log.LogWarning((object)"[Debug] Spawn is host-only."); return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { Log.LogWarning((object)"[Debug] No main camera; are you in a level?"); return; } Vector3 val = ((Component)main).transform.position + ((Component)main).transform.forward * 3f; EnemySetup val2 = FindEnemySetup(nameContains, componentType); if ((Object)(object)val2 == (Object)null) { Log.LogWarning((object)("[Debug] " + label + " base enemy setup not found.")); return; } ForceFuseUntil = Time.time + 5f; Enemies.SpawnEnemy(val2, val, Quaternion.identity, false); Log.LogInfo((object)$"[Debug] Spawned a {label} at {val}."); } catch (Exception arg) { Log.LogError((object)$"[Debug] spawn error: {arg}"); } } private static EnemySetup? FindEnemySetup(string nameContains, Type componentType) { foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if ((Object)(object)allEnemy != (Object)null && ((Object)allEnemy).name.IndexOf(nameContains, StringComparison.OrdinalIgnoreCase) >= 0) { return allEnemy; } } foreach (EnemySetup allEnemy2 in Enemies.AllEnemies) { if (allEnemy2?.spawnObjects == null) { continue; } foreach (PrefabRef spawnObject in allEnemy2.spawnObjects) { GameObject val = ((PrefabRef)(object)spawnObject)?.Prefab; if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponentInChildren(componentType, true) != (Object)null) { return allEnemy2; } } } return null; } public static SemiLaser? GetClownLaserPrefab() { if (_clownLaserSearched) { return _clownLaserPrefab; } _clownLaserSearched = true; try { EnemySetup val = FindEnemySetup("Beamer", typeof(EnemyBeamer)); if (val?.spawnObjects != null) { foreach (PrefabRef spawnObject in val.spawnObjects) { GameObject val2 = ((PrefabRef)(object)spawnObject)?.Prefab; EnemyBeamer val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInChildren(true) : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val3.laser != (Object)null) { _clownLaserPrefab = val3.laser; break; } } } if ((Object)(object)_clownLaserPrefab == (Object)null) { Log.LogWarning((object)"[Deathgaze] Could not find the Clown/Beamer laser prefab; beams disabled."); } } catch (Exception arg) { Log.LogError((object)$"[Deathgaze] laser prefab lookup error: {arg}"); } return _clownLaserPrefab; } public static PrefabRef? GetMeltdownHeadPrefabRef() { if (_meltdownHeadBuilt) { return _meltdownHeadRef; } PrefabRef meltdownHeadRef = default(PrefabRef); if (NetworkPrefabs.TryGetNetworkPrefabRef("Matsu/MeltdownExtraHead", ref meltdownHeadRef)) { _meltdownHeadBuilt = true; _meltdownHeadRef = meltdownHeadRef; return _meltdownHeadRef; } _meltdownHeadBuilt = true; try { EnemySetup val = FindEnemySetup("Bomb", typeof(EnemyBombThrower)); GameObject val2 = null; if (val?.spawnObjects != null) { foreach (PrefabRef spawnObject in val.spawnObjects) { GameObject val3 = ((PrefabRef)(object)spawnObject)?.Prefab; EnemyBombThrower val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponentInChildren(true) : null); if ((Object)(object)val4 != (Object)null && (Object)(object)val4.head != (Object)null) { val2 = ((Component)val4.head).gameObject; break; } } } if ((Object)(object)val2 == (Object)null) { Log.LogWarning((object)"[MeltdownCrew] head prefab not found; extra heads disabled."); return null; } GameObject val5 = Object.Instantiate(val2); ((Object)val5).name = "MatsuMeltdownExtraHead"; Object.DontDestroyOnLoad((Object)(object)val5); val5.SetActive(false); EnemyBombThrowerHead component = val5.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } val5.AddComponent(); _meltdownHeadRef = NetworkPrefabs.RegisterNetworkPrefab("Matsu/MeltdownExtraHead", val5); if (_meltdownHeadRef == null) { Log.LogWarning((object)"[MeltdownCrew] RegisterNetworkPrefab returned null; extra heads disabled."); } else { Log.LogInfo((object)"[MeltdownCrew] Registered the extra-head network prefab."); } } catch (Exception arg) { Log.LogError((object)$"[MeltdownCrew] head prefab build error: {arg}"); } return _meltdownHeadRef; } public static void SpawnMeltdownHead(Vector3 pos, Quaternion rot, Vector3 forward, float factor) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) try { PrefabRef meltdownHeadPrefabRef = GetMeltdownHeadPrefabRef(); if (meltdownHeadPrefabRef == null) { Log.LogWarning((object)"[MeltdownCrew] no head prefab ref; skipping spawn."); return; } GameObject val = NetworkPrefabs.SpawnNetworkPrefab(meltdownHeadPrefabRef, pos, rot, (byte)0, (object[])null); if ((Object)(object)val == (Object)null) { Log.LogWarning((object)"[MeltdownCrew] SpawnNetworkPrefab returned null."); return; } val.SetActive(true); MeltdownExtraHead component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Log.LogWarning((object)"[MeltdownCrew] spawned head has no driver component."); return; } component.Launch(factor, forward); Log.LogInfo((object)$"[MeltdownCrew] spawned extra head (factor {factor}, active={val.activeSelf}) at {pos}."); } catch (Exception arg) { Log.LogError((object)$"[MeltdownCrew] spawn head error: {arg}"); } } public void StartBalloonChain(List balloons, int damage, GameObject? popEffect) { if (balloons != null && balloons.Count != 0 && SemiFunc.IsMasterClientOrSingleplayer()) { ((MonoBehaviour)this).StartCoroutine(BalloonChainRoutine(balloons, damage, popEffect)); } } private IEnumerator BalloonChainRoutine(List balloons, int damage, GameObject? popEffect) { foreach (GameObject balloon in balloons) { if ((Object)(object)balloon != (Object)null) { Vector3 position = balloon.transform.position; FusionShared.ExplodeAuthoritative(position, 0.7f, damage, 0); if ((Object)(object)popEffect != (Object)null) { Object.Instantiate(popEffect, position, Quaternion.identity); } Object.Destroy((Object)(object)balloon); } yield return (object)new WaitForSeconds(0.1f); } } } [HarmonyPatch(typeof(EnemyParent), "Spawn")] internal static class EnemyParent_Spawn_Patch { private static void Postfix(EnemyParent __instance) { MutationAttach.TryAttach(__instance); } } [HarmonyPatch(typeof(EnemyParent), "SpawnRPC")] internal static class EnemyParent_SpawnRPC_Patch { private static void Postfix(EnemyParent __instance) { MutationAttach.TryAttach(__instance); } } internal static class MutationAttach { private static float _boomdayPity; private static float _poltergeistPity; private static float _cleanupPity; private static float _snatcherPity; private static float _deathgazePity; private static int _boomdayPityLevel = -1; private static int _poltergeistPityLevel = -1; private static int _cleanupPityLevel = -1; private static int _snatcherPityLevel = -1; private static int _deathgazePityLevel = -1; private static bool _boomdayMutatedThisLevel; private static bool _poltergeistMutatedThisLevel; private static bool _cleanupMutatedThisLevel; private static bool _snatcherMutatedThisLevel; private static bool _deathgazeMutatedThisLevel; private static readonly Dictionary _boomdayMutatedIds = new Dictionary(); private static readonly Dictionary _poltergeistMutatedIds = new Dictionary(); private static readonly Dictionary _cleanupMutatedIds = new Dictionary(); private static readonly Dictionary _snatcherMutatedIds = new Dictionary(); private static readonly Dictionary _deathgazeMutatedIds = new Dictionary(); public static void TryAttach(EnemyParent __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } bool flag = Time.time <= Plugin.ForceFuseUntil; int key = EnemyId(__instance); EnemyBirthdayBoy componentInChildren = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { float chance = (flag ? 1f : GetMutationChance(ref _boomdayPity, ref _boomdayPityLevel, ref _boomdayMutatedThisLevel, _boomdayMutatedIds)); bool value; bool flag2 = _boomdayMutatedIds.TryGetValue(key, out value) && value; if ((Object)(object)((Component)componentInChildren).GetComponent() == (Object)null && (flag2 || ShouldMutate(__instance, chance))) { ((Component)componentInChildren).gameObject.AddComponent(); _boomdayMutatedThisLevel = true; _boomdayPity = 0f; _boomdayMutatedIds[key] = true; Plugin.Log.LogInfo((object)"[BoomdayBoy] A Birthday Boy became a Boomday Boy."); } return; } EnemyFloater componentInChildren2 = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren2 != (Object)null) { float chance2 = (flag ? 1f : GetMutationChance(ref _poltergeistPity, ref _poltergeistPityLevel, ref _poltergeistMutatedThisLevel, _poltergeistMutatedIds)); bool value2; bool flag3 = _poltergeistMutatedIds.TryGetValue(key, out value2) && value2; if ((Object)(object)((Component)componentInChildren2).GetComponent() == (Object)null && (flag3 || ShouldMutate(__instance, chance2))) { ((Component)componentInChildren2).gameObject.AddComponent(); _poltergeistMutatedThisLevel = true; _poltergeistPity = 0f; _poltergeistMutatedIds[key] = true; Plugin.Log.LogInfo((object)"[Poltergeist] A Mentalist mutated into a Poltergeist."); } return; } EnemyBombThrower componentInChildren3 = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren3 != (Object)null) { float chance3 = (flag ? 1f : GetMutationChance(ref _cleanupPity, ref _cleanupPityLevel, ref _cleanupMutatedThisLevel, _cleanupMutatedIds)); bool value3; bool flag4 = _cleanupMutatedIds.TryGetValue(key, out value3) && value3; if ((Object)(object)((Component)componentInChildren3).GetComponent() == (Object)null && (flag4 || ShouldMutate(__instance, chance3))) { ((Component)componentInChildren3).gameObject.AddComponent(); _cleanupMutatedThisLevel = true; _cleanupPity = 0f; _cleanupMutatedIds[key] = true; Plugin.Log.LogInfo((object)"[MeltdownCrew] A Cleanup Crew mutated into a Meltdown Crew."); } return; } EnemyHidden componentInChildren4 = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren4 != (Object)null) { float chance4 = (flag ? 1f : GetMutationChance(ref _snatcherPity, ref _snatcherPityLevel, ref _snatcherMutatedThisLevel, _snatcherMutatedIds)); bool value4; bool flag5 = _snatcherMutatedIds.TryGetValue(key, out value4) && value4; if ((Object)(object)((Component)componentInChildren4).GetComponent() == (Object)null && (flag5 || ShouldMutate(__instance, chance4))) { ((Component)componentInChildren4).gameObject.AddComponent(); _snatcherMutatedThisLevel = true; _snatcherPity = 0f; _snatcherMutatedIds[key] = true; Plugin.Log.LogInfo((object)"[Snatcher] A Hidden mutated into a Snatcher."); } return; } EnemyCeilingEye componentInChildren5 = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren5 != (Object)null) { float chance5 = (flag ? 1f : GetMutationChance(ref _deathgazePity, ref _deathgazePityLevel, ref _deathgazeMutatedThisLevel, _deathgazeMutatedIds)); bool value5; bool flag6 = _deathgazeMutatedIds.TryGetValue(key, out value5) && value5; if ((Object)(object)((Component)componentInChildren5).GetComponent() == (Object)null && (flag6 || ShouldMutate(__instance, chance5))) { ((Component)componentInChildren5).gameObject.AddComponent(); _deathgazeMutatedThisLevel = true; _deathgazePity = 0f; _deathgazeMutatedIds[key] = true; Plugin.Log.LogInfo((object)"[Deathgaze] A Peeper mutated into a Deathgaze."); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Mutation] attach error: {arg}"); } } private static float GetMutationChance(ref float pity, ref int lastLevel, ref bool mutatedThisLevel, Dictionary mutatedIds) { RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null) { return 0f; } int num = instance.levelsCompleted + 1; if (lastLevel == -1) { lastLevel = num; } else if (num != lastLevel) { if (mutatedThisLevel) { pity = 0f; } else { pity += (float)lastLevel * Plugin.MutationChancePerLevel.Value; } mutatedThisLevel = false; lastLevel = num; mutatedIds.Clear(); } return Mathf.Clamp((float)num * Plugin.MutationChancePerLevel.Value + pity, 0f, Plugin.MutationMaxChance.Value); } private static int EnemyId(EnemyParent instance) { PhotonView photonView = ((MonoBehaviourPun)instance).photonView; if (!((Object)(object)photonView != (Object)null)) { return ((Object)instance).GetInstanceID(); } return photonView.ViewID; } private static bool ShouldMutate(EnemyParent instance, float chance) { if (chance <= 0f) { return false; } if (chance >= 1f) { return true; } PhotonView photonView = ((MonoBehaviourPun)instance).photonView; if ((Object)(object)photonView == (Object)null) { return Random.value <= chance; } int num = photonView.ViewID * -1640531535; int num2 = (num ^ (num >>> 13)) * -1640531535; return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777216f < chance; } } [HarmonyPatch(typeof(EnemyBirthdayBoy), "OnDeath")] internal static class EnemyBirthdayBoy_OnDeath_Patch { private static void Postfix(EnemyBirthdayBoy __instance) { try { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { BoomdayBoyFusion component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.Detonate(); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[BoomdayBoy] OnDeath patch error: {arg}"); } } } }