Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of BoplPlus24 v1.0.0
plugins\BoplPlus24\BoplPlus24.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BoplFixedMath; using HarmonyLib; using Mayhem.Abilities; using Mayhem.Core; using Mayhem.Testing; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BoplPlus24")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BoplPlus24")] [assembly: AssemblyTitle("BoplPlus24")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Mayhem { [BepInPlugin("com.boplmayhem.mayhem", "BoplPlus24", "1.0.0")] [BepInProcess("BoplBattle.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.boplmayhem.mayhem"; public const string DisplayName = "BoplPlus24"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static Plugin Instance; private void Awake() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; try { MayhemConfig.Load(((BaseUnityPlugin)this).Config); DevConsole.Bind(((BaseUnityPlugin)this).Config); AbilityCatalog.Discover(typeof(Plugin).Assembly); AbilityCatalog.BindConfig(((BaseUnityPlugin)this).Config); MayhemConfig.ComputeFingerprint(); AbilityRegistry.Build(); new Harmony("com.boplmayhem.mayhem").PatchAll(typeof(Plugin).Assembly); AbilityRegistry.TryInjectIntoLoadedLists(); DevConsole.CreateIfEnabled(); Log.LogInfo((object)string.Format("{0} {1} loaded: {2} abilities enabled, lobby tag '{3}'.", "BoplPlus24", "1.0.0", AbilityRegistry.Enabled.Count, MayhemConfig.VersionTag)); } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed to initialise; the game will run unmodded. {1}", "BoplPlus24", arg)); } } } } namespace Mayhem.Testing { public sealed class DevConsole : MonoBehaviour { private sealed class SelfDestruct : MonoBehaviour { public float Seconds = 5f; private void Update() { if ((Seconds -= Time.deltaTime) <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); } } } public static ConfigEntry<bool> Enabled; public static DevConsole Instance; private float pollTimer; private static string CommandFile => Path.Combine(Paths.BepInExRootPath, "mayhem_cmd.txt"); public static string OutDir => Path.Combine(Paths.BepInExRootPath, "mayhem_dev"); public static void Bind(ConfigFile cfg) { Enabled = cfg.Bind<bool>("Dev", "EnableDevTools", false, "Developer tools (command file, bots, checksum logs). Leave off for normal play."); } public static void CreateIfEnabled() { if (Enabled.Value) { Directory.CreateDirectory(OutDir); Application.runInBackground = true; Stats.Enabled = true; Plugin.Log.LogWarning((object)"Mayhem dev tools are enabled."); SceneManager.sceneLoaded += delegate { Ensure(); }; Ensure(); } } private static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("Mayhem.DevConsole"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent<DevConsole>(); } } private void Start() { Plugin.Log.LogInfo((object)"DevConsole started"); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { LocalMatch.Pump(Time.unscaledDeltaTime); pollTimer -= Time.unscaledDeltaTime; if (pollTimer > 0f) { return; } pollTimer = 0.25f; if (!File.Exists(CommandFile)) { return; } string[] array; try { array = File.ReadAllLines(CommandFile); File.Delete(CommandFile); } catch (IOException) { return; } string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i].Trim(); if (text.Length != 0 && !text.StartsWith("#")) { try { Run(text); } catch (Exception arg) { Plugin.Log.LogError((object)$"dev command '{text}' failed: {arg}"); } } } } private void Run(string line) { //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)("dev> " + line)); string[] array = line.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Scene val; switch (array[0].ToLowerInvariant()) { case "shot": { string text = ((array.Length > 1) ? array[1] : DateTime.Now.ToString("HHmmss")); ScreenCapture.CaptureScreenshot(Path.Combine(OutDir, text + ".png")); break; } case "test": ChecksumLog.Open(Path.Combine(OutDir, array[3])); SelfTest.Muted = true; LocalMatch.RoundsLeft = int.Parse(array[2]); LocalMatch.QuitWhenDone = true; LocalMatch.Start(uint.Parse(array[1]), 0, Slice(array, 4)); break; case "local": LocalMatch.Start(uint.Parse(array[1]), int.Parse(array[2]), (array.Length > 3) ? Slice(array, 3) : new string[0]); break; case "bots": Bots.Active = array.Length < 2 || array[1] != "off"; break; case "human": Bots.HumanPlayer = ((array.Length <= 1) ? 1 : int.Parse(array[1])); break; case "checksums": ChecksumLog.Open((array.Length > 1) ? Path.Combine(OutDir, array[1]) : null); break; case "scenarios": Scenarios.Start((array.Length > 1) ? string.Join(" ", Slice(array, 1)) : null); break; case "scene": SceneManager.LoadScene(array[1]); break; case "grid": { AbilityGrid[] array2 = Resources.FindObjectsOfTypeAll<AbilityGrid>(); foreach (AbilityGrid val2 in array2) { val = ((Component)val2).gameObject.scene; if (((Scene)(ref val)).IsValid()) { ((Component)val2).gameObject.SetActive(true); val2.Init(true, (Gamepad)null, (array.Length <= 1) ? 1 : int.Parse(array[1])); Plugin.Log.LogInfo((object)$"grid opened: {val2.abilityIcons.sprites.Count - 1} entries, {val2.columns} columns"); break; } } break; } case "god": LocalMatch.GodMode = array.Length < 2 || array[1] != "off"; break; case "timescale": Time.timeScale = float.Parse(array[1], CultureInfo.InvariantCulture); break; case "nextlevel": LocalMatch.ForceNextLevel((array.Length > 1) ? int.Parse(array[1]) : (-1)); break; case "list": { NamedSpriteList fullList = AbilityRegistry.FullList; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < fullList.sprites.Count; i++) { stringBuilder.Append(i).Append(':').Append(fullList.sprites[i].name) .Append(" "); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); break; } case "scenes": { ManualLogSource log = Plugin.Log; object arg = SceneManager.sceneCountInBuildSettings; val = SceneManager.GetActiveScene(); log.LogInfo((object)$"scenes in build: {arg}, active: {((Scene)(ref val)).name}"); break; } case "fxtest": FxTest(); break; case "quit": LocalMatch.RestoreSettings(); ChecksumLog.Close(); Application.Quit(); break; default: Plugin.Log.LogWarning((object)("unknown dev command: " + array[0])); break; } } private static void FxTest() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0168: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) Player player = PlayerHandler.Get().GetPlayer(1); Vector2 val = ((player != null) ? ((Vector2)player.Position + new Vector2(-6f, 3f)) : Vector2.zero); Color val2 = ((player != null) ? Fx.PlayerColor(player.Color) : Color.yellow); string[] array = new string[22] { "orb", "portal", "coin", "hook", "cuff", "link", "planet", "pebble", "mitt", "bomb_flip", "spark", "potato", "pinata", "pad", "magnet", "anvil", "pushpin", "clamp", "streak", "confetti", "arrowhead", "bubble" }; GameObject val3 = new GameObject("Mayhem.FxTest"); val3.AddComponent<SelfDestruct>().Seconds = 6f; for (int i = 0; i < array.Length; i++) { Art.Add(val3, array[i], val2, 1f, "effect", 30).Root.position = Vector2.op_Implicit(val + new Vector2((float)(i % 8) * 1.8f, (float)(-(i / 8)) * 2f)); } string[] array2 = new string[6] { "SmokeBombSmoke", "SideSmoke", "RollWave", "Shockwave4C", "gruondrubble", "RocketEngineFire2" }; foreach (string text in array2) { Plugin.Log.LogInfo((object)$"fxtest: sheet {text} has {Flipbook.Frames(text).Length} frames"); } Vector2 val4 = val + new Vector2(0f, -7f); Vfx.Poof(val4); Vfx.Dust(val4 + new Vector2(3f, 0f), Vector2.up); Vfx.GroundWave(val4 + new Vector2(7f, 0f), Vector2.up); Vfx.Shock(val4 + new Vector2(11f, 0f), 2.5f, 2f); Vfx.Rubble(val4 + new Vector2(14f, 0f), Vector2.up, 5); Vfx.Confetti(val4 + new Vector2(17f, 0f), val2, 12, 9f); ReachFlash.Show(val4 + new Vector2(20f, 0f), 2f, val2); } private static string[] Slice(string[] a, int from) { string[] array = new string[a.Length - from]; Array.Copy(a, from, array, 0, array.Length); return array; } } public static class LocalMatch { public static bool Running; public static uint Seed = 1234u; public static int Round; public static int RoundsLeft = -1; public static bool QuitWhenDone; public static bool GodMode; private static int savedAbilityCount = -1; private static float endedFor; public static int MaxRoundSeconds = 45; public static void RestoreSettings() { if (savedAbilityCount >= 0) { Settings.Get().NumberOfAbilities = savedAbilityCount; } savedAbilityCount = -1; } internal static void Pump(float dt) { //IL_0026: 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) if (!Running || RoundsLeft < 0) { return; } bool flag = (Object)(object)GameSessionHandler.selfRef != (Object)null && GameSessionHandler.HasGameEnded(); bool flag2 = Updater.SimTimeSinceLevelLoaded > (Fix)(long)MaxRoundSeconds; if (!flag && !flag2) { endedFor = 0f; return; } endedFor += dt; if (endedFor < 1f) { return; } endedFor = 0f; RoundsLeft--; Plugin.Log.LogInfo((object)string.Format("round {0} finished ({1}), {2} left", Round, flag ? "winner" : "timeout", RoundsLeft)); Plugin.Log.LogInfo((object)("stats: " + Stats.Dump())); if (RoundsLeft <= 0) { Running = false; RestoreSettings(); ChecksumLog.Close(); if (QuitWhenDone) { Application.Quit(); } } else { Round++; LoadLevel(Round * 7); } } public static void Start(uint seed, int level, string[] playerAbilities) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0081: 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_009b: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) Seed = seed; NamedSpriteList fullList = AbilityRegistry.FullList; PlayerColors[] array = Resources.FindObjectsOfTypeAll<PlayerColors>(); if ((Object)(object)fullList == (Object)null || array.Length == 0) { throw new InvalidOperationException("game assets not loaded yet - open the main menu first"); } List<Player> list = PlayerHandler.Get().PlayerList(); list.Clear(); int num = Mathf.Clamp(playerAbilities.Length, 2, 4); for (int i = 0; i < num; i++) { Player val = new Player(i + 1, i) { Color = array[0].playerColors[i].playerMaterial, UsesKeyboardAndMouse = true, CanUseAbilities = true, Abilities = new List<GameObject>(3), AbilityIcons = new List<Sprite>(3) }; string text = ((i < playerAbilities.Length) ? playerAbilities[i] : "Random"); string[] array2 = text.Split(new char[1] { ',' }); if (array2.Length > 3) { throw new ArgumentException("at most 3 abilities per player: " + text); } string[] array3 = array2; for (int j = 0; j < array3.Length; j++) { string text2 = array3[j].Replace('_', ' '); int num2 = fullList.IndexOf(text2); if (num2 < 0) { throw new ArgumentException("unknown ability " + text2); } val.Abilities.Add(fullList.sprites[num2].associatedGameObject); val.AbilityIcons.Add(fullList.sprites[num2].sprite); } list.Add(val); } if (savedAbilityCount < 0) { savedAbilityCount = Settings.Get().TrueNumberOfAbilities; } Settings.Get().NumberOfAbilities = list[0].Abilities.Count; GameLobby.isOnlineGame = false; GameLobby.isPlayingAReplay = false; GameSession.Init(); Bots.Active = true; Running = true; Round = 0; LoadLevel(level); if (!WinnerTriangleCanvas.HasBeenSpawned) { SceneManager.LoadScene("winnerTriangle", (LoadSceneMode)1); } } public static void LoadLevel(int level) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) int num = SceneManager.sceneCountInBuildSettings - 6; byte b = (byte)((level % num + num) % num); GameSession.SetCurrentLevel(b); Updater.PreLevelLoad(); foreach (Player item in PlayerHandler.Get().PlayerList()) { item.Position = Vec2.zero; item.stillAliveThisRound = true; item.Scale = Fix.One; item.RespawnPositions.Clear(); } SceneManager.LoadScene(6 + b, (LoadSceneMode)0); Updater.PostLevelLoad(); } public static void ForceNextLevel(int level) { LoadLevel((level >= 0) ? level : (GameSession.CurrentLevel() + 1)); } } public static class Bots { public static bool Active; public static int HumanPlayer; internal static void BeforeTick() { //IL_0021: 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) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!Active || GameLobby.isOnlineGame || GameLobby.isPlayingAReplay) { return; } List<Player> list = PlayerHandler.Get().PlayerList(); int tick = (int)(long)(Updater.SimTimeSinceLevelLoaded * (Fix)60L); for (int i = 0; i < list.Count; i++) { Player val = list[i]; if (val.Id != HumanPlayer) { Drive(val, list, tick); } } } private static uint Hash(uint a, uint b, uint c, uint d) { uint num = (((((((0x811C9DC5u ^ a) * 16777619) ^ b) * 16777619) ^ c) * 16777619) ^ d) * 16777619; uint num2 = (num ^ (num >> 13)) * 1540483477; return num2 ^ (num2 >> 15); } private static void Drive(Player p, List<Player> all, int tick) { //IL_001c: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) uint seed = LocalMatch.Seed; uint id = (uint)p.Id; uint c = (uint)(tick / 24); uint num = Hash(seed, id, c, 1u); Vec2 val = Vec2.right; Fix val2 = Fix.MaxValue; for (int i = 0; i < all.Count; i++) { if (all[i] != p && all[i].IsAlive) { Fix val3 = Vec2.SqrMagnitude(all[i].Position - p.Position); if (val3 < val2) { val2 = val3; val = Vec2.NormalizedSafe(all[i].Position - p.Position); } } } byte b = InputProfile.JoyStickAngleByteFromVector(val); int num2 = (int)(Hash(seed, id, (uint)(tick / 8), 2u) % 21 - 10); b = (byte)(1 + (b - 1 + num2 + 255) % 255); int num3 = (int)(num % 5); bool flag = num3 switch { 3 => val.x < Fix.Zero, 0 => true, _ => false, }; bool flag2 = num3 switch { 3 => val.x >= Fix.Zero, 1 => true, _ => false, }; bool flag3 = Hash(seed, id, (uint)(tick / 6), 3u) % 9 == 0; bool flag4 = Hash(seed, id, c, 4u) % 11 == 0; bool flag5 = !flag4 && Hash(seed, id, c, 5u) % 4 == 0; bool[] array = new bool[3]; for (int j = 0; j < 3; j++) { uint c2 = (uint)(tick / (9 + j * 4)); array[j] = Hash(seed, id, c2, (uint)(10 + j)) % 7 == 0; } p.ForceSetInputProfile(false, false, flag3, array[0], array[1], array[2], b, flag5, flag, flag4, flag2); } } public static class ChecksumLog { private static StreamWriter writer; public static void Open(string path) { Close(); if (path != null) { writer = new StreamWriter(path, append: false, Encoding.ASCII); } } public static void Close() { writer?.Flush(); writer?.Dispose(); writer = null; } internal static void AfterTick() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (writer != null) { int num = (int)(long)(Updater.SimTimeSinceLevelLoaded * (Fix)60L); writer.Write(LocalMatch.Round); writer.Write(' '); writer.Write(num); writer.Write(' '); writer.Write(Updater.ComputeChecksum()); writer.Write(' '); writer.Write(Entity.All.Count); writer.Write('\n'); if (num % 120 == 0) { writer.Flush(); } } } } [HarmonyPatch(typeof(Updater), "TickSimulation")] internal static class TickHooks { private static void Prefix() { if (!((Object)(object)DevConsole.Instance == (Object)null)) { if (Scenarios.Running) { Scenarios.BeforeTick(); } else { Bots.BeforeTick(); } } } private static void Postfix() { if ((Object)(object)DevConsole.Instance != (Object)null) { ChecksumLog.AfterTick(); } } } [HarmonyPatch(typeof(PlayerCollision), "killPlayer")] internal static class GodMode { private static bool Prefix(ref bool __result) { if ((Object)(object)DevConsole.Instance == (Object)null || !LocalMatch.GodMode || !LocalMatch.Running || GameLobby.isOnlineGame) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Updater), "InitSeed")] internal static class FixedSeed { private static void Prefix(ref uint seed) { if ((Object)(object)DevConsole.Instance != (Object)null && LocalMatch.Running && !GameLobby.isOnlineGame) { seed = LocalMatch.Seed; } } } public static class Scenarios { private sealed class Fail : Exception { public Fail(string m) : base(m) { } } private static readonly List<(string name, Func<IEnumerator<int>> run)> all = new List<(string, Func<IEnumerator<int>>)> { ("rebound reflects arrow", Rebound), ("mitt catches and throws arrow", MittCatch), ("bubble traps arrow then pops", BubbleTrap), ("portals carry an arrow", PortalArrow), ("portals: placing the exit keeps you there", PortalExitStays), ("switcheroo swaps with arrow", SwitcherooArrow), ("orbit bends arrow", SlingshotBend), ("hijack steers arrow", HijackSteer), ("jet stream pushes arrow and player", JetStreamPush), ("polarity pulls arrow, pushes player", PolarityField), ("trampoline bounces player", TrampolineBounce), ("chain drags owner along", ChainDrag), ("bungee snaps both ends together", BungeeSnap), ("gift launches rival", GiftTrap), ("hot potato sticks, passes, explodes", PotatoFlow), ("mimic copies then restores", MimicCopyRestore), ("mimic cannot copy mimic", MimicOfMimic), ("echo ghost shoves rival", EchoShove), ("pinata bursts after hits", PinataBurst), ("shuffle swaps players", ShuffleSwap), ("anvil resists knockback and slams", AnvilSlam), ("flip bomb lifts airborne player", FlipBombLift), ("hoverpad steers", HoverpadSteer), ("turntable rotates and restores", TurntableRestore), ("piggy bank stores and releases", PiggyBankFlow), ("tractor drags platform and returns it", TractorPull), ("edge: simultaneous switcheroo", SimultaneousSwap), ("edge: caught object destroyed", CaughtDestroyed), ("edge: level change with live entities", LevelChange), ("edge: owner dies mid-chain", OwnerDiesMidChain) }; private static IEnumerator<int> current; private static int index = -1; private static int wait; private static int pass; private static int fail; private static int errorsAtStart; private static string filter; private static Vec2 home1; private static Vec2 home2; private static readonly List<string> results = new List<string>(); public static bool Running => index >= 0; public static void Start(string only) { TestKit.HookErrors(); filter = only; index = -1; pass = (fail = 0); results.Clear(); Bots.Active = false; Next(); } private static void Next() { TestKit.ReleaseAll(); TestKit.Reset(); TestKit.ClearEntities(); current = null; while (++index < all.Count) { if (string.IsNullOrEmpty(filter) || Array.Exists(filter.Split(new char[1] { ',' }), (string f) => all[index].name.Contains(f.Trim()))) { errorsAtStart = TestKit.Errors; Stats.Clear(); current = Setup(all[index].run); wait = 0; return; } } Plugin.Log.LogInfo((object)$"SCENARIOS DONE: {pass} passed, {fail} failed"); foreach (string result in results) { Plugin.Log.LogInfo((object)(" " + result)); } index = -1; } private static IEnumerator<int> Setup(Func<IEnumerator<int>> body) { int spawnWait = 0; while (!Spawned(1) || !Spawned(2)) { if (spawnWait++ > 400) { throw new Fail("need two living players (use 'god on' and a 2-player local match)"); } yield return 1; } home1 = TestKit.FindOpenSky((Fix)9L, Vec2.zero, Fix.Zero); home2 = TestKit.FindOpenSky((Fix)5L, home1, (Fix)14L); TestKit.Hold(1, home1); TestKit.Hold(2, home2); yield return 3; IEnumerator<int> inner = body(); while (inner.MoveNext()) { yield return inner.Current; } } private static bool Spawned(int id) { Player player = PlayerHandler.Get().GetPlayer(id); SlimeController val = TestKit.Slime(id); if (player != null && player.IsAlive && (Object)(object)val != (Object)null) { return val.HasSpawned; } return false; } internal static void BeforeTick() { if (!Running || current == null) { return; } if (wait > 0) { wait--; TestKit.BeforeTick(); return; } string item = all[index].name; try { if (current.MoveNext()) { wait = Math.Max(0, current.Current - 1); TestKit.BeforeTick(); return; } if (TestKit.Errors > errorsAtStart) { throw new Fail("logged error: " + TestKit.LastError); } pass++; results.Add("PASS " + item); Plugin.Log.LogInfo((object)("PASS " + item)); } catch (Fail fail) { Scenarios.fail++; results.Add("FAIL " + item + " -- " + fail.Message + " [" + Stats.Dump() + "]"); Plugin.Log.LogWarning((object)("FAIL " + item + " -- " + fail.Message)); } catch (Exception ex) { Scenarios.fail++; results.Add("FAIL " + item + " -- exception " + ex.GetType().Name + ": " + ex.Message); Plugin.Log.LogError((object)("FAIL " + item + " -- " + ex)); } Next(); } private static void Check(bool ok, string message) { if (!ok) { throw new Fail(message); } } private static string V(Vec2 v) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) return $"({(float)v.x:0.0},{(float)v.y:0.0})"; } private static Vec2 At(Fix x, Fix y) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return home1 + new Vec2(x, y); } private static Fix F(float f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return (Fix)f; } private static void Cast(int id, string ability, Vec2 aim) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) Check(TestKit.Equip(id, 0, ability), "could not equip " + ability); TestKit.Aim(id, aim); TestKit.Button(id, 0, down: true); } private static IEnumerator<int> Rebound() { TestKit.Equip(1, 0, "Rebound"); BoplBody arrow = TestKit.Arrow(At(F(5f), Fix.Zero), new Vec2(-(Fix)35L, Fix.Zero), 2); Check((Object)(object)arrow != (Object)null, "no arrow prefab"); yield return 3; TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; Check(TestKit.Vel(arrow).x > (Fix)10L, "arrow not reflected: v=" + V(TestKit.Vel(arrow))); Check(TestKit.Owner(arrow) == 1, "arrow owner not transferred: " + TestKit.Owner(arrow)); } private static IEnumerator<int> MittCatch() { Cast(1, "Mitt", Vec2.right); yield return 2; BoplBody arrow = TestKit.Arrow(At(F(7f), Fix.Zero), new Vec2(-(Fix)35L, Fix.Zero), 2); yield return 14; Check(Entity.Count<CatchMitt>(1) == 1, "mitt closed early"); Vec2 val = (((Object)(object)arrow != (Object)null && !((MonoUpdatable)arrow).IsDestroyed) ? arrow.position : Vec2.zero); Check(Vec2.Distance(val, TestKit.Pos(1)) < (Fix)3L, "arrow not held near player: " + V(val)); TestKit.Aim(1, Vec2.up); yield return 3; TestKit.Button(1, 0, down: false); yield return 2; Check(TestKit.Vel(arrow).y > (Fix)20L, "arrow not thrown upward: v=" + V(TestKit.Vel(arrow))); Check(TestKit.Owner(arrow) == 1, "thrown arrow not owned by catcher"); } private static IEnumerator<int> BubbleTrap() { Cast(1, "Bubble", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 15; List<TrapBubble> bubbles = new List<TrapBubble>(); Entity.Collect(bubbles); Check(bubbles.Count == 1, "no bubble"); Vec2 position = bubbles[0].Position; BoplBody arrow = TestKit.Arrow(position + new Vec2((Fix)6L, Fix.Zero), new Vec2(-(Fix)25L, Fix.Zero), 2); yield return 30; Vec2 position2 = arrow.position; Check(Vec2.Distance(position2, bubbles[0].Position) < bubbles[0].Radius, "arrow not inside bubble: " + V(position2) + " vs " + V(bubbles[0].Position)); TestKit.Aim(1, Vec2.up); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; Check(((MonoUpdatable)bubbles[0]).IsDestroyed, "bubble did not pop on recast"); Check(TestKit.Vel(arrow).y > (Fix)25L, "arrow not fired where the owner aimed: v=" + V(TestKit.Vel(arrow))); Check(TestKit.Owner(arrow) == 1, "popped arrow not owned by the bubble's owner: " + TestKit.Owner(arrow)); } private static IEnumerator<int> PortalArrow() { Cast(1, "Portals", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); Vec2 entrance = TestKit.Pos(1); TestKit.Hold(1, At(Fix.Zero, (Fix)9L)); yield return 3; TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); Vec2 exit = TestKit.Pos(1); TestKit.Hold(1, At(-(Fix)12L, (Fix)4L)); yield return 2; Check(Entity.Count<Portal>(1) == 2, "expected 2 portals, got " + Entity.Count<Portal>(1)); BoplBody arrow = TestKit.Arrow(entrance + new Vec2((Fix)5L, Fix.Zero), new Vec2(-(Fix)30L, Fix.Zero), 2); yield return 12; Check((Object)(object)arrow != (Object)null && !((MonoUpdatable)arrow).IsDestroyed, "arrow vanished"); Check(Vec2.Distance(arrow.position, exit) < Vec2.Distance(arrow.position, entrance), "arrow did not come out of exit: " + V(arrow.position)); } private static IEnumerator<int> PortalExitStays() { Cast(1, "Portals", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); Vec2 entrance = TestKit.Pos(1); TestKit.Hold(1, At(Fix.Zero, (Fix)9L)); yield return 3; TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); Vec2 exit = TestKit.Pos(1); TestKit.Release(1); yield return 4; Check(Entity.Count<Portal>(1) == 2, "expected 2 portals, got " + Entity.Count<Portal>(1)); Check(Vec2.Distance(TestKit.Pos(1), exit) < (Fix)3L, "caster was thrown back through the portal: at " + V(TestKit.Pos(1)) + ", exit " + V(exit) + ", entrance " + V(entrance)); } private static IEnumerator<int> SwitcherooArrow() { TestKit.Equip(1, 0, "Switcheroo"); TestKit.Arrow(At((Fix)6L, Fix.Zero), new Vec2(-(Fix)15L, Fix.Zero), 2); TestKit.Aim(1, Vec2.right); TestKit.Release(1); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 12; Check(TestKit.Pos(1).x > home1.x + (Fix)2L, "player did not swap toward arrow: " + V(TestKit.Pos(1))); } private static IEnumerator<int> SlingshotBend() { Cast(1, "Orbit", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; List<GravityWell> list = new List<GravityWell>(); Entity.Collect(list); Check(list.Count == 1, "no well"); Vec2 position = list[0].Position; BoplBody arrow = TestKit.Arrow(position + new Vec2(-(Fix)6L, (Fix)2L), new Vec2((Fix)25L, Fix.Zero), 2); yield return 14; Check(TestKit.Vel(arrow).y < -(Fix)10L, "arrow not bent toward well: v=" + V(TestKit.Vel(arrow))); } private static IEnumerator<int> HijackSteer() { BoplBody arrow = TestKit.Arrow(At((Fix)3L, Fix.Zero), new Vec2((Fix)30L, Fix.Zero), 2); yield return 1; Cast(1, "Hijack", Vec2.up); yield return 1; TestKit.Button(1, 0, down: false); yield return 30; Check(TestKit.Vel(arrow).y > (Fix)15L, "arrow not steered up: v=" + V(TestKit.Vel(arrow))); Check(TestKit.Owner(arrow) == 1, "hijacked arrow not owned"); } private static IEnumerator<int> JetStreamPush() { TestKit.Hold(2, At((Fix)5L, F(0.5f))); Cast(1, "Jet Stream", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); BoplBody arrow = TestKit.Arrow(At((Fix)3L, -F(0.5f)), Vec2.zero, 2); TestKit.Release(2); Vec2 p2 = TestKit.Pos(2); yield return 20; Check(TestKit.Vel(arrow).x > (Fix)10L, "arrow not pushed: v=" + V(TestKit.Vel(arrow))); Check(TestKit.Pos(2).x > p2.x + Fix.One, "player not pushed: " + V(TestKit.Pos(2)) + " from " + V(p2)); } private static IEnumerator<int> PolarityField() { Cast(1, "Polarity", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 1; List<MagnetTotem> list = new List<MagnetTotem>(); Entity.Collect(list); Check(list.Count == 1, "no totem"); Vec2 t = list[0].Position; TestKit.Hold(2, t + new Vec2((Fix)2L, Fix.Zero)); BoplBody arrow = TestKit.Arrow(t + new Vec2(-(Fix)4L, (Fix)3L), Vec2.zero, 2); yield return 2; TestKit.Release(2); TestKit.Release(1); Fix d2 = Vec2.Distance(TestKit.Pos(2), t); Fix da = Vec2.Distance(arrow.position, t); yield return 25; Check(Vec2.Distance(TestKit.Pos(2), t) > d2 + F(0.5f), "player not pushed away"); Check(Vec2.Distance(arrow.position, t) < da - Fix.One, "arrow not pulled in"); } private static IEnumerator<int> TrampolineBounce() { List<Thing> list = new List<Thing>(); World.Query(Vec2.zero, (Fix)40L, Kind.Platform, list); Check(list.Count > 0, "level has no platforms"); Thing thing = list[0]; for (int i = 1; i < list.Count; i++) { if (list[i].Position.y > thing.Position.y) { thing = list[i]; } } TestKit.Release(1); World.Teleport(TestKit.P(1), thing.Position + Vec2.up * (Fix)4L); World.SetVelocity(TestKit.P(1), Vec2.zero); TestKit.Hold(2, home2); for (int j = 0; j < 120; j++) { if ((Object)(object)TestKit.P(1).PPhys != (Object)null && TestKit.P(1).PPhys.IsGrounded()) { break; } yield return 1; } Check((Object)(object)TestKit.P(1).PPhys != (Object)null && TestKit.P(1).PPhys.IsGrounded(), "player 1 never landed"); Cast(1, "Trampoline", Vec2.down); yield return 1; TestKit.Button(1, 0, down: false); List<SpringPad> list2 = new List<SpringPad>(); Entity.Collect(list2); Check(list2.Count == 1, "no pad placed"); TestKit.Hold(2, list2[0].Position + Vec2.up * (Fix)4L); yield return 2; TestKit.Release(2); Fix best = -(Fix)1000L; for (int j = 0; j < 40; j++) { best = Fix.Max(best, World.GetVelocity(TestKit.P(2)).y); yield return 1; } Check(best > (Fix)20L, "player 2 not bounced, max vy=" + (float)best); } private static IEnumerator<int> ChainDrag() { TestKit.Hold(2, At((Fix)5L, Fix.Zero)); Cast(1, "Chain", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 10; Check(Entity.Count<ChainLink>(1) == 1, "chain did not link"); TestKit.Release(1); TestKit.Release(2); Vec2 p1 = TestKit.Pos(1); World.SetVelocity(TestKit.P(2), new Vec2((Fix)60L, (Fix)10L)); yield return 30; Check(TestKit.Pos(1).x > p1.x + (Fix)2L, "owner not dragged: " + V(TestKit.Pos(1)) + " from " + V(p1)); Check(Vec2.Distance(TestKit.Pos(1), TestKit.Pos(2)) < Chain.MaxLength.V * (Fix)1.6, "chain overstretched: " + (float)Vec2.Distance(TestKit.Pos(1), TestKit.Pos(2))); } private static IEnumerator<int> BungeeSnap() { TestKit.Hold(2, At((Fix)7L, Fix.Zero)); Cast(1, "Bungee", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 10; Check(Entity.Count<BungeeCord>(1) == 1, "bungee did not attach"); TestKit.Hold(2, At((Fix)15L, Fix.Zero)); yield return 3; TestKit.Release(1); TestKit.Release(2); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 1; Check(World.GetVelocity(TestKit.P(1)).x > (Fix)10L, "owner not snapped forward: " + V(World.GetVelocity(TestKit.P(1)))); Check(World.GetVelocity(TestKit.P(2)).x < -(Fix)10L, "target not snapped back: " + V(World.GetVelocity(TestKit.P(2)))); } private static IEnumerator<int> GiftTrap() { Cast(1, "Gift", Vec2.down); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; List<GiftBox> gifts = new List<GiftBox>(); Entity.Collect(gifts); Check(gifts.Count == 1, "no gift"); Check(Entity.Count<GiftBox>(1) == 1 && !((MonoUpdatable)gifts[0]).IsDestroyed, "gift triggered by its owner"); TestKit.Hold(1, At(-(Fix)10L, Fix.Zero)); TestKit.Release(2); World.Teleport(TestKit.P(2), gifts[0].Position); World.SetVelocity(TestKit.P(2), Vec2.zero); yield return 2; Check(((MonoUpdatable)gifts[0]).IsDestroyed, "gift did not trigger"); Check(World.GetVelocity(TestKit.P(2)).y > (Fix)25L, "rival not launched: " + V(World.GetVelocity(TestKit.P(2)))); } private static IEnumerator<int> PotatoFlow() { TestKit.Hold(2, At((Fix)4L, Fix.Zero)); Cast(1, "Hot Potato", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 15; List<Potato> spuds = new List<Potato>(); Entity.Collect(spuds); Check(spuds.Count == 1, "no potato"); Check(Vec2.Distance(spuds[0].Position, TestKit.Pos(2)) < (Fix)2L, "potato did not stick to rival"); yield return 40; TestKit.Hold(1, TestKit.Pos(2)); yield return 4; TestKit.Hold(1, At(-(Fix)10L, Fix.Zero)); yield return 4; Check(Vec2.Distance(spuds[0].Position, TestKit.Pos(1)) < (Fix)2L, "potato not passed back on touch"); int guard = 0; while (!((MonoUpdatable)spuds[0]).IsDestroyed && guard++ < 400) { yield return 5; } Check(((MonoUpdatable)spuds[0]).IsDestroyed, "potato never exploded"); } private static IEnumerator<int> MimicCopyRestore() { Check(TestKit.Equip(2, 0, "Rebound"), "equip"); TestKit.Button(2, 0, down: true); yield return 1; TestKit.Button(2, 0, down: false); TestKit.Hold(2, At((Fix)3L, Fix.Zero)); yield return 2; Cast(1, "Mimic", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; Check(TestKit.SlotName(1, 0) == "Rebound", "slot shows " + TestKit.SlotName(1, 0)); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 3; Check(TestKit.SlotName(1, 0) == "Mimic", "slot not restored, shows " + TestKit.SlotName(1, 0)); } private static IEnumerator<int> MimicOfMimic() { Check(TestKit.Equip(2, 0, "Mimic"), "equip"); TestKit.Hold(2, At((Fix)3L, Fix.Zero)); TestKit.Button(2, 0, down: true); yield return 1; TestKit.Button(2, 0, down: false); TestKit.Equip(2, 0, "Mimic"); yield return 1; Cast(1, "Mimic", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; Check(TestKit.SlotName(1, 0) == "Switcheroo", "expected fallback to the rival's other ability, got " + TestKit.SlotName(1, 0)); } private static IEnumerator<int> EchoShove() { TestKit.Equip(1, 0, "Echo"); for (int i = 0; i <= 60; i++) { TestKit.Hold(1, At((Fix)(long)i / (Fix)5L, Fix.Zero)); yield return 1; } TestKit.Hold(2, At((Fix)6L, Fix.Zero)); TestKit.Aim(1, Vec2.right); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); TestKit.Release(2); TestKit.Hold(2, At((Fix)6L, Fix.Zero)); TestKit.Hold(1, At(Fix.Zero, (Fix)10L)); for (int i = 0; i < 170; i++) { if (Entity.Count<EchoGhost>(1) <= 0) { break; } yield return 1; } Check(Stats.Dump().Contains("echo.hit.Player"), "ghost never shoved rival"); } private static IEnumerator<int> PinataBurst() { Cast(1, "Pinata", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); List<PinataBody> pinatas = new List<PinataBody>(); Entity.Collect(pinatas); Check(pinatas.Count == 1, "no pinata"); Vec2 c = pinatas[0].Position; for (int i = 0; i < 6; i++) { if (((MonoUpdatable)pinatas[0]).IsDestroyed) { break; } TestKit.Arrow(c + new Vec2((Fix)4L, Fix.Zero), new Vec2(-(Fix)30L, Fix.Zero), 2); yield return 12; } Check(((MonoUpdatable)pinatas[0]).IsDestroyed, "pinata did not burst after repeated hits"); } private static IEnumerator<int> ShuffleSwap() { TestKit.Equip(1, 0, "Shuffle"); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); Vec2 a = TestKit.Pos(1); Vec2 b = TestKit.Pos(2); TestKit.ReleaseAll(); yield return (int)(long)(Shuffle.Warning.V * (Fix)60L) + 3; Check(Fix.Abs(TestKit.Pos(1).x - b.x) < (Fix)3L && Fix.Abs(TestKit.Pos(2).x - a.x) < (Fix)3L, "players not swapped: " + V(TestKit.Pos(1)) + " " + V(TestKit.Pos(2)) + " expected near " + V(b) + " " + V(a)); } private static IEnumerator<int> AnvilSlam() { Cast(1, "Anvil", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); TestKit.Release(1); World.Nudge(TestKit.P(1), new Vec2((Fix)60L, Fix.Zero)); yield return 2; Check(TestKit.P(1).PBody.externalVelocity.x < (Fix)35L, "knockback not resisted: " + V(TestKit.P(1).PBody.externalVelocity)); Stats.Clear(); TestKit.ReleaseAll(); TestKit.Hold(2, home2); int guard = 0; while (guard++ < 120) { yield return 2; if (Stats.Dump().Contains("anvil.slam")) { break; } } Check(Stats.Dump().Contains("anvil.slam"), "no slam on landing"); } private static IEnumerator<int> FlipBombLift() { TestKit.Hold(2, At((Fix)3L, F(0.5f))); Cast(1, "Flip Bomb", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); for (int i = 0; i < 200; i++) { if (Entity.Count<FlipZone>(1) != 0) { break; } yield return 1; } Check(Entity.Count<FlipZone>(1) == 1, "bomb did not open a zone"); TestKit.Release(2); Fix y0 = TestKit.Pos(2).y; yield return 30; Check(TestKit.Pos(2).y > y0 + Fix.One, "airborne player not lifted: " + (float)(TestKit.Pos(2).y - y0)); } private static IEnumerator<int> HoverpadSteer() { TestKit.Equip(1, 0, "Hoverpad"); TestKit.Release(1); TestKit.Button(1, 0, down: true); TestKit.Move(1, Vec2.right); yield return 2; List<HoverpadDriver> drivers = new List<HoverpadDriver>(); Entity.Collect(drivers); Check(drivers.Count == 1, "no hoverpad"); Vec2 start = drivers[0].Position; yield return 45; TestKit.Button(1, 0, down: false); TestKit.Move(1, Vec2.zero); Check(drivers[0].Position.x > start.x + (Fix)2L, "pad not steered: " + V(drivers[0].Position) + " from " + V(start)); } private static IEnumerator<int> TurntableRestore() { TestKit.ReleaseAll(); yield return 60; List<Thing> list = new List<Thing>(); World.Query(TestKit.Pos(1), (Fix)12L, Kind.Platform, list); Check(list.Count > 0, "no platform near player"); AnimateVelocity anim = ((Component)list[0].Ft).GetComponent<AnimateVelocity>(); Check((Object)(object)anim != (Object)null, "platform has no AnimateVelocity"); Fix r0 = anim.homeRotation; Vec2 h0 = anim.HomePosition; TestKit.Equip(1, 0, "Turntable"); TestKit.Aim(1, Vec2.NormalizedSafe(list[0].Position - TestKit.Pos(1))); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 2; Check(anim.homeRotation != r0 || anim.HomePosition != h0, "nearest platform not turned"); yield return (int)(long)(Turntable.Duration.V * (Fix)60L) + 5; Check(Fix.Abs(anim.homeRotation - r0) < (Fix)0.01 && Vec2.Distance(anim.HomePosition, h0) < (Fix)0.01, "platform not restored"); } private static IEnumerator<int> PiggyBankFlow() { TestKit.Equip(1, 0, "Piggy Bank"); TestKit.Release(1); World.SetVelocity(TestKit.P(1), new Vec2((Fix)30L, Fix.Zero)); yield return 1; TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 3; Check(Vec2.Magnitude(World.GetVelocity(TestKit.P(1))) < (Fix)8L, "not stopped after banking: " + V(World.GetVelocity(TestKit.P(1)))); TestKit.Aim(1, Vec2.up); yield return 5; TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); yield return 1; Check(World.GetVelocity(TestKit.P(1)).y > (Fix)20L, "stored momentum not released upward: " + V(World.GetVelocity(TestKit.P(1)))); } private static IEnumerator<int> TractorPull() { yield return 2; List<Thing> list = new List<Thing>(); World.Query(TestKit.Pos(1), (Fix)25L, Kind.Platform, list); Thing thing = default(Thing); bool ok = false; for (int i = 0; i < list.Count; i++) { AnimateVelocity component = ((Component)list[i].Ft).GetComponent<AnimateVelocity>(); if ((Object)(object)component != (Object)null && component.HomeIsMovable && Vec2.Distance(list[i].Position, TestKit.Pos(1)) > (Fix)7L) { thing = list[i]; ok = true; break; } } Check(ok, "no distant movable platform to pull"); _ = ((Component)thing.Ft).GetComponent<AnimateVelocity>().HomePosition; TestKit.Equip(1, 0, "Tractor"); TestKit.Aim(1, Vec2.NormalizedSafe(thing.Position - TestKit.Pos(1))); TestKit.Hold(1, TestKit.Pos(1)); TestKit.Button(1, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); if (Entity.Count<TractorBeam>(1) == 0) { Check(ok: true, ""); yield break; } List<TractorBeam> list2 = new List<TractorBeam>(); Entity.Collect(list2); AnimateVelocity grabbed = list2[0].Grabbed; Vec2 original = grabbed.HomePosition; yield return 60; Check(Vec2.Distance(grabbed.HomePosition, original) > Fix.One, "platform home not moved"); for (int j = 0; j < 600; j++) { if (Entity.Count<TractorBeam>(1) <= 0) { break; } yield return 1; } yield return 2; Check(Vec2.Distance(grabbed.HomePosition, original) < (Fix)0.05, "platform home not restored"); } private static IEnumerator<int> SimultaneousSwap() { TestKit.Hold(2, At((Fix)8L, Fix.Zero)); TestKit.Equip(1, 0, "Switcheroo"); TestKit.Equip(2, 0, "Switcheroo"); TestKit.Aim(1, Vec2.right); TestKit.Aim(2, Vec2.left); TestKit.ReleaseAll(); TestKit.Button(1, 0, down: true); TestKit.Button(2, 0, down: true); yield return 1; TestKit.Button(1, 0, down: false); TestKit.Button(2, 0, down: false); yield return 60; Check(Entity.Count<SwapOrb>(1) + Entity.Count<SwapOrb>(2) == 0, "orbs still alive"); } private static IEnumerator<int> CaughtDestroyed() { Cast(1, "Mitt", Vec2.right); yield return 2; BoplBody arrow = TestKit.Arrow(At(F(6f), Fix.Zero), new Vec2(-(Fix)35L, Fix.Zero), 2); yield return 12; Check(Entity.Count<CatchMitt>(1) == 1, "mitt not open"); Updater.DestroyFix(((Component)arrow).gameObject); yield return 3; Check(Entity.Count<CatchMitt>(1) == 0, "mitt still holding a destroyed object"); TestKit.Button(1, 0, down: false); } private static IEnumerator<int> OwnerDiesMidChain() { TestKit.Hold(2, At((Fix)5L, Fix.Zero)); Cast(1, "Chain", Vec2.right); yield return 1; TestKit.Button(1, 0, down: false); yield return 10; Check(Entity.Count<ChainLink>(1) == 1, "chain did not link"); bool godMode = LocalMatch.GodMode; LocalMatch.GodMode = false; SlimeController obj = TestKit.Slime(1); PlayerCollision obj2 = ((obj != null) ? obj.GetPlayerCollision() : null); Check((Object)(object)obj2 != (Object)null, "no player collision"); TestKit.ReleaseAll(); obj2.killPlayer(2, true, true, (CauseOfDeath)0); LocalMatch.GodMode = godMode; yield return 10; Check(Entity.Count<ChainLink>(1) == 0, "chain survived owner death"); Check(!PlayerHandler.Get().GetPlayer(1).IsAlive, "owner did not die"); } private static IEnumerator<int> LevelChange() { Cast(2, "Bubble", Vec2.left); yield return 1; TestKit.Button(2, 0, down: false); Cast(2, "Portals", Vec2.left); yield return 1; Check(Entity.All.Count > 0, "nothing alive to test with"); LocalMatch.ForceNextLevel(-1); yield return 30; Check(Entity.All.Count == 0, "entities leaked across level load: " + Entity.All.Count); } } public static class SelfTest { public static bool Muted; } public static class TestKit { public struct Inputs { public bool[] Buttons; public Vec2 Aim; public Vec2 Move; public bool Jump; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static LogCallback <>9__6_0; internal void <HookErrors>b__6_0(string cond, string stack, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) if ((int)type == 4 || ((int)type == 0 && cond.Contains("Mayhem"))) { Errors++; LastError = cond + " " + (stack ?? "").Split(new char[1] { '\n' })[0]; } } } private static readonly Dictionary<int, Inputs> inputs = new Dictionary<int, Inputs>(); private static readonly Dictionary<int, Vec2> holds = new Dictionary<int, Vec2>(); public static int Errors; public static string LastError = ""; private static bool hooked; public static int TraceTicks; private static BoplBody arrowPrefab; private static readonly List<BoplBody> spawnedArrows = new List<BoplBody>(); public static void HookErrors() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (hooked) { return; } hooked = true; object obj = <>c.<>9__6_0; if (obj == null) { LogCallback val = delegate(string cond, string stack, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) if ((int)type == 4 || ((int)type == 0 && cond.Contains("Mayhem"))) { Errors++; LastError = cond + " " + (stack ?? "").Split(new char[1] { '\n' })[0]; } }; <>c.<>9__6_0 = val; obj = (object)val; } Application.logMessageReceived += (LogCallback)obj; } public static void Reset() { inputs.Clear(); holds.Clear(); } internal static void BeforeTick() { //IL_0050: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: 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) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) if (TraceTicks > 0) { TraceTicks--; SlimeController val = Slime(1); Player player = PlayerHandler.Get().GetPlayer(1); if ((Object)(object)val != (Object)null && player != null) { Plugin.Log.LogInfo((object)$"[trace] state={val.getCurrentState()} inAbility={val.isInAbility} suppress={val.suppressInput} btn0={player.AbilityButtonIsDown(0)} timer={(float)val.abilityCooldownTimers[0]:0.00} cd={(float)val.abilities[0].GetCooldown():0.00} castable={val.isAbilityCastable(0)} canUse={player.CanUseAbilities} active={((Component)val).gameObject.activeInHierarchy}"); } } foreach (Player item in PlayerHandler.Get().PlayerList()) { inputs.TryGetValue(item.Id, out var value); bool[] array = value.Buttons ?? new bool[3]; byte b = (byte)((!(value.Aim == Vec2.zero)) ? InputProfile.JoyStickAngleByteFromVector(value.Aim) : 0); item.ForceSetInputProfile(false, false, value.Jump, array[0], array[1], array[2], b, value.Move.y > Fix.Zero, value.Move.x < Fix.Zero, value.Move.y < Fix.Zero, value.Move.x > Fix.Zero); } foreach (KeyValuePair<int, Vec2> hold in holds) { if (World.FindPlayer(hold.Key, hold.Value, out var found)) { World.Teleport(in found, hold.Value); World.SetVelocity(in found, Vec2.zero); } } } public static void Aim(int id, Vec2 aim) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) inputs.TryGetValue(id, out var value); value.Aim = aim; inputs[id] = value; } public static void Move(int id, Vec2 dir) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) inputs.TryGetValue(id, out var value); value.Move = dir; inputs[id] = value; } public static void Button(int id, int slot, bool down) { inputs.TryGetValue(id, out var value); value.Buttons = value.Buttons ?? new bool[3]; value.Buttons[slot] = down; inputs[id] = value; } public static void Hold(int id, Vec2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) holds[id] = pos; } public static void Release(int id) { holds.Remove(id); } public static void ReleaseAll() { holds.Clear(); } public static Thing P(int id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) World.FindPlayer(id, Vec2.zero, out var found); return found; } public static Vec2 Pos(int id) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!P(id).Valid) { return Vec2.zero; } return P(id).Position; } public static SlimeController Slime(int id) { SlimeController val = null; int num = 0; SlimeController[] array = Object.FindObjectsOfType<SlimeController>(); foreach (SlimeController val2 in array) { if (!((MonoUpdatable)val2).IsDestroyed && val2.playerNumber == id) { num++; if ((Object)(object)val == (Object)null || (val2.HasSpawned && !val.HasSpawned) || ((Object)(object)val2.body != (Object)null && val2.body.simulated && ((Object)(object)val.body == (Object)null || !val.body.simulated))) { val = val2; } } } if (num > 1) { Plugin.Log.LogInfo((object)$"[test] {num} SlimeControllers for player {id}; using {((Object)val).name} spawned={val.HasSpawned}"); } return val; } public static bool Equip(int id, int slot, string abilityName) { //IL_0037: 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_003d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_00d8: Unknown result type (might be due to invalid IL or missing references) SlimeController val = Slime(id); NamedSpriteList fullList = AbilityRegistry.FullList; int num = (((Object)(object)fullList != (Object)null) ? fullList.IndexOf(abilityName) : (-1)); if ((Object)(object)val == (Object)null || num < 0) { return false; } NamedSprite val2 = fullList.sprites[num]; GameObject val3 = FixTransform.InstantiateFixed(val2.associatedGameObject, Vec2.zero); val3.SetActive(false); val.abilities[slot] = val3.GetComponent<AbilityMonoBehaviour>(); val.AbilityReadyIndicators[slot].SetSprite(val2.sprite, true); Cooldowns.Refill(val, slot, Fix.Zero); Plugin.Log.LogInfo((object)$"[test] equip p{id} slot{slot}={abilityName} timer={(float)val.abilityCooldownTimers[slot]:0.00} cd={(float)val.abilities[slot].GetCooldown():0.00} inCast={Cooldowns.InCastForDebug}"); return true; } public static string SlotName(int id, int slot) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) SlimeController slime = Slime(id); NamedSpriteList fullList = AbilityRegistry.FullList; int num = CastTracker.SlotIndex(slime, slot); if (num < 0) { return "?"; } return fullList.sprites[num].name; } public static BoplBody Arrow(Vec2 pos, Vec2 vel, int owner) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0098: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)arrowPrefab == (Object)null) { BowTransform[] array = Resources.FindObjectsOfTypeAll<BowTransform>(); foreach (BowTransform val in array) { if ((Object)(object)val != (Object)null) { Scene scene = ((Component)val).gameObject.scene; if (!((Scene)(ref scene)).IsValid() && (Object)(object)val.Arrow != (Object)null) { arrowPrefab = val.Arrow; break; } } } } if ((Object)(object)arrowPrefab == (Object)null) { return null; } BoplBody val2 = FixTransform.InstantiateFixed<BoplBody>(arrowPrefab, pos, Vec2.NormalizedVectorAngle(Vec2.NormalizedSafe(vel))); IPlayerIdHolder component = ((Component)val2).GetComponent<IPlayerIdHolder>(); if (component != null) { component.SetPlayerId(owner); } val2.StartVelocity = vel; spawnedArrows.Add(val2); return val2; } public static Vec2 Vel(BoplBody b) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)b != (Object)null) || ((MonoUpdatable)b).IsDestroyed || !b.HasBeenInitialized) { if (!((Object)(object)b != (Object)null)) { return Vec2.zero; } return b.StartVelocity; } return b.velocity; } public static int Owner(BoplBody b) { Projectile val = (((Object)(object)b != (Object)null) ? ((Component)b).GetComponent<Projectile>() : null); if (!((Object)(object)val != (Object)null)) { return -1; } return val.PlayerOwnerId; } public static Vec2 FindOpenSky(Fix clearance, Vec2 avoid, Fix minSeparation) { //IL_0080: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0044: 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_0063: 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) List<Thing> list = new List<Thing>(); Vec2 val = default(Vec2); for (int num = 14; num >= 0; num -= 2) { for (int i = 0; i <= 24; i++) { int num2 = ((i % 2 == 0) ? 1 : (-1)) * (i / 2) * 2; ((Vec2)(ref val))..ctor((Fix)(long)num2, (Fix)(long)num); if (!(avoid != Vec2.zero) || !(Vec2.Distance(val, avoid) < minSeparation)) { World.Query(val, clearance, Kind.Platform, list); if (list.Count == 0 && !World.InsideGround(val)) { return val; } } } } return new Vec2(Fix.Zero, (Fix)12L); } public static void ClearEntities() { foreach (BoplBody spawnedArrow in spawnedArrows) { if ((Object)(object)spawnedArrow != (Object)null && !((MonoUpdatable)spawnedArrow).IsDestroyed) { Updater.DestroyFix(((Component)spawnedArrow).gameObject); } } spawnedArrows.Clear(); for (int num = Entity.All.Count - 1; num >= 0; num--) { if (num < Entity.All.Count) { Entity.All[num].Despawn(); } } } } } namespace Mayhem.Patches { [HarmonyPatch(typeof(SteamManager), "Awake")] internal static class SteamManagerAwake { private static void Postfix(SteamManager __instance) { AbilityRegistry.Inject(__instance.abilityIconsFull); } } [HarmonyPatch(typeof(AbilityGrid), "Awake")] internal static class AbilityGridAwake { private static void Prefix(AbilityGrid __instance) { AbilityRegistry.Inject(__instance.abilityIcons); } private static void Postfix(AbilityGrid __instance) { GridLayout.Relayout(__instance); } } internal static class GridLayout { public static void Relayout(AbilityGrid grid) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) if (grid.grid == null || (Object)(object)grid.recTrans == (Object)null) { return; } int num = grid.grid.Length; if (num <= 32) { return; } Rect rect = grid.recTrans.rect; if (((Rect)(ref rect)).height <= 1f || ((Rect)(ref rect)).width <= 1f) { return; } float num2 = Mathf.Sqrt(((Rect)(ref rect)).width * ((Rect)(ref rect)).height * 0.9f / 32f); float num3 = 126f - num2 * 0.5f; float num4 = 122f - num2 * 0.5f; float num5 = ((Rect)(ref rect)).width - 2f * num3; float num6 = ((Rect)(ref rect)).height * 0.95f - num4; int num7 = grid.columns; float num8 = 0f; for (int i = 4; i <= 8; i++) { int num9 = Mathf.CeilToInt((float)num / (float)i); float num10 = Mathf.Min(num5 / (float)i, num6 / (float)num9); if (num10 > num8) { num8 = num10; num7 = i; } } grid.columns = num7; grid.rows = Mathf.CeilToInt((float)num / (float)num7); grid.entrySize = num8; for (int j = 0; j < num; j++) { AbilityGridEntry val = grid.grid[j]; int num11 = j / num7; int num12 = j % num7; val.rectTrans.anchoredPosition = new Vector2((0f - ((Rect)(ref rect)).width) / 2f + num3 + num8 * ((float)num12 + 0.5f), ((Rect)(ref rect)).height / 2f - num4 - num8 * ((float)num11 + 0.5f)); RectTransform rectTrans = val.rectTrans; float nonSelectedScale = grid.nonSelectedScale; float num13 = num8; Rect rect2 = val.rectTrans.rect; float num14 = num13 / ((Rect)(ref rect2)).width; float num15 = num8; rect2 = val.rectTrans.rect; ((Transform)rectTrans).localScale = nonSelectedScale * new Vector3(num14, num15 / ((Rect)(ref rect2)).height, 1f); } } } [HarmonyPatch(typeof(InstantAbility), "EnterAbility")] internal static class InstantAbilityEnter { private static void Postfix(InstantAbility __instance, PlayerInfo playerInfo) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) MayhemAbility component = ((Component)__instance).GetComponent<MayhemAbility>(); if ((Object)(object)component == (Object)null) { return; } try { component.HandleCast(playerInfo); } catch (Exception arg) { Plugin.Log.LogError((object)$"{((object)component).GetType().Name} cast failed: {arg}"); } } } [HarmonyPatch(typeof(Updater), "PreLevelLoad")] internal static class LevelReset { private static void Postfix() { Lifecycle.RaiseLevelReset(); } } [HarmonyPatch(typeof(Updater), "ReInit")] internal static class UpdaterReInit { private static void Postfix() { Lifecycle.RaiseLevelReset(); } } [HarmonyPatch(typeof(printText), "Awake")] internal static class VersionTag { private static void Postfix(printText __instance) { if (!AbilityRegistry.Ready || !MayhemConfig.TagLobbies.Value || Constants.version == null || Constants.version.Contains("+Mayhem")) { return; } Constants.version += MayhemConfig.VersionTag; if (MayhemConfig.ShowLobbyTag.Value) { TextMeshProUGUI component = ((Component)__instance).GetComponent<TextMeshProUGUI>(); if ((Object)(object)component != (Object)null) { ((TMP_Text)component).text = ((TMP_Text)component).text + "\n<size=60%>+ Mayhem 1.0.0</size>"; } } } } [HarmonyPatch(typeof(LocalizationTable), "getText")] internal static class LocalizationPassthrough { private static bool Prefix(string enText, ref string __result) { if (enText == null || !AbilityCatalog.IsMayhemNameLower(enText)) { return true; } __result = enText; return false; } } } namespace Mayhem.Core { public static class AbilityCatalog { public static readonly List<AbilityDef> All = new List<AbilityDef>(); private static readonly Dictionary<string, AbilityDef> byId = new Dictionary<string, AbilityDef>(); private static readonly Dictionary<string, AbilityDef> byName = new Dictionary<string, AbilityDef>(); private static HashSet<string> lowerNames; public static void Discover(Assembly asm) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) All.Clear(); byId.Clear(); byName.Clear(); Type[] array; try { array = asm.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array2 = array; foreach (Type type in array2) { AbilityAttribute customAttribute = type.GetCustomAttribute<AbilityAttribute>(); if (customAttribute == null) { continue; } if (!typeof(MayhemAbility).IsAssignableFrom(type) || type.IsAbstract) { Plugin.Log.LogWarning((object)("[Ability] on " + type.Name + " ignored: it must be a concrete MayhemAbility.")); continue; } AbilityDef abilityDef = new AbilityDef { Id = customAttribute.Id, Name = customAttribute.Name, Description = customAttribute.Description, Offensive = customAttribute.Offensive, Behaviour = type, Cooldown = (Fix)(long)Math.Round((double)customAttribute.Cooldown * 1000.0) / (Fix)1000L }; FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(Param) && fieldInfo.GetValue(null) is Param item) { abilityDef.Params.Add(item); } } abilityDef.Params.Sort((Param a, Param b) => string.CompareOrdinal(a.Key, b.Key)); All.Add(abilityDef); } All.Sort((AbilityDef a, AbilityDef b) => string.CompareOrdinal(a.Id, b.Id)); foreach (AbilityDef item2 in All) { if (byId.ContainsKey(item2.Id) || byName.ContainsKey(item2.Name)) { throw new InvalidOperationException($"Duplicate ability id or name: {item2}"); } byId[item2.Id] = item2; byName[item2.Name] = item2; } } public static void BindConfig(ConfigFile cfg) { //IL_004f: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) foreach (AbilityDef item in All) { string text = "Ability: " + item.Name; item.Enabled = cfg.Bind<bool>(text, "Enabled", true, item.Description).Value; float value = cfg.Bind<float>(text, "Cooldown", (float)item.Cooldown, "Seconds between uses.").Value; item.Cooldown = (Fix)(long)Math.Round((double)value * 1000.0) / (Fix)1000L; foreach (Param item2 in item.Params) { item2.Bind(cfg, text); } if (!item.Enabled) { continue; } MayhemConfig.Feed(item.Id + ".cd", item.Cooldown.m_rawValue); foreach (Param item3 in item.Params) { MayhemConfig.Feed(item.Id + "." + item3.Key, item3.V.m_rawValue); } } } public static AbilityDef ById(string id) { if (id == null || !byId.TryGetValue(id, out var value)) { return null; } return value; } public static AbilityDef ByName(string name) { if (name == null || !byName.TryGetValue(name, out var value)) { return null; } return value; } public static bool IsMayhemName(string name) { if (name != null) { return byName.ContainsKey(name); } return false; } public static bool IsMayhemNameLower(string text) { if (lowerNames == null) { lowerNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (AbilityDef item in All) { lowerNames.Add(item.Name); } } return lowerNames.Contains(text); } } [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class AbilityAttribute : Attribute { public string Id { get; } public string Name { get; } public float Cooldown { get; set; } = 5f; public bool Offensive { get; set; } public string Description { get; set; } = ""; public AbilityAttribute(string id, string name) { Id = id; Name = name; } } public sealed class Param { public readonly string Key; public readonly float Default; public readonly string Description; public Fix V { get; private set; } public float F { get; private set; } public int I => (int)(long)Fix.Round(V); public Param(string key, float defaultValue, string description) { Key = key; Default = defaultValue; Description = description; Set(defaultValue); } internal void Bind(ConfigFile cfg, string section) { ConfigEntry<float> val = cfg.Bind<float>(section, Key, Default, Description); Set(val.Value); } private void Set(float value) { //IL_001a: 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) F = value; V = (Fix)(long)Math.Round((double)value * 1000.0) / (Fix)1000L; } } public sealed class AbilityDef { public string Id; public string Name; public string Description; public bool Offensive; public Type Behaviour; public Fix Cooldown; public bool Enabled = true; public readonly List<Param> Params = new List<Param>(); public int IconCell; public Sprite Icon; public GameObject Prefab; public override string ToString() { return Name + " (" + Id + ")"; } } public static class AbilityRegistry { public static readonly List<AbilityDef> Enabled = new List<AbilityDef>(); private const string FullListName = "AbilityIcons"; public static bool Ready { get; private set; } public static int VanillaCount { get; private set; } = -1; public static NamedSpriteList FullList { get { SteamManager instance = SteamManager.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.abilityIconsFull != (Object)null) { return instance.abilityIconsFull; } NamedSpriteList[] array = Resources.FindObjectsOfTypeAll<NamedSpriteList>(); foreach (NamedSpriteList val in array) { if (((Object)val).name == "AbilityIcons") { return val; } } return null; } } public static void Build() { Enabled.Clear(); foreach (AbilityDef item in AbilityCatalog.All) { if (item.Enabled) { Enabled.Add(item); } } IconAtlas.Build(Enabled); Ready = true; SceneManager.sceneLoaded += delegate { EnsurePrefabs(); TryInjectIntoLoadedLists(); }; } public static void EnsurePrefabs() { if (!Ready) { return; } foreach (AbilityDef item in Enabled) { if ((Object)(object)item.Prefab == (Object)null) { item.Prefab = BuildPrefab(item); } } } private static GameObject BuildPrefab(AbilityDef def) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0079: Expected O, but got Unknown GameObject val = new GameObject(def.Name); val.SetActive(false); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)32; val.layer = World.PlayerLayer; val.AddComponent<FixTransform>(); InstantAbility obj = val.AddComponent<InstantAbility>(); obj.SetCoolDown(def.Cooldown); ((MonoUpdatable)obj).HierarchyNumber = 1; obj.AudioOnCast = ""; MayhemAbility obj2 = (MayhemAbility)(object)val.AddComponent(def.Behaviour); obj2.abilityId = def.Id; ((MonoUpdatable)obj2).HierarchyNumber = 2; return val; } public static void Inject(NamedSpriteList list) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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) if (!Ready || (Object)(object)list == (Object)null || list.sprites == null || ((Object)list).name != "AbilityIcons" || Enabled.Count == 0) { return; } EnsurePrefabs(); bool flag = false; foreach (AbilityDef item in Enabled) { int num = list.IndexOf(item.Name); if (num < 0) { if (VanillaCount < 0) { VanillaCount = list.sprites.Count; } list.sprites.Add(new NamedSprite(item.Name, item.Icon, item.Prefab, item.Offensive)); flag = true; } else if ((Object)(object)list.sprites[num].associatedGameObject != (Object)(object)item.Prefab || (Object)(object)list.sprites[num].sprite != (Object)(object)item.Icon) { list.sprites[num] = new NamedSprite(item.Name, item.Icon, item.Prefab, item.Offensive); } } if (flag) { Plugin.Log.LogInfo((object)$"Added {Enabled.Count} Mayhem abilities after {VanillaCount} built-in ones."); } } public static void TryInjectIntoLoadedLists() { if (Ready) { NamedSpriteList[] array = Resources.FindObjectsOfTypeAll<NamedSpriteList>(); for (int i = 0; i < array.Length; i++) { Inject(array[i]); } } } public static AbilityDef DefOf(GameObject abilityObject) { if ((Object)(object)abilityObject == (Object)null) { return null; } MayhemAbility component = abilityObject.GetComponent<MayhemAbility>(); if (!((Object)(object)component != (Object)null)) { return null; } return AbilityCatalog.ById(component.abilityId); } } public static class Art { public struct Piece { public Transform Root; public SpriteRenderer Fill; public SpriteRenderer Ink; private Color tint; public GameObject gameObject => ((Component)Root).gameObject; public void SetAlpha(float a) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Fill != (Object)null) { if (tint.a == 0f) { tint = Fill.color; } Fill.color = Fx.WithAlpha(tint, tint.a * a); } if ((Object)(object)Ink != (Object)null) { Ink.color = new Color(1f, 1f, 1f, a); } } public void SetTint(Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) tint = c; if ((Object)(object)Fill != (Object)null) { Fill.color = c; } } } public const float PixelsPerUnit = 128f; private static readonly Dictionary<string, Sprite> cache = new Dictionary<string, Sprite>(); public static Sprite Get(string name) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) if (cache.TryGetValue(name, out var value)) { return value; } Texture2D val = IconAtlas.LoadEmbedded("sprites." + name + ".png"); if ((Object)(object)val != (Object)null) { ((Object)val).name = "Mayhem_" + name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; ((Object)val).hideFlags = (HideFlags)32; value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 128f); ((Object)value).name = name; ((Object)value).hideFlags = (HideFlags)32; } cache[name] = value; return value; } public static Piece Add(GameObject parent, string name, Color tint, float scale = 1f, string sortingLayer = "effect", int order = 0) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0031: 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) //IL_0094: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.layer = Constants.effectLayer; val.transform.SetParent(parent.transform, false); val.transform.localScale = new Vector3(scale, scale, 1f); Piece result = new Piece { Root = val.transform }; Sprite val2 = Get(name + ".fill"); if ((Object)(object)val2 != (Object)null) { result.Fill = Layer(val, val2, tint, sortingLayer, order); } Sprite val3 = Get(name); if ((Object)(object)val3 != (Object)null) { result.Ink = Layer(val, val3, Color.white, sortingLayer, order + 1); } return result; } private static SpriteRenderer Layer(GameObject root, Sprite sprite, Color color, string sortingLayer, int order) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(((Object)sprite).name) { layer = Constants.effectLayer }; val.transform.SetParent(root.transform, false); SpriteRenderer obj = val.AddComponent<SpriteRenderer>(); obj.sprite = sprite; obj.color = color; ((Renderer)obj).sortingLayerName = sortingLayer; ((Renderer)obj).sortingOrder = order; return obj; } } public sealed class Flipbook : MonoBehaviour { public const string Poof = "SmokeBombSmoke"; public const string Dust = "SideSmoke"; public const string GroundWave = "RollWave"; public const string Shock = "Shockwave4C"; public const string Rubble = "gruondrubble"; public const string Splash = "WaterSplash"; private static readonly Dictionary<string, Sprite[]> sheets = new Dictionary<string, Sprite[]>(); private SpriteRenderer sr; private Sprite[] frames; private float age; private float duration; private Color color; private Vector2 drift; private bool looping; public int FrameLimit; public static Sprite[] Frames(string sheet) { if (sheets.TryGetValue(sheet, out var value) && value != null && value.Length != 0 && (Object)(object)value[0] != (Object)null) { return value; } SortedDictionary<int, Sprite> sortedDictionary = new SortedDictionary<int, Sprite>(); string text = sheet + "_"; Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>(); foreach (Sprite val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name.StartsWith(text) && int.TryParse(((Object)val).name.Substring(text.Length), out var result) && !sortedDictionary.ContainsKey(result)) { sortedDictionary[result] = val; } } value = (Sprite[])(object)new Sprite[sortedDictionary.Count]; sortedDictionary.Values.CopyTo(value, 0); sheets[sheet] = value; return value; } public static Flipbook Play(string sheet, Vector2 pos, float size, float duration, Color color, float rotationDeg = 0f, bool flipX = false, int order = 20, Vector2 drift = default(Vector2)) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0029: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Sprite[] array = Frames(sheet); if (array.Length == 0) { return null; } GameObject val = new GameObject("Mayhem.Flipbook"); val.layer = Constants.effectLayer; val.transform.position = Vector2.op_Implicit(pos); val.transform.rotation = Quaternion.Euler(0f, 0f, rotationDeg); val.transform.localScale = new Vector3(flipX ? (0f - size) : size, size, 1f); Flipbook flipbook = val.AddComponent<Flipbook>(); flipbook.sr = val.AddComponent<SpriteRenderer>(); ((Renderer)flipbook.sr).sortingLayerName = "effect"; ((Renderer)flipbook.sr).sortingOrder = order; flipbook.frames = array; flipbook.duration = Mathf.Max(0.05f, duration); flipbook.color = color; flipbook.drift = drift; flipbook.Apply(); return flipbook; } public static Flipbook Attach(GameObject parent, string sheet, Vector2 localPos, float size, float loopSeconds, float rotationDeg = 0f, int order = 5) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_003b: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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) Sprite[] array = Frames(sheet); if (array.Length == 0) { return null; } GameObject val = new GameObject("Mayhem.Loop"); val.layer = Constants.effectLayer; val.transform.SetParent(parent.transform, false); val.transform.localPosition = Vector2.op_Implicit(localPos); val.transform.localRotation = Quaternion.Euler(0f, 0f, rotationDeg); val.transform.localScale = new Vector3(size, size, 1f); Flipbook flipbook = val.AddComponent<Flipbook>(); flipbook.sr = val.AddComponent<SpriteRenderer>(); ((Renderer)flipbook.sr).sortingLayerName = "effect"; ((Renderer)flipbook.sr).sortingOrder = order; flipbook.frames = array; flipbook.duration = Mathf.Max(0.05f, loopSeconds); flipbook.color = Color.white; flipbook.looping = true; flipbook.Apply(); return flipbook; } public static void Clear() { sheets.Clear(); } private void Update() { //IL_0050: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) age += Time.deltaTime; if (looping) { age %= duration; } else if (age >= duration) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Transform transform = ((Component)this).transform; transform.position += Vector2.op_Implicit(drift * Time.deltaTime); Apply(); } private void Apply() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) int num = ((FrameLimit > 0) ? Mathf.Min(FrameLimit, frames.Length) : frames.Length); float num2 = age / duration; sr.sprite = frames[Mathf.Clamp((int)(num2 * (float)num), 0, num - 1)]; sr.color = (looping ? color : Fx.WithAlpha(color, color.a * Mathf.Clamp01((1f - num2) * 3f))); } } public sealed class InkLine { private readonly LineRenderer ink; private readonly LineRenderer body; public bool Enabled { get { return ((Renderer)body).enabled; } set { ((Renderer)body).enabled = value; ((Renderer)ink).enabled = value; } } public InkLine(GameObject parent, Color color, float width, int points, int order = 10) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) ink = Fx.Line(parent, new Color(0.11f, 0.094f, 0.133f, color.a), width + 0.09f, points, "effect", order); body = Fx.Line(parent, color, width, points, "effect", order + 1); } public void Set(int i, Vector3 p) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) ink.SetPosition(i, p); body.SetPosition(i, p); } public void SetCount(int n) { ink.positionCount = n; body.positionCount = n; } public void SetAlpha(float a) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_004e: 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_0050: 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) Color startColor = body.startColor; startColor.a = a; LineRenderer obj = body; Color startColor2 = (body.endColor = startColor); obj.startColor = startColor2; Color startColor3 = ink.startColor; startColor3.a = a; LineRenderer obj2 = ink; startColor2 = (ink.endColor = startColor3); obj2.startColor = startColor2; } public void SetWidth(float w) { body.widthMultiplier = w; ink.widthMultiplier = w + 0.09f; } } public sealed class FieldEdge : MonoBehaviour { private const int Points = 72; private LineRenderer line; private float radius; private float shown; private float target; private float seed; public static FieldEdge Add(GameObject parent, float radius, Color color, float alpha = 0.55f) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0031: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown GameObject val = new GameObject("fieldEdge"); val.layer = Constants.effectLayer; val.transform.SetParent(parent.transform, false); FieldEdge fieldEdge = val.AddComponent<FieldEdge>(); fieldEdge.line = Fx.Line(val, Fx.WithAlpha(color, alpha), 0.09f, 73, "Default", -4); fieldEdge.line.useWorldSpace = false; fieldEdge.line.loop = false; fieldEdge.radius = radius; fieldEdge.target = 1f; fieldEdge.seed = Mathf.Abs(parent.transform.position.x * 1.37f + parent.transform.position.y) % 10f; AnimationCurve val2 = new AnimationCurve(); for (int i = 0; i <= 8; i++) { val2.AddKey((float)i / 8f, 0.75f + 0.5f * Mathf.PerlinNoise(fieldEdge.seed, (float)i * 0.7f)); } fieldEdge.line.widthCurve = val2; fieldEdge.Apply(); return fieldEdge; } public void SetRadius(float r) { radius = r; } public void Close() { target = 0f; } private void Update() { shown = Mathf.MoveTowards(shown, target, Time.deltaTime * ((target > shown) ? 6f : 8f)); Apply(); } private void Apply() { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) float num = shown; float num2 = ((target > 0f) ? (1f + 2.2f * Mathf.Pow(num - 1f, 3f) + 1.2f * Mathf.Pow(num - 1f, 2f)) : (num * num)); float num3 = radius * Mathf.Max(0f, num2); for (int i = 0; i <= 72; i++) { float num4 = (float)i / 72f * (float)Math.PI * 2f; float num5 = 1f + 0.012f * Mathf.Sin(num4 * 3f + seed); line.SetPosition(i, new Vector3(Mathf.Cos(num4) * num3 * num5, Mathf.Sin(num4) * num3 * num5, 0f)); } } } public abstract class Ballistic : Entity { public Fix Gravity = (Fix)45L; private Vec2 localPos; public bool Landed { get; private set; } protected StickyRoundedRectangle Ground { get; private set; } protected Vec2 GroundNormal { get; private set; } = Vec2.up; public override bool Movable => true; protected bool Fly(Fix dt) { //IL_009e: 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_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_00b3: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (m