using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using BoplFixedMath; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("FreezeRay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Bopl Battle ability: a ray gun that freezes whoever it hits in place.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+68449a836cee4b463c2618bb101bb08a9d84a03a")] [assembly: AssemblyProduct("FreezeRay")] [assembly: AssemblyTitle("FreezeRay")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FreezeRay { internal static class FreezableExtras { private const string ComponentName = "Sheep"; private const string MethodName = "Freeze"; private static MethodInfo cachedFreeze; private static Type cachedType; private static bool searchedForType; public static bool TryFreeze(FixTransform target) { if ((Object)(object)target == (Object)null || target.IsDestroyed) { return false; } Component val = FindFreezableComponent(((Component)target).gameObject); if ((Object)(object)val == (Object)null) { return false; } MethodInfo methodInfo = ResolveFreezeMethod(((object)val).GetType()); if (methodInfo == null) { Plugin.Log.LogInfo((object)("Freeze Ray: '" + ((Object)((Component)target).gameObject).name + "' has a Sheep component but no usable Freeze(int) method - not frozen.")); return false; } try { methodInfo.Invoke(val, new object[1] { 90 }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Freeze Ray: Sheep.Freeze threw, so it was not frozen: " + ex.Message)); return false; } FrozenObjects.Freeze(((Component)target).gameObject, 90); AudioManager.Get().Play("shrink"); Plugin.Log.LogInfo((object)("Freeze Ray: froze '" + ((Object)((Component)target).gameObject).name + "' for " + $"{90} ticks.")); return true; } private static Component FindFreezableComponent(GameObject go) { Component[] components = go.GetComponents(); foreach (Component val in components) { if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "Sheep") { return val; } } return null; } private static MethodInfo ResolveFreezeMethod(Type type) { if (searchedForType && cachedType == type) { return cachedFreeze; } searchedForType = true; cachedType = type; cachedFreeze = type.GetMethod("Freeze", new Type[1] { typeof(int) }); return cachedFreeze; } } public static class FreezeManager { private struct FreezeState { public int TicksRemaining; public bool CanUseAbilitiesBeforeFreeze; } public const int FreezeDurationTicks = 90; public const int CrackingStartsAtTicks = 36; private static readonly Dictionary frozen = new Dictionary(); public static bool IsFrozen(int playerId) { return frozen.ContainsKey(playerId); } public static int TicksRemaining(int playerId) { if (!frozen.TryGetValue(playerId, out var value)) { return 0; } return value.TicksRemaining; } public static List FrozenPlayerIds() { return new List(frozen.Keys); } public static void Freeze(int playerId) { if (frozen.TryGetValue(playerId, out var value)) { value.TicksRemaining = 90; frozen[playerId] = value; Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} freeze refreshed to {90} ticks."); } else { Player val = SafeGetPlayer(playerId); frozen[playerId] = new FreezeState { TicksRemaining = 90, CanUseAbilitiesBeforeFreeze = (val == null || val.CanUseAbilities) }; Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} frozen for {90} ticks."); } } public static void TickAll() { if (frozen.Count == 0) { return; } bool flag = GameTime.IsTimeStopped(); List list = null; foreach (int item in FrozenPlayerIds()) { if (!flag || !GameTime.IsTimeStoppedFor(item)) { Player val = SafeGetPlayer(item); if (val != null) { val.CanUseAbilities = false; } FreezeState value = frozen[item]; value.TicksRemaining--; if (value.TicksRemaining <= 0) { (list ?? (list = new List())).Add(item); } else { frozen[item] = value; } } } if (list == null) { return; } foreach (int item2 in list) { Thaw(item2, "freeze expired"); } } public static void ClearAll() { if (frozen.Count == 0) { return; } Plugin.Log.LogInfo((object)$"Freeze Ray: clearing {frozen.Count} active freeze(s) on round reset."); foreach (int item in FrozenPlayerIds()) { Thaw(item, "round reset"); } } public static void Clear(int playerId) { if (frozen.ContainsKey(playerId)) { Thaw(playerId, "player died"); } } private static void Thaw(int playerId, string reason) { if (frozen.TryGetValue(playerId, out var value)) { frozen.Remove(playerId); Player val = SafeGetPlayer(playerId); if (val == null) { Plugin.Log.LogInfo((object)($"Freeze Ray: player {playerId} thawed ({reason}), but the Player object " + "was gone so CanUseAbilities was not restored.")); return; } val.CanUseAbilities = value.CanUseAbilitiesBeforeFreeze; Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} thawed ({reason})."); } } private static Player SafeGetPlayer(int playerId) { PlayerHandler val = PlayerHandler.Get(); if (val != null) { return val.GetPlayer(playerId); } return null; } } [HarmonyPatch(typeof(Updater), "TickSimulation")] public static class FreezeTickPatch { public static void Postfix() { FreezeManager.TickAll(); FrozenObjects.Tick(); FreezeVisuals.Sync(); } } [HarmonyPatch(typeof(SlimeController), "isAbilityCastable")] public static class FreezeBlockCastPatch { public static bool Prefix(SlimeController __instance, ref bool __result) { if (!FreezeManager.IsFrozen(__instance.GetPlayerId())) { return true; } __result = false; return false; } } internal static class FreezeGate { public static bool IsFrozen(PlayerPhysics physics) { IPlayerIdHolder component = ((Component)physics).GetComponent(); if (component != null) { return FreezeManager.IsFrozen(component.GetPlayerId()); } return false; } } [HarmonyPatch(typeof(PlayerPhysics), "Move")] public static class FreezeSuppressMovePatch { public static bool Prefix(PlayerPhysics __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!FreezeGate.IsFrozen(__instance)) { return true; } __instance.groundedSpeed = Fix.Zero; return false; } } [HarmonyPatch(typeof(PlayerPhysics), "UpdateSim")] public static class FreezeSuppressUpdateSimPatch { public static bool Prefix(PlayerPhysics __instance) { return !FreezeGate.IsFrozen(__instance); } } [HarmonyPatch(typeof(PlayerBody), "UpdateSim")] public static class FreezeHoldBodyStillPatch { public static void Prefix(PlayerBody __instance) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0029: Unknown result type (might be due to invalid IL or missing references) IPlayerIdHolder component = ((Component)__instance).GetComponent(); if (component != null && FreezeManager.IsFrozen(component.GetPlayerId())) { __instance.selfImposedVelocity = Vec2.zero; __instance.externalVelocity = Vec2.zero; } } } [HarmonyPatch(typeof(PlayerHandler), "ResetForNextStage")] public static class FreezeResetOnStagePatch { public static void Prefix() { FreezeManager.ClearAll(); FrozenObjects.ClearAll(); FreezeVisuals.DestroyAll(); } } [HarmonyPatch(typeof(Player), "Kill")] public static class FreezeClearOnDeathPatch { public static void Prefix(Player __instance) { FreezeManager.Clear(__instance.Id); } } public static class FreezeRayAbility { public const string AbilityName = "freezeray"; public const int CooldownSeconds = 3; public const float IconScale = 0.85f; private const string TemplateNameFragment = "grow"; public static bool IsFreezeRay(GameObject go) { if ((Object)(object)go != (Object)null) { return ((Object)go).name.ToLower().Contains("freezeray"); } return false; } public static Sprite LoadIcon(Sprite template) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_008a: 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_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0249: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_016d: 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_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("FreezeRay.AbilityIcon.png"); if (stream == null) { Plugin.Log.LogError((object)"Freeze Ray: embedded resource 'FreezeRay.AbilityIcon.png' not found; falling back to the cloned ability's own icon."); return null; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(1, 1); if (!ImageConversion.LoadImage(val, array)) { Plugin.Log.LogError((object)"Freeze Ray: embedded icon failed to decode as a PNG; falling back to the cloned ability's own icon."); return null; } float num = 100f; if ((Object)(object)template != (Object)null) { Rect val2 = template.rect; if (((Rect)(ref val2)).width > 0f) { float pixelsPerUnit = template.pixelsPerUnit; float num2 = ((Texture)val).width; val2 = template.rect; num = pixelsPerUnit * (num2 / ((Rect)(ref val2)).width) / 0.85f; ManualLogSource log = Plugin.Log; string text = $"Freeze Ray: icon built at {num:0.#} pixels/unit to match the "; val2 = template.rect; log.LogInfo((object)(text + $"cloned ability ({((Rect)(ref val2)).width:0}px at {template.pixelsPerUnit:0.#}).")); ManualLogSource log2 = Plugin.Log; string[] obj = new string[8] { "Freeze Ray: [icon-bg] template texture '", ((Object)template.texture).name, "' ", $"{((Texture)template.texture).width}x{((Texture)template.texture).height}, ", $"textureRect {template.textureRect}, ", null, null, null }; val2 = template.textureRect; obj[5] = $"centre ({((Rect)(ref val2)).center.x / (float)((Texture)template.texture).width:0.###}, "; val2 = template.textureRect; obj[6] = $"{((Rect)(ref val2)).center.y / (float)((Texture)template.texture).height:0.###}) "; obj[7] = $"| ours {((Texture)val).width}x{((Texture)val).height}, centre (0.5, 0.5)"; log2.LogInfo((object)string.Concat(obj)); goto IL_0221; } } Plugin.Log.LogWarning((object)"Freeze Ray: could not read the cloned ability's sprite scale, so the icon uses Unity's default 100 pixels/unit and may look oversized."); goto IL_0221; IL_0221: return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), num); } } [HarmonyPatch(typeof(AbilityGrid), "Awake")] public static class AbilityInjectionPatch { private static bool hasInjected; public static void Prefix(AbilityGrid __instance) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0073: 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_0096: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_0147: 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 (hasInjected) { return; } NamedSpriteList abilityIcons = __instance.abilityIcons; if ((Object)(object)abilityIcons == (Object)null || abilityIcons.sprites == null) { Plugin.Log.LogWarning((object)"Freeze Ray: AbilityGrid.abilityIcons was empty this Awake; not injecting yet (will retry on the next grid build)."); return; } NamedSprite val = default(NamedSprite); bool flag = false; foreach (NamedSprite sprite in abilityIcons.sprites) { if (sprite.name != null && sprite.name.ToLower().Contains("grow")) { val = sprite; flag = true; break; } } if (!flag || (Object)(object)val.associatedGameObject == (Object)null) { Plugin.Log.LogError((object)"Freeze Ray: could not find the native grow ray to clone, so the ability was not added. (Looked for an ability whose name contains 'grow' in AbilityGrid.abilityIcons.)"); return; } GameObject val2 = Object.Instantiate(val.associatedGameObject); Object.DontDestroyOnLoad((Object)(object)val2); ((Object)val2).name = "freezeray"; Ability component = val2.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)"Freeze Ray: the cloned ray has no Ability component, so its cooldown could not be set; it will keep the grow ray's cooldown."); } else { component.Cooldown = (Fix)3L; } Sprite val3 = FreezeRayAbility.LoadIcon(val.sprite) ?? val.sprite; abilityIcons.sprites.Add(new NamedSprite("freezeray", val3, val2, true)); hasInjected = true; Plugin.Log.LogInfo((object)("Freeze Ray: ability injected into the select grid " + $"(cloned '{val.name}', cooldown {3}s).")); } } public static class FreezeVisuals { private const float CubeWorldSize = 2.2f; private const float CubeSizeVsPlayer = 1.45f; public const float CubeSizeVsTarget = 1.09f; private const int StageCount = 4; private static Sprite[] stages; private static bool loadAttempted; private static bool loadFailed; private static bool announced; private static readonly Dictionary cubes = new Dictionary(); private static readonly Dictionary targets = new Dictionary(); private static readonly Dictionary cachedIsSlime = new Dictionary(); private static readonly Dictionary objectCubes = new Dictionary(); public static void Sync() { if (loadFailed) { return; } if (!loadAttempted) { loadAttempted = true; if (!LoadStages()) { loadFailed = true; return; } Plugin.Log.LogInfo((object)$"Freeze Ray: ice visuals ready ({4} stages loaded)."); } foreach (int item in FreezeManager.FrozenPlayerIds()) { if (!cubes.TryGetValue(item, out var value) || (Object)(object)value == (Object)null) { value = CreateCube(); cubes[item] = value; } PositionCube(item, value); } SyncObjectCubes(); List list = null; foreach (KeyValuePair cube in cubes) { if (!FreezeManager.IsFrozen(cube.Key)) { (list ?? (list = new List())).Add(cube.Key); } } if (list == null) { return; } foreach (int item2 in list) { GameObject val = cubes[item2]; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } cubes.Remove(item2); targets.Remove(item2); cachedIsSlime.Remove(item2); } } private static void SyncObjectCubes() { //IL_006b: 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) foreach (int item in FrozenObjects.FrozenIds()) { if (FrozenObjects.TryGet(item, out var target, out var renderer, out var cubeWidth)) { if (!objectCubes.TryGetValue(item, out var value) || (Object)(object)value == (Object)null) { value = CreateCube(); objectCubes[item] = value; } value.SetActive(true); value.transform.position = target.transform.position; float num = cubeWidth / 2.2f; value.transform.localScale = new Vector3(num, num, 1f); SpriteRenderer component = value.GetComponent(); if ((Object)(object)renderer != (Object)null) { ((Renderer)component).sortingLayerID = ((Renderer)renderer).sortingLayerID; ((Renderer)component).sortingOrder = ((Renderer)renderer).sortingOrder + 1; } else { ((Renderer)component).sortingOrder = 1000; } component.sprite = stages[StageForRemainingTicks(FrozenObjects.TicksRemaining(item))]; } } List list = null; foreach (KeyValuePair objectCube in objectCubes) { if (!FrozenObjects.IsFrozen(objectCube.Key)) { (list ?? (list = new List())).Add(objectCube.Key); } } if (list == null) { return; } foreach (int item2 in list) { if ((Object)(object)objectCubes[item2] != (Object)null) { Object.Destroy((Object)(object)objectCubes[item2]); } objectCubes.Remove(item2); } } public static void DestroyAll() { foreach (KeyValuePair cube in cubes) { if ((Object)(object)cube.Value != (Object)null) { Object.Destroy((Object)(object)cube.Value); } } foreach (KeyValuePair objectCube in objectCubes) { if ((Object)(object)objectCube.Value != (Object)null) { Object.Destroy((Object)(object)objectCube.Value); } } objectCubes.Clear(); cubes.Clear(); targets.Clear(); cachedIsSlime.Clear(); } private static GameObject CreateCube() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown GameObject val = new GameObject("FreezeRayIceCube"); val.AddComponent().sprite = stages[0]; if (!announced) { announced = true; Plugin.Log.LogInfo((object)"Freeze Ray: first ice block spawned."); } return val; } private static void PositionCube(int playerId, GameObject cube) { //IL_0033: 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) bool isSlime; SpriteRenderer val = ResolveTarget(playerId, out isSlime); if ((Object)(object)val == (Object)null) { cube.SetActive(false); return; } cube.SetActive(true); SpriteRenderer component = cube.GetComponent(); cube.transform.position = ((Component)val).transform.position; float num = Mathf.Max(0.01f, PlayerScaleOf(playerId)) * 1.45f; cube.transform.localScale = new Vector3(num, num, 1f); ((Renderer)component).sortingLayerID = ((Renderer)val).sortingLayerID; ((Renderer)component).sortingOrder = ((Renderer)val).sortingOrder + 1; component.sprite = stages[StageForRemainingTicks(FreezeManager.TicksRemaining(playerId))]; } private static float PlayerScaleOf(int playerId) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) PlayerHandler val = PlayerHandler.Get(); Player val2 = ((val == null) ? null : val.GetPlayer(playerId)); if (val2 != null) { return (float)val2.Scale; } return 1f; } private static SpriteRenderer ResolveTarget(int playerId, out bool isSlime) { isSlime = false; if (targets.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && ((Component)value).gameObject.activeInHierarchy) { cachedIsSlime.TryGetValue(playerId, out isSlime); return value; } SpriteRenderer val = null; bool flag = false; SlimeController[] array = Object.FindObjectsOfType(); foreach (SlimeController val2 in array) { if (val2.GetPlayerId() == playerId) { SpriteRenderer playerSprite = val2.GetPlayerSprite(); if ((Object)(object)playerSprite != (Object)null && ((Component)playerSprite).gameObject.activeInHierarchy) { val = playerSprite; flag = true; break; } } } if ((Object)(object)val == (Object)null) { Ability[] array2 = Object.FindObjectsOfType(); foreach (Ability val3 in array2) { if (val3.GetPlayerId() == playerId) { SpriteRenderer component = ((Component)val3).GetComponent(); if ((Object)(object)component != (Object)null && ((Component)component).gameObject.activeInHierarchy) { val = component; break; } } } } targets[playerId] = val; cachedIsSlime[playerId] = flag; isSlime = flag; if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)($"Freeze Ray: no active sprite found for frozen player {playerId}; " + "hiding their ice block this tick.")); } return val; } private static int StageForRemainingTicks(int remaining) { if (remaining > 36) { return 0; } int num = 12; if (num < 1) { num = 1; } return Mathf.Clamp(3 - remaining / num, 0, 3); } private static bool LoadStages() { //IL_0066: 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) Sprite[] array = (Sprite[])(object)new Sprite[4]; for (int i = 0; i < 4; i++) { string text = $"FreezeRay.IceCube{i}.png"; Texture2D val = LoadTexture(text); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Freeze Ray: could not load embedded '" + text + "', so frozen players will have no visible ice. The freeze itself still works.")); return false; } array[i] = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width / 2.2f); } stages = array; return true; } private static Texture2D LoadTexture(string resourceName) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); if (stream == null) { return null; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(1, 1); return ImageConversion.LoadImage(val, array) ? val : null; } } public static class FrozenObjects { private class Entry { public GameObject Target; public SpriteRenderer Renderer; public int TicksRemaining; public float CubeWidth; } private static readonly Dictionary frozen = new Dictionary(); public static void Freeze(GameObject target, int ticks) { //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) //IL_0042: 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_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return; } int instanceID = ((Object)target).GetInstanceID(); if (frozen.TryGetValue(instanceID, out var value)) { value.TicksRemaining = ticks; return; } SpriteRenderer componentInChildren = target.GetComponentInChildren(); float num; if (!((Object)(object)componentInChildren == (Object)null)) { Bounds bounds = ((Renderer)componentInChildren).bounds; float x = ((Bounds)(ref bounds)).size.x; bounds = ((Renderer)componentInChildren).bounds; num = Mathf.Max(x, ((Bounds)(ref bounds)).size.y); } else { num = 2f; } float num2 = num; frozen[instanceID] = new Entry { Target = target, Renderer = componentInChildren, TicksRemaining = ticks, CubeWidth = Mathf.Max(0.5f, num2 * 1.09f) }; } public static void Tick() { if (frozen.Count == 0) { return; } List list = null; foreach (KeyValuePair item in frozen) { Entry value = item.Value; if ((Object)(object)value.Target == (Object)null || --value.TicksRemaining <= 0) { (list ?? (list = new List())).Add(item.Key); } } if (list == null) { return; } foreach (int item2 in list) { frozen.Remove(item2); } } public static List FrozenIds() { return new List(frozen.Keys); } public static bool TryGet(int id, out GameObject target, out SpriteRenderer renderer, out float cubeWidth) { if (frozen.TryGetValue(id, out var value) && (Object)(object)value.Target != (Object)null) { target = value.Target; renderer = value.Renderer; cubeWidth = value.CubeWidth; return true; } target = null; renderer = null; cubeWidth = 0f; return false; } public static bool IsFrozen(int id) { if (frozen.TryGetValue(id, out var value)) { return (Object)(object)value.Target != (Object)null; } return false; } public static int TicksRemaining(int id) { if (!frozen.TryGetValue(id, out var value)) { return 0; } return value.TicksRemaining; } public static void ClearAll() { frozen.Clear(); } } [BepInPlugin("com.maha.boplbattle.freezeray", "Freeze Ray", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.maha.boplbattle.freezeray"; public const string PluginName = "Freeze Ray"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Freeze Ray: loading..."); new Harmony("com.maha.boplbattle.freezeray").PatchAll(); Log.LogInfo((object)"Freeze Ray: Harmony patches applied."); Log.LogInfo((object)($"Freeze Ray: loaded (freeze {90} ticks / " + $"{1.5f:0.##}s, cooldown {3}s).")); } } [HarmonyPatch(typeof(ShootScaleChange), "ApplyScaleChange")] public static class FreezeOnHitPatch { public static bool Prefix(ShootScaleChange __instance, RaycastInformation hit, Vec2 firepoint, Vec2 direction, ref bool hasFired, int playerId) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!FreezeRayAbility.IsFreezeRay(((Component)__instance).gameObject)) { return true; } if (hit.layer == LayerMask.NameToLayer("Water")) { return true; } __instance.spawnRayCastEffect((Vector2)firepoint, (Vector2)direction, (float)hit.nearDist, true, false); if (hit.layer != LayerMask.NameToLayer("Player")) { if (!FreezableExtras.TryFreeze(hit.pp.fixTrans)) { Plugin.Log.LogInfo((object)("Freeze Ray: beam hit layer '" + LayerMask.LayerToName(hit.layer) + "', which is not a player - no freeze applied.")); } hasFired = true; return false; } FixTransform fixTrans = hit.pp.fixTrans; if ((Object)(object)fixTrans == (Object)null || fixTrans.IsDestroyed) { Plugin.Log.LogInfo((object)"Freeze Ray: hit a player-layer collider whose FixTransform was already destroyed - no freeze applied."); hasFired = true; return false; } IPlayerIdHolder component = ((Component)fixTrans).GetComponent(); if (component == null) { if (!FreezableExtras.TryFreeze(fixTrans)) { Plugin.Log.LogInfo((object)("Freeze Ray: hit '" + ((Object)((Component)fixTrans).gameObject).name + "' on the Player layer, but it has no IPlayerIdHolder so its owner is unknown - no freeze applied.")); } hasFired = true; return false; } FreezeManager.Freeze(component.GetPlayerId()); AudioManager.Get().Play("shrink"); hasFired = true; return false; } } [HarmonyPatch(typeof(ShootScaleChange), "spawnRayCastEffect")] public static class BeamTintPatch { private static readonly Color IceBlue = new Color(0.35f, 0.8f, 1f, 1f); public static void Prefix(ShootScaleChange __instance) { if (FreezeRayAbility.IsFreezeRay(((Component)__instance).gameObject)) { Tint(Traverse.Create((object)__instance).Field("rayParticle").GetValue()); Tint(Traverse.Create((object)__instance).Field("hitParticle").GetValue()); } } private static void Tint(ParticleSystem system) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0026: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)system == (Object)null)) { ParticleSystem[] componentsInChildren = ((Component)system).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { MainModule main = componentsInChildren[i].main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(IceBlue); } } } } }