Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LCCustomDifficulty v1.3.0
LCCustomDifficulty.dll
Decompiled 2 years ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LCCustomDifficulty.Blomko.Lib.WeightedRandom; using LCSyncTool; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LCCustomDifficulty")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A template for Lethal Company")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LCCustomDifficulty")] [assembly: AssemblyTitle("LCCustomDifficulty")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 LCCustomDifficulty { public static class CommandSystem { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<KeyValuePair<string, Action<int, string>>, string> <>9__8_9; public static Action<int, string> <>9__8_0; public static Action<int, string> <>9__8_1; public static Action<int, string> <>9__8_2; public static Func<Type, Tuple<string, Type>> <>9__8_14; public static Action<int, string> <>9__8_3; public static Func<Type, Tuple<string, Type>> <>9__8_16; public static Action<int, string> <>9__8_4; public static Action<int, string> <>9__8_5; public static Action<int, string> <>9__8_6; public static Action<int, string> <>9__8_7; public static Action<int, string> <>9__8_8; public static OnValidateInput <>9__11_0; internal void <InitialiseCommands>b__8_0(int id, string _) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("User can't call this command.", -1); return; } ClearChat(); s_CurrentHUD.AddTextToChatOnServer("Available Commands Are:\n" + GeneralExtensions.Join<KeyValuePair<string, Action<int, string>>>((IEnumerable<KeyValuePair<string, Action<int, string>>>)s_CommandActionMap, (Func<KeyValuePair<string, Action<int, string>>, string>)((KeyValuePair<string, Action<int, string>> x) => x.Key), "\n"), -1); } internal string <InitialiseCommands>b__8_9(KeyValuePair<string, Action<int, string>> x) { return x.Key; } internal void <InitialiseCommands>b__8_1(int _, string _) { s_CurrentHUD.AddTextToChatOnServer("<color=blue>Pong!</color>", -1); } internal void <InitialiseCommands>b__8_2(int id, string _) { <>c__DisplayClass8_0 CS$<>8__locals0 = new <>c__DisplayClass8_0(); if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("You can't invoke this command!", -1); return; } CS$<>8__locals0.colours = new string[7] { "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF" }; CS$<>8__locals0.t = typeof(AbstractLevelEvent); string text = GeneralExtensions.Join<string>(from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && CS$<>8__locals0.t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select "<color=" + RandomColour() + ">" + x.Name + "</color>", (Func<string, string>)null, ", "); ClearChat(); s_CurrentHUD.AddTextToChatOnServer(text, -1); string RandomColour() { return CS$<>8__locals0.colours[Random.RandomRangeInt(0, CS$<>8__locals0.colours.Length)]; } } internal void <InitialiseCommands>b__8_3(int id, string msg) { <>c__DisplayClass8_1 CS$<>8__locals0 = new <>c__DisplayClass8_1(); if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("<color=red>You can't invoke this command!</color>", -1); return; } string[] array = msg.Split(" "); if (array.Length < 2) { s_CurrentHUD.AddTextToChatOnServer("<color=red>Error Expected Format is '!add LevelEvent'</color>", -1); return; } CS$<>8__locals0.t = typeof(AbstractLevelEvent); foreach (var (text2, type2) in (from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && CS$<>8__locals0.t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select new Tuple<string, Type>(x.Name, x)).ToList()) { if (text2.Equals(array[1])) { AbstractLevelEvent abstractLevelEvent = (AbstractLevelEvent)type2.GetConstructor(Type.EmptyTypes).Invoke(null); bool flag = LevelModifier.AddToGuaranteed(abstractLevelEvent); s_AddedEvents.Add(abstractLevelEvent); s_CurrentHUD.AddTextToChatOnServer(flag ? ("<color=green>Successfully added '" + text2 + "'</color>") : ("<color=red>Failed to add '" + text2 + "'</color>"), -1); break; } } } internal Tuple<string, Type> <InitialiseCommands>b__8_14(Type x) { return new Tuple<string, Type>(x.Name, x); } internal void <InitialiseCommands>b__8_4(int id, string msg) { <>c__DisplayClass8_2 CS$<>8__locals0 = new <>c__DisplayClass8_2(); if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("You can't invoke this command!", -1); return; } string[] array = msg.Split(" "); if (array.Length < 2) { s_CurrentHUD.AddTextToChatOnServer($"Error Expected Format is '{array} LevelEvent'", -1); return; } CS$<>8__locals0.t = typeof(AbstractLevelEvent); foreach (var (text2, type2) in (from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && CS$<>8__locals0.t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select new Tuple<string, Type>(x.Name, x)).ToList()) { if (text2.Equals(array[1])) { AbstractLevelEvent instance = (AbstractLevelEvent)type2.GetConstructor(Type.EmptyTypes).Invoke(null); s_CurrentHUD.AddTextToChatOnServer(LevelModifier.RemoveFromGuaranteed(instance) ? ("Successfully removed '" + text2 + "'") : ("Failed to remove '" + text2 + "'"), -1); break; } } } internal Tuple<string, Type> <InitialiseCommands>b__8_16(Type x) { return new Tuple<string, Type>(x.Name, x); } internal void <InitialiseCommands>b__8_5(int id, string _) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("<color=red>User not allowed to do this.</color>", -1); return; } int num = s_AddedEvents.RemoveWhere(LevelModifier.RemoveFromGuaranteed); s_CurrentHUD.AddTextToChatOnServer($"Pruned {num} level events.", -1); } internal void <InitialiseCommands>b__8_6(int id, string _) { if (IsLocalPlayer(id)) { ClearChat(); } } internal void <InitialiseCommands>b__8_7(int id, string _) { if (IsLocalPlayer(id)) { ClearChat(); LevelModifier.PostCurrentModifiersTo(s_CurrentHUD); } } internal void <InitialiseCommands>b__8_8(int id, string _) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!IsLocalPlayer(id)) { return; } ClearChat(); Vector3 position = ((Component)StartOfRound.Instance.localPlayerController).transform.position; HashSet<string> hashSet = new HashSet<string>(); SelectableLevel[] levels = StartOfRound.Instance.levels; for (int i = 0; i < levels.Length; i++) { foreach (SpawnableItemWithRarity item in levels[i].spawnableScrap) { Item spawnableItem = item.spawnableItem; if (hashSet.Add(spawnableItem.itemName)) { GameObject obj = Object.Instantiate<GameObject>(spawnableItem.spawnPrefab); obj.GetComponent<GrabbableObject>().grabbable = true; obj.transform.position = position; obj.GetComponent<NetworkObject>().Spawn(true); } } } } internal char <SetTextLimits>b__11_0(string _, int _, char c) { return c; } } [CompilerGenerated] private sealed class <>c__DisplayClass8_0 { public string[] colours; public Type t; internal bool <InitialiseCommands>b__11(Type x) { if (!x.IsAbstract && t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null) { return x != typeof(RandomDifficulty); } return false; } internal string <InitialiseCommands>b__12(Type x) { return "<color=" + RandomColour() + ">" + x.Name + "</color>"; string RandomColour() { return colours[Random.RandomRangeInt(0, colours.Length)]; } } } [CompilerGenerated] private sealed class <>c__DisplayClass8_1 { public Type t; internal bool <InitialiseCommands>b__13(Type x) { if (!x.IsAbstract && t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null) { return x != typeof(RandomDifficulty); } return false; } } [CompilerGenerated] private sealed class <>c__DisplayClass8_2 { public Type t; internal bool <InitialiseCommands>b__15(Type x) { if (!x.IsAbstract && t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null) { return x != typeof(RandomDifficulty); } return false; } } private static Dictionary<string, Action<int, string>> s_CommandActionMap = new Dictionary<string, Action<int, string>>(); private static HUDManager s_CurrentHUD; private static HashSet<AbstractLevelEvent> s_AddedEvents = new HashSet<AbstractLevelEvent>(); [HarmonyPatch(typeof(HUDManager), "AddTextToChatOnServer")] [HarmonyPostfix] private static void OnChatMessageReceived(ref HUDManager __instance, ref string chatMessage, ref int playerId) { s_CurrentHUD = __instance; if (playerId != -1) { string[] array = chatMessage.Split(" "); if (s_CommandActionMap.TryGetValue(array[0], out var value)) { value(playerId, chatMessage); } Plugin.LOGGER.LogInfo((object)("Received Chat Message: '" + chatMessage + "'; Split: '" + GeneralExtensions.Join<string>((IEnumerable<string>)array, (Func<string, string>)null, ", ") + "'")); } } public static void AddCommand(string command, Action<int, string> handler) { if (!s_CommandActionMap.TryAdd(command, handler)) { s_CommandActionMap[command] = handler; } } public static void RemoveCommand(string cmd) { s_CommandActionMap.Remove(cmd); } public static void Clear() { s_CommandActionMap.Clear(); } public static bool IsLocalPlayer(int id) { return (int)StartOfRound.Instance.localPlayerController.playerClientId == id; } public static void InitialiseCommands() { AddCommand("!help", delegate(int id, string _) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("User can't call this command.", -1); } else { ClearChat(); s_CurrentHUD.AddTextToChatOnServer("Available Commands Are:\n" + GeneralExtensions.Join<KeyValuePair<string, Action<int, string>>>((IEnumerable<KeyValuePair<string, Action<int, string>>>)s_CommandActionMap, (Func<KeyValuePair<string, Action<int, string>>, string>)((KeyValuePair<string, Action<int, string>> x) => x.Key), "\n"), -1); } }); AddCommand("!ping", delegate { s_CurrentHUD.AddTextToChatOnServer("<color=blue>Pong!</color>", -1); }); AddCommand("!list", delegate(int id, string _) { string[] colours; if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("You can't invoke this command!", -1); } else { colours = new string[7] { "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF" }; Type t3 = typeof(AbstractLevelEvent); string text5 = GeneralExtensions.Join<string>(from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && t3.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select "<color=" + RandomColour() + ">" + x.Name + "</color>", (Func<string, string>)null, ", "); ClearChat(); s_CurrentHUD.AddTextToChatOnServer(text5, -1); } string RandomColour() { return colours[Random.RandomRangeInt(0, colours.Length)]; } }); AddCommand("!add", delegate(int id, string msg) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("<color=red>You can't invoke this command!</color>", -1); } else { string[] array2 = msg.Split(" "); if (array2.Length >= 2) { Type t2 = typeof(AbstractLevelEvent); { foreach (var (text4, type4) in (from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && t2.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select new Tuple<string, Type>(x.Name, x)).ToList()) { if (text4.Equals(array2[1])) { AbstractLevelEvent abstractLevelEvent = (AbstractLevelEvent)type4.GetConstructor(Type.EmptyTypes).Invoke(null); bool flag = LevelModifier.AddToGuaranteed(abstractLevelEvent); s_AddedEvents.Add(abstractLevelEvent); s_CurrentHUD.AddTextToChatOnServer(flag ? ("<color=green>Successfully added '" + text4 + "'</color>") : ("<color=red>Failed to add '" + text4 + "'</color>"), -1); break; } } return; } } s_CurrentHUD.AddTextToChatOnServer("<color=red>Error Expected Format is '!add LevelEvent'</color>", -1); } }); AddCommand("!remove", delegate(int id, string msg) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("You can't invoke this command!", -1); } else { string[] array = msg.Split(" "); if (array.Length >= 2) { Type t = typeof(AbstractLevelEvent); { foreach (var (text2, type2) in (from x in Assembly.GetAssembly(typeof(Plugin)).GetTypes() where !x.IsAbstract && t.IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null && x != typeof(RandomDifficulty) select new Tuple<string, Type>(x.Name, x)).ToList()) { if (text2.Equals(array[1])) { AbstractLevelEvent instance = (AbstractLevelEvent)type2.GetConstructor(Type.EmptyTypes).Invoke(null); s_CurrentHUD.AddTextToChatOnServer(LevelModifier.RemoveFromGuaranteed(instance) ? ("Successfully removed '" + text2 + "'") : ("Failed to remove '" + text2 + "'"), -1); break; } } return; } } s_CurrentHUD.AddTextToChatOnServer($"Error Expected Format is '{array} LevelEvent'", -1); } }); AddCommand("!reset", delegate(int id, string _) { if (!IsLocalPlayer(id)) { s_CurrentHUD.AddTextToChatOnServer("<color=red>User not allowed to do this.</color>", -1); } else { int num = s_AddedEvents.RemoveWhere(LevelModifier.RemoveFromGuaranteed); s_CurrentHUD.AddTextToChatOnServer($"Pruned {num} level events.", -1); } }); AddCommand("!clear", delegate(int id, string _) { if (IsLocalPlayer(id)) { ClearChat(); } }); AddCommand("!show_events", delegate(int id, string _) { if (IsLocalPlayer(id)) { ClearChat(); LevelModifier.PostCurrentModifiersTo(s_CurrentHUD); } }); AddCommand("!spawn_scrap", delegate(int id, string _) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (IsLocalPlayer(id)) { ClearChat(); Vector3 position = ((Component)StartOfRound.Instance.localPlayerController).transform.position; HashSet<string> hashSet = new HashSet<string>(); SelectableLevel[] levels = StartOfRound.Instance.levels; for (int i = 0; i < levels.Length; i++) { foreach (SpawnableItemWithRarity item in levels[i].spawnableScrap) { Item spawnableItem = item.spawnableItem; if (hashSet.Add(spawnableItem.itemName)) { GameObject obj = Object.Instantiate<GameObject>(spawnableItem.spawnPrefab); obj.GetComponent<GrabbableObject>().grabbable = true; obj.transform.position = position; obj.GetComponent<NetworkObject>().Spawn(true); } } } } }); } public static void ClearChat() { s_CurrentHUD.AddTextToChatOnServer(new string('\n', 30), -1); } [HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> IncreaseTextInputLimit(IEnumerable<CodeInstruction> xs) { foreach (CodeInstruction x in xs) { if (x.opcode == OpCodes.Ldc_I4_S && (sbyte)x.operand == 50) { yield return new CodeInstruction(OpCodes.Ldc_I4, (object)1024); } else { yield return x; } } } [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPrefix] private static void SetTextLimits(ref HUDManager __instance) { //IL_003f: 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_004a: Expected O, but got Unknown if (__instance.chatTextField.characterLimit == 1024) { return; } __instance.chatTextField.characterLimit = 1024; TMP_InputField chatTextField = __instance.chatTextField; object obj = <>c.<>9__11_0; if (obj == null) { OnValidateInput val = (string _, int _, char c) => c; <>c.<>9__11_0 = val; obj = (object)val; } chatTextField.onValidateInput = (OnValidateInput)obj; } } [BepInPlugin("LCCustomDifficulty", "LCCustomDifficulty", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static ManualLogSource LOGGER; public static Harmony HARMONY = new Harmony("LCCustomDifficulty"); private void Awake() { LOGGER = ((BaseUnityPlugin)this).Logger; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin LCCustomDifficulty is loaded!"); HARMONY.PatchAll(typeof(UtilityPatches)); HARMONY.PatchAll(typeof(GameDefaults)); HARMONY.PatchAll(typeof(LevelModifier)); try { LevelModifier.InitialiseLevelEvents(Assembly.GetExecutingAssembly()); LevelModifier.InitialiseLevelEvents(Assembly.GetAssembly(typeof(InstantEnemySpawner))); LevelModifier.InitialiseLevelEvents(Assembly.GetAssembly(typeof(EnemyEventRandomiser))); } catch (Exception ex) { LOGGER.LogError((object)("Error initialising level events; " + ex.Message + "\n" + ex.StackTrace)); } HARMONY.PatchAll(typeof(ExplosivePlayers)); HARMONY.PatchAll(typeof(MovingLandmines)); HARMONY.PatchAll(typeof(ExplosivePuffers)); HARMONY.PatchAll(typeof(ExplosiveItems)); HARMONY.PatchAll(typeof(NoisyPlayers)); HARMONY.PatchAll(typeof(RandomlyScaledEntities)); HARMONY.PatchAll(typeof(FreeItems)); HARMONY.PatchAll(typeof(MagneticBodies)); HARMONY.PatchAll(typeof(InstantEnemySpawner)); HARMONY.PatchAll(typeof(Jumpscare)); CommandSystem.InitialiseCommands(); HARMONY.PatchAll(typeof(CommandSystem)); } } public class RandomDifficulty : AbstractLevelEvent { private float m_Scalar; private float m_LogScalar; public RandomDifficulty() : base("Random Difficulty", -1.0, true, 1, true) { } public override bool Apply(ref SelectableLevel level) { //IL_0012: 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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected I4, but got Unknown //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Invalid comparison between Unknown and I4 //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Expected O, but got Unknown //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_049e: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Expected O, but got Unknown float num = new AnimationCurve((Keyframe[])(object)new Keyframe[5] { new Keyframe(0.33f, 1f), new Keyframe(0.45f, 2f), new Keyframe(0.66f, 3f), new Keyframe(0.85f, 4f), new Keyframe(1f, 5f) }).Evaluate(Random.Range(0f, 1f)); m_Scalar = Mathf.RoundToMultipleOf(num, 0.25f); m_LogScalar = 1f + Mathf.Log(Mathf.Pow(m_Scalar, 1.3f)); SelectableLevel obj = level; obj.minScrap += Mathf.CeilToInt(4f * m_Scalar); SelectableLevel obj2 = level; obj2.maxScrap += Mathf.CeilToInt(8f * m_Scalar); SelectableLevel obj3 = level; obj3.minTotalScrapValue += Mathf.CeilToInt(300f * m_Scalar); SelectableLevel obj4 = level; obj4.maxTotalScrapValue += Mathf.CeilToInt(850f * m_LogScalar); LevelWeatherType currentWeather = level.currentWeather; float num2 = (currentWeather - -1) switch { 0 => 1f, 1 => 1f, 2 => 1.15f, 3 => 1.25f, 4 => 1.25f, 5 => 1.75f, 6 => 3f, _ => 1f, }; level.minScrap = Mathf.CeilToInt((float)level.minScrap * num2); level.maxScrap = Mathf.CeilToInt((float)level.maxScrap * num2); level.minTotalScrapValue = Mathf.CeilToInt((float)level.minTotalScrapValue * num2); level.maxTotalScrapValue = Mathf.CeilToInt((float)level.maxTotalScrapValue * num2); level.minScrap = Math.Max(level.minScrap, 5); level.minScrap = Math.Max(level.maxScrap, 10); level.minTotalScrapValue = Math.Max(level.minTotalScrapValue, 500); level.maxTotalScrapValue = Math.Max(level.maxTotalScrapValue, 1000); level.maxEnemyPowerCount = 10000; level.maxDaytimeEnemyPowerCount = 10000; level.maxOutsideEnemyPowerCount = 10000; float num3 = new AnimationCurve((Keyframe[])(object)new Keyframe[7] { new Keyframe(1f, 0f), new Keyframe(1.5f, 0.15f), new Keyframe(2f, 0.25f), new Keyframe(2.5f, 0.75f), new Keyframe(3f, 1f), new Keyframe(4f, 2f), new Keyframe(5f, 3.5f) }).Evaluate(m_Scalar); if ((int)level.currentWeather == 5) { num3 += 6.5f; } float num4 = 3f + num3; AnimationCurve enemySpawnChanceThroughoutDay = new AnimationCurve((Keyframe[])(object)new Keyframe[5] { new Keyframe(0f, -7.5f + num4 * m_LogScalar), new Keyframe(0.15f, -6.5f + num4 * m_LogScalar), new Keyframe(0.25f, -1f + num4 * m_LogScalar), new Keyframe(0.55f, 5f + num4 * m_LogScalar), new Keyframe(1f, 15f) }); level.enemySpawnChanceThroughoutDay = enemySpawnChanceThroughoutDay; num4 = 1.3f + num3 * 0.4f; AnimationCurve val = new AnimationCurve((Keyframe[])(object)new Keyframe[5] { new Keyframe(0f, -7.5f + num4 * m_LogScalar), new Keyframe(0.15f, -5.8f + num4 * m_LogScalar), new Keyframe(0.25f, -2.5f + num4 * m_LogScalar), new Keyframe(0.55f, -1.5f + num4 * m_LogScalar), new Keyframe(1f, 5f) }); level.outsideEnemySpawnChanceThroughDay = val; AnimationCurve obj5 = Util.CloneCurve(val); obj5.keys = obj5.GetKeys().Reverse().Zip((IEnumerable<Keyframe>)val.GetKeys(), (Func<Keyframe, Keyframe, Keyframe>)((Keyframe l, Keyframe r) => new Keyframe(((Keyframe)(ref r)).time, ((Keyframe)(ref l)).value))) .ToArray(); level.Enemies.ForEach(delegate(SpawnableEnemyWithRarity x) { ApplyScalarToEnemy(x, 1.3f); }); level.DaytimeEnemies.ForEach(delegate(SpawnableEnemyWithRarity x) { ApplyScalarToEnemy(x, 1.3f); }); level.OutsideEnemies.ForEach(delegate(SpawnableEnemyWithRarity x) { ApplyScalarToEnemy(x, 1.3f); }); return true; static void ApplyScalarToEnemy(SpawnableEnemyWithRarity enemy, float scalar) { EnemyType enemyType = enemy.enemyType; if (enemyType.MaxCount > 0) { enemyType.MaxCount = (int)Math.Clamp(Math.Ceiling((float)enemyType.MaxCount * scalar), 0.0, 20.0); } } } public override string ToString() { float scalar = m_Scalar; string text = ((scalar <= 2f) ? $"Normal ({m_Scalar:F2})" : ((scalar <= 3f) ? $"Medium ({m_Scalar:F2})" : ((scalar <= 4f) ? $"Hard ({m_Scalar:F2})" : ((!(scalar <= 5f)) ? $"??? ({m_Scalar:F2})" : $"Insane ({m_Scalar:F2})")))); string text2 = text; return "<color=white>" + text2 + "</color>"; } } public class LandmineChaos : AbstractLevelEvent { public LandmineChaos() : base("Lots of Landmines", -1.0, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown SpawnableMapObject val = Util.FindMapObject<Landmine>(level); if (val == null) { val = Util.FindMapObject<Landmine>(); if (val == null) { Plugin.LOGGER.LogInfo((object)"Could not find a Landmine component in any level."); return false; } CollectionExtensions.AddToArray<SpawnableMapObject>(level.spawnableMapObjects, val); } val.numberToSpawn = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 200f), new Keyframe(1f, 75f + Random.Range(0f, 75f)) }); return true; } } public class TurretChaos : AbstractLevelEvent { private enum Mode { NORMAL, MEDIUM, IMPOSSIBLE } private Mode m_Mode; public TurretChaos() : base("Turret Chaos", 33.333333333333336, false, -1, false) { } public override bool Apply(ref SelectableLevel level) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown m_Mode = (Mode)Random.RandomRangeInt(0, 3); SpawnableMapObject val = Util.FindMapObject<Turret>(level); if (val == null) { val = Util.FindMapObject<Turret>(); if (val == null) { Plugin.LOGGER.LogInfo((object)"Could not find a Turret component in any level."); return false; } CollectionExtensions.AddToArray<SpawnableMapObject>(level.spawnableMapObjects, val); } val.numberToSpawn = new AnimationCurve(m_Mode switch { Mode.NORMAL => (Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 75f), new Keyframe(1f, 35f) }, Mode.MEDIUM => (Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 75f), new Keyframe(1f, 50f) }, Mode.IMPOSSIBLE => (Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 150f), new Keyframe(1f, 75f) }, _ => Util.ZeroCurve().keys, }); level.Enemies.ForEach(delegate(SpawnableEnemyWithRarity x) { if (!Util.EnemyIs<HoarderBugAI>(x) && !Util.EnemyIs<PufferAI>(x) && !Util.EnemyIs<BlobAI>(x)) { x.enemyType.probabilityCurve = Util.ZeroCurve(); x.enemyType.MaxCount = 0; x.rarity = 0; } }); int num = m_Mode switch { Mode.NORMAL => 500, Mode.MEDIUM => 1000, Mode.IMPOSSIBLE => 1500, _ => 0, }; SelectableLevel obj = level; obj.minTotalScrapValue += num; SelectableLevel obj2 = level; obj2.maxTotalScrapValue += num; int num2 = m_Mode switch { Mode.NORMAL => 5, Mode.MEDIUM => 10, Mode.IMPOSSIBLE => 20, _ => 0, }; SelectableLevel obj3 = level; obj3.minScrap += num2; SelectableLevel obj4 = level; obj4.maxScrap += num2; return true; } public override int CompareTo(AbstractLevelEvent other) { if (other != null && other.Name == Name) { return 0; } if (!(other is RandomDifficulty)) { return 1; } return -1; } public override string ToString() { return m_Mode switch { Mode.NORMAL => "Some Turrets", Mode.MEDIUM => "Lots of Turrets", Mode.IMPOSSIBLE => "A lot of Turrets", _ => "???", }; } } public class FreeItems : AbstractLevelEvent { private enum Item { WALKIE_TALKIE, FLASHLIGHT, SHOVEL, LOCK_PICKER, PRO_FLASHLIGHT, STUN_GRENADE, BOOMBOX, TZP_INHALANT, ZAP_GUN, JETPACK, EXTENSION_LADDER, RADAR_BOOSTER, SPRAY_PAINT, END_OF_ENUM } private enum Mode { RANDOM, USEFUL, USELESS, EXPLOSIONS, END_OF_ENUM } private static bool s_IsEnabled; private Mode m_Mode; public FreeItems() : base("Free Items!", 66.66666666666667, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { Terminal val = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val == (Object)null) { Plugin.LOGGER.LogInfo((object)"Could not find 'Terminal' object..."); return false; } if (Random.Range(0f, 1f) > 0.8f) { m_Mode = Mode.EXPLOSIONS; } else { m_Mode = (Mode)Random.RandomRangeInt(0, 3); } switch (m_Mode) { case Mode.RANDOM: { int num2 = Random.RandomRangeInt(2, 7); for (int j = 0; j < num2; j++) { val.orderedItemsFromTerminal.Add(Random.RandomRangeInt(0, 13)); } break; } case Mode.USEFUL: { int num3 = Random.RandomRangeInt(2, 5); Item[] array2 = new Item[6] { Item.SHOVEL, Item.PRO_FLASHLIGHT, Item.STUN_GRENADE, Item.ZAP_GUN, Item.JETPACK, Item.EXTENSION_LADDER }; for (int k = 0; k < num3; k++) { val.orderedItemsFromTerminal.Add((int)array2[Random.RandomRangeInt(0, array2.Length)]); } break; } case Mode.USELESS: { int num = Random.RandomRangeInt(2, 5); Item[] array = new Item[7] { Item.WALKIE_TALKIE, Item.FLASHLIGHT, Item.LOCK_PICKER, Item.BOOMBOX, Item.TZP_INHALANT, Item.RADAR_BOOSTER, Item.SPRAY_PAINT }; for (int i = 0; i < num; i++) { val.orderedItemsFromTerminal.Add((int)array[Random.RandomRangeInt(0, array.Length)]); } break; } case Mode.EXPLOSIONS: s_IsEnabled = true; val.orderedItemsFromTerminal.Add(9); break; } return true; } public override void OnMatchFinished() { s_IsEnabled = false; } public override string ToString() { string[] messages = new string[4] { "Random Items :)", "Useful Items :)", "Useless Items :(", "Explosive Delivery!" }; return m_Mode switch { Mode.RANDOM => messages[0], Mode.USEFUL => messages[1], Mode.USELESS => messages[2], Mode.EXPLOSIONS => GetExplosiveStr(), _ => "Should Not Happen; Error", }; string GetExplosiveStr() { int num = Random.RandomRangeInt(0, messages.Length); string text = messages[num]; if (num == messages.Length - 1) { return text; } char[] array = text.ToCharArray(); int num2 = Random.RandomRangeInt(0, array.Length); int num3 = Random.RandomRangeInt(0, array.Length); ref char reference = ref array[num2]; ref char reference2 = ref array[num3]; char c = array[num3]; char c2 = array[num2]; reference = c; reference2 = c2; return new string(array); } } [HarmonyPatch(typeof(ItemDropship), "Update")] [HarmonyPrefix] private static void ExplodeOnDropShipOpen(ref ItemDropship __instance) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (s_IsEnabled && __instance.shipDoorsOpened) { Plugin.LOGGER.LogInfo((object)"Drop Ship Opened!"); Vector3 position = ((Component)__instance).transform.position; ((MonoBehaviour)__instance).StartCoroutine(SpawnExplosionsAround(position, 8f, 24, 1f / 3f)); s_IsEnabled = false; } } private static IEnumerator SpawnExplosionsAround(Vector3 pos, float radius, int count, float delay) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) float theta = 360f / (float)count; Vector3 val = default(Vector3); for (int i = 0; i < count; i++) { float num = (float)i * theta; ((Vector3)(ref val))..ctor(radius * Mathf.Cos(MathF.PI / 180f * num), 0f, radius * Mathf.Sin(MathF.PI / 180f * num)); MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SpawnExplosionAt", true) .AddParams(new object[4] { pos + val, true, radius, radius * 1.5f }) .Broadcast(); yield return (object)new WaitForSeconds(delay); } } } public abstract class OnlyEnemyType : AbstractLevelEvent { protected struct EnemyData { public bool IsUntouched { get; set; } public int Rarity { get; set; } public int MaxCount { get; set; } public AnimationCurve DropOff { get; set; } public AnimationCurve SpawnCurve { get; set; } public EnemyData() { IsUntouched = false; Rarity = -1; MaxCount = -1; DropOff = null; SpawnCurve = null; } public void Apply(SpawnableEnemyWithRarity enemy) { if (!IsUntouched) { if (Rarity >= 0) { enemy.rarity = Rarity; } if (MaxCount >= 0) { enemy.enemyType.MaxCount = MaxCount; } if (DropOff != null) { enemy.enemyType.numberSpawnedFalloff = DropOff; } if (DropOff != null) { enemy.enemyType.probabilityCurve = SpawnCurve; } } } } protected static Tuple<bool, EnemyData> LowerChance(int rarity) { return new Tuple<bool, EnemyData>(item1: true, new EnemyData { Rarity = rarity, SpawnCurve = Util.ModerateCurve() }); } protected static Tuple<bool, EnemyData> AllowEnemy(EnemyData data) { return new Tuple<bool, EnemyData>(item1: true, data); } protected static Tuple<bool, EnemyData> AllowEnemyUntouched() { return new Tuple<bool, EnemyData>(item1: true, new EnemyData { IsUntouched = true }); } protected static Tuple<bool, EnemyData> DisallowEnemy() { return new Tuple<bool, EnemyData>(item1: false, new EnemyData()); } protected OnlyEnemyType(string name, double weight = 50.0, bool is_additive = false, int ordering = -1, bool natural_ordering = false, params string[] ordering_tags) : base(name, weight, is_additive, ordering, natural_ordering, ordering_tags) { } protected virtual IEnumerable<SpawnableEnemyWithRarity> IterateEnemies(SelectableLevel level) { return level.Enemies; } protected abstract Tuple<bool, EnemyData> IsEnemyAllowed(SpawnableEnemyWithRarity enemy); public override bool Apply(ref SelectableLevel level) { foreach (SpawnableEnemyWithRarity item in IterateEnemies(level)) { var (flag2, enemyData2) = IsEnemyAllowed(item); if (!flag2) { Util.ZeroEnemy(item); } enemyData2.Apply(item); } return true; } public override int CompareTo(AbstractLevelEvent other) { if (other != null && other.Name == Name) { return 0; } if (!(other is RandomDifficulty)) { return 1; } return -1; } } internal class RedLocustBeeChaos : OnlyEnemyType { public RedLocustBeeChaos() : base("Cunt with Wings", 40.0, true, -1, false) { } protected override IEnumerable<SpawnableEnemyWithRarity> IterateEnemies(SelectableLevel level) { return level.DaytimeEnemies; } protected override Tuple<bool, EnemyData> IsEnemyAllowed(SpawnableEnemyWithRarity enemy) { if (Util.EnemyIs<RedLocustBees>(enemy)) { enemy.rarity = 999; enemy.enemyType.MaxCount = 4; enemy.enemyType.numberSpawnedFalloff = Util.ModerateCurve(); enemy.enemyType.probabilityCurve = Util.MaxCurve(); } return OnlyEnemyType.AllowEnemyUntouched(); } } internal class ApexPredator : OnlyEnemyType { private enum Type { DOG, GIANT, WORM } private Type m_EnemyType; private int GetRarityFor(Type type) { if (m_EnemyType != type) { return 5; } return 90; } public ApexPredator() : base("Apex Predator", 66.66666666666667, true, -1, false) { } protected override IEnumerable<SpawnableEnemyWithRarity> IterateEnemies(SelectableLevel level) { m_EnemyType = (Type)Random.RandomRangeInt(0, 3); return level.OutsideEnemies; } protected override Tuple<bool, EnemyData> IsEnemyAllowed(SpawnableEnemyWithRarity enemy) { if (Util.EnemyIs<SandWormAI>(enemy)) { EnemyData data = new EnemyData(); data.Rarity = GetRarityFor(Type.WORM); data.MaxCount = 4; data.DropOff = Util.ModerateCurve(); data.SpawnCurve = Util.MaxCurve(); return OnlyEnemyType.AllowEnemy(data); } if (Util.EnemyIs<MouthDogAI>(enemy)) { EnemyData data = new EnemyData(); data.Rarity = GetRarityFor(Type.DOG); data.MaxCount = 4; data.DropOff = Util.ModerateCurve(); data.SpawnCurve = Util.MaxCurve(); return OnlyEnemyType.AllowEnemy(data); } if (Util.EnemyIs<ForestGiantAI>(enemy)) { EnemyData data = new EnemyData(); data.Rarity = GetRarityFor(Type.GIANT); data.MaxCount = 4; data.DropOff = Util.ModerateCurve(); data.SpawnCurve = Util.MaxCurve(); return OnlyEnemyType.AllowEnemy(data); } return OnlyEnemyType.DisallowEnemy(); } public override string ToString() { return m_EnemyType switch { Type.DOG => "Beware the Dogs", Type.GIANT => "POV You are a Snack", Type.WORM => "Tremors???", _ => "???", }; } } public class ExplosivePlayers : AbstractLevelEvent { private static bool s_IsEnabled = false; private static HashSet<ulong> s_KilledPlayers = new HashSet<ulong>(); [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPrefix] private static void SpawnExplosionOnPlayerDeath(ref PlayerControllerB __instance, ref Vector3 bodyVelocity, ref bool spawnBody, ref CauseOfDeath causeOfDeath, ref int deathAnimation) { if (s_IsEnabled && (int)causeOfDeath != 3 && s_KilledPlayers.Add(__instance.actualClientId)) { MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SpawnExplosionOnPlayer", true) .AddParam((float)__instance.actualClientId) .AddParams(new object[3] { true, 2f, 2f }) .Broadcast(); } } public ExplosivePlayers() : base("Explosive Players", 66.66666666666667, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { s_KilledPlayers.Clear(); s_IsEnabled = true; return true; } public override void OnMatchFinished() { s_IsEnabled = false; } } public class ExplosivePuffers : AbstractLevelEvent { private static bool s_IsEnabled; [HarmonyPatch(typeof(PufferAI), "StompClientRpc")] [HarmonyPostfix] private static void OnPuffExplode(PufferAI __instance) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (s_IsEnabled) { MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SpawnExplosionAt", true) .AddParam(((Component)__instance).transform.position) .AddParam(true) .AddParam(5f) .AddParam(7.5f) .Broadcast(); } } public ExplosivePuffers() : base("Huff and Puff", 50.0, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { SpawnableEnemyWithRarity val = Util.FindInsideEnemy<PufferAI>(level); if (val == null) { return false; } s_IsEnabled = true; val.rarity = 999; val.enemyType.MaxCount = 5; val.enemyType.numberSpawnedFalloff = Util.ModerateCurve(); val.enemyType.probabilityCurve = Util.MaxCurve(); return true; } public override void OnMatchFinished() { s_IsEnabled = false; } } public class ExplosiveItems : AbstractLevelEvent { public static bool s_IsEnabled; public ExplosiveItems() : base("Explosive Items?", 33.333333333333336, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { s_IsEnabled = true; return true; } public override void OnMatchFinished() { s_IsEnabled = false; } public static void OnItemActivateImpl(GrabbableObject item, bool is_used) { if (s_IsEnabled && is_used && !((Object)(object)item.playerHeldBy == (Object)null)) { MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SpawnExplosionOnPlayer", true) .AddParam((float)item.playerHeldBy.actualClientId) .AddParams(new object[3] { true, 2f, 2f }) .Broadcast(); } } [HarmonyPatch(typeof(StunGrenadeItem), "ItemActivate")] [HarmonyPrefix] private static void ExplodeStunGrenadeOnActivate(ref StunGrenadeItem __instance, ref bool used, ref bool buttonDown) { OnItemActivateImpl((GrabbableObject)(object)__instance, used); } [HarmonyPatch(typeof(BoomboxItem), "ItemActivate")] [HarmonyPrefix] private static void ExplodeBoomboxOnActivate(ref BoomboxItem __instance, ref bool used, ref bool buttonDown) { OnItemActivateImpl((GrabbableObject)(object)__instance, used); } [HarmonyPatch(typeof(FlashlightItem), "ItemActivate")] [HarmonyPrefix] private static void ExplodeFlashlightOnActivate(ref FlashlightItem __instance, ref bool used, ref bool buttonDown) { OnItemActivateImpl((GrabbableObject)(object)__instance, used); } [HarmonyPatch(typeof(ExtensionLadderItem), "ItemActivate")] [HarmonyPrefix] public static void ExplodeLadderOnActivate(ref ExtensionLadderItem __instance, ref bool used, ref bool buttonDown) { OnItemActivateImpl((GrabbableObject)(object)__instance, used); } } public class MovingLandmines : AbstractLevelEvent { private enum Mode { SLOW, NORMAL, FAST, VERY_FAST } private static bool s_IsEnabled; private static StartOfRound s_StartOfRound; private static MovingLandmines s_Instance; private Mode m_Mode; [HarmonyPatch(typeof(Landmine), "Update")] [HarmonyPrefix] private static void LandmineUpdate(ref Landmine __instance) { //IL_0033: 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_003b: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!s_IsEnabled || (Object)(object)s_StartOfRound == (Object)null || s_StartOfRound.inShipPhase || __instance.hasExploded) { return; } Transform transform = ((Component)__instance).transform; Vector3 position = transform.position; Vector3 val = default(Vector3); float num = float.MaxValue; PlayerControllerB val2 = null; PlayerControllerB[] allPlayerScripts = s_StartOfRound.allPlayerScripts; foreach (PlayerControllerB val3 in allPlayerScripts) { if (val3.isPlayerDead) { continue; } Vector3 position2 = ((Component)val3).transform.position; if (!(Mathf.Abs(position2.y - position.y) > 0.15f)) { float num2 = Vector3.Distance(position, position2); if (!(num2 > 4f) && !(num2 < 1.75f) && num2 < num) { val2 = val3; num = num2; val = position2; } } } if (!((Object)(object)val2 == (Object)null)) { Vector3 val4 = val - position; ((Vector3)(ref val4)).Normalize(); transform.position += val4 * s_Instance.Speed() * Time.deltaTime; } } public MovingLandmines() : base("Is that a Roomba???", 33.333333333333336, false, -1, true) { } public override bool Apply(ref SelectableLevel level) { s_StartOfRound = StartOfRound.Instance; s_Instance = this; m_Mode = (Mode)Random.RandomRangeInt(0, 3); if (Random.Range(0f, 1f) <= 0.05f) { m_Mode = Mode.VERY_FAST; } s_IsEnabled = true; MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(false) .AddParam("MovingLandmines", true) .AddParam(true) .AddParam(Speed()) .Broadcast(); return true; } public float Speed() { return m_Mode switch { Mode.SLOW => 1.01f, Mode.NORMAL => 1.025f, Mode.FAST => 1.05f, Mode.VERY_FAST => 3f, _ => 1.01f, }; } public override void OnMatchFinished() { s_IsEnabled = false; MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(false) .AddParam("MovingLandmines", true) .AddParam(false) .AddParam(0f) .Broadcast(); } public override string ToString() { return m_Mode switch { Mode.SLOW => "Slow Roomba", Mode.NORMAL => "Normal Roomba", Mode.FAST => "Fast Roomba", Mode.VERY_FAST => "Ka-Chow Roomba", _ => "??? Roomba", }; } } public class NoisyPlayers : AbstractLevelEvent { private static bool s_IsEnabled; private static float s_Theta; [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPrefix] private static void PlayNoisePeriodically() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!s_IsEnabled || StartOfRound.Instance.inShipPhase) { return; } s_Theta -= Time.deltaTime; if (!(s_Theta > 0f)) { s_Theta = Random.Range(0.5f, 10f); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { RoundManager.Instance.PlayAudibleNoise(((Component)val).transform.position, 35f, 1.5f, 0, val.isInHangarShipRoom && val.playersManager.hangarDoorsClosed, 7); } } } public NoisyPlayers() : base("Noisy Players", 40.0, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { return s_IsEnabled = true; } public override void OnMatchFinished() { s_IsEnabled = false; } } public class RandomlyScaledEntities : AbstractLevelEvent { public static bool s_IsEnabled = false; private static float s_PollingTime = 0f; private static HashSet<ulong> s_ModifiedEnemies = new HashSet<ulong>(); public RandomlyScaledEntities() : base("Big or Small?", -1.0, true, -1, true) { } [HarmonyPatch(typeof(RoundManager), "Update")] [HarmonyPrefix] public static void SetEnemyScaleOnCreation(ref RoundManager __instance) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!s_IsEnabled) { return; } s_PollingTime -= Time.deltaTime; if (s_PollingTime > 0f) { return; } s_PollingTime = 0.5f; foreach (EnemyAI spawnedEnemy in __instance.SpawnedEnemies) { if (s_ModifiedEnemies.Add(spawnedEnemy.thisNetworkObject.NetworkObjectId)) { float num = Random.Range(0.5f, 1.5f); MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SetEnemyScale", true) .AddParam((float)spawnedEnemy.thisNetworkObject.NetworkObjectId) .AddParam(new Vector3(num, num, num)) .AddDelaySeconds(5f) .Broadcast(); } } } public override bool Apply(ref SelectableLevel level) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) s_IsEnabled = true; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && (val.actualClientId != 0L || val.isHostPlayerObject)) { float num = Random.Range(0.35f, 1.35f); MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SetPlayerScale", true) .AddParam((float)val.actualClientId) .AddParam(new Vector3(num, num, num)) .Broadcast(); } } return true; } public override void OnMatchFinished() { s_IsEnabled = false; s_ModifiedEnemies.Clear(); MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("ResetAllPlayerScales", true) .Broadcast(); } } public class MagneticBodies : AbstractLevelEvent { private static bool s_IsEnabled; private static float s_Timer; public MagneticBodies() : base("Magneto", 33.333333333333336, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { Plugin.LOGGER.LogInfo((object)"Enabling Magneto Mode"); s_IsEnabled = true; return true; } public override void OnMatchFinished() { s_IsEnabled = false; } [HarmonyPatch(typeof(DeadBodyInfo), "Update")] [HarmonyPrefix] private static void PeriodicallyThrowBodyAtNearestPlayer(ref DeadBodyInfo __instance) { //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) //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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) if (!s_IsEnabled || __instance.isInShip || __instance.deactivated || __instance.grabBodyObject.isHeld) { return; } s_Timer -= Time.deltaTime; if (s_Timer > 0f) { return; } s_Timer = Random.Range(1.5f, 3f); Vector3 position = ((Component)__instance).transform.position; Transform val = null; Vector3 val2 = default(Vector3); float num = 0f; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val3 in allPlayerScripts) { if (!val3.isPlayerDead && (val3.actualClientId != 0L || val3.isHostPlayerObject)) { Transform transform = ((Component)val3).transform; Vector3 position2 = transform.position; float num2 = Vector3.Distance(position, position2); if ((Object)(object)val == (Object)null || num2 < num) { val = transform; val2 = position2; num = num2; } } } Plugin.LOGGER.LogInfo((object)("Closest Player == " + ((object)val)?.ToString() + "; Distance = " + num)); if (!((Object)(object)val == (Object)null) && !(num > 30f) && !(num < 3f)) { Vector3 val4 = val2 - position + new Vector3(0f, 1f, 0f); ((Vector3)(ref val4)).Normalize(); Plugin.LOGGER.LogInfo((object)$"Launching Body towards player: {num:F2}"); Vector3 val5 = val4 * num * 20f; MessageBuilder.Create().SetSourceClientToLocal().SetTargetClientAll(true) .AddParam("SetForceToAllBodyParts", true) .AddParam((float)__instance.playerScript.actualClientId) .AddParam(val5) .AddParam(position) .AddParam(val2 + new Vector3(0f, 1.5f, 0f)) .Broadcast(); } } } public class OnlyClownHorns : AbstractLevelEvent { private List<SpawnableItemWithRarity> m_OriginalItems = new List<SpawnableItemWithRarity>(); private SelectableLevel m_PreviousLevel; public OnlyClownHorns() : base("They Gave Me Clown Juice!", 40.0, true, -1, true) { } public override bool Apply(ref SelectableLevel level) { m_OriginalItems.Clear(); m_OriginalItems = level.spawnableScrap.ToList(); m_PreviousLevel = level; level.spawnableScrap.Clear(); foreach (SpawnableItemWithRarity originalItem in m_OriginalItems) { if (originalItem.spawnableItem.itemName == "Clown horn") { level.spawnableScrap.Add(originalItem); } } return true; } public override void OnMatchFinished() { m_PreviousLevel.spawnableScrap.Clear(); foreach (SpawnableItemWithRarity originalItem in m_OriginalItems) { m_PreviousLevel.spawnableScrap.Add(originalItem); } } } public class Jumpscare : AbstractLevelEvent { public interface IScareEvent { double Weight { get; } string Name() { return GetType().Name; } void Apply(ScareablePlayer scareable, PlayerControllerB p); } public class EmptyScareEvent : IScareEvent { public double Weight => 1.5; public void Apply(ScareablePlayer scareable, PlayerControllerB p) { Plugin.LOGGER.LogInfo((object)"Empty Scare Event Triggering!"); } } public class ScareablePlayer { private static WeightedRandom<IScareEvent> s_ScareRandom; public PlayerControllerB Player { get; set; } public float TimeUntilNextScare { get; set; } public int ScareCount { get; set; } public IScareEvent LastScare { get; set; } public ScareablePlayer(PlayerControllerB player) { Player = player; AdvanceState(); if (s_ScareRandom == null) { Type scare_type = typeof(IScareEvent); s_ScareRandom = new WeightedRandom<IScareEvent>((from x in Assembly.GetExecutingAssembly().GetTypes() where !x.IsAbstract && !x.IsInterface && scare_type.IsAssignableFrom(x) select x.GetConstructor(Type.EmptyTypes) into x where x != null select (IScareEvent)x.Invoke(null) into x select WeightedParameterFactory.Create(x, x.Weight)).ToList()); double sum = s_ScareRandom.WeightSum; string text = GeneralExtensions.Join<WeightedParameter<IScareEvent>>((IEnumerable<WeightedParameter<IScareEvent>>)s_ScareRandom.WeightedParameters, (Func<WeightedParameter<IScareEvent>, string>)((WeightedParameter<IScareEvent> x) => $"{x.Value.Name(),16} => {Util.GetWeightAsPercentage(x.Weight, sum):F2}"), ", "); Plugin.LOGGER.LogInfo((object)("Jumpscare Events => '" + text + "'")); } } public bool CanScare() { return TimeUntilNextScare <= 0f; } public void AdvanceState() { int scareCount = ScareCount + 1; ScareCount = scareCount; float num = 30f * (float)ScareCount; TimeUntilNextScare = Random.Range(60f + num, 80f + num); if (ScareCount > 5) { ScareCount = 0; } } public IScareEvent GetNextScareType(bool adjust_last = true) { IScareEvent scareEvent; do { scareEvent = s_ScareRandom.Next(); } while (LastScare != null && scareEvent.Name() == LastScare.Name()); if (adjust_last) { LastScare = scareEvent; } return scareEvent; } } private static bool s_IsEnabled = false; private static List<ScareablePlayer> s_ScareStats = new List<ScareablePlayer>(); public Jumpscare() : base("The Boogieman", 50.0, false, -1, true) { } public override bool Apply(ref SelectableLevel level) { s_ScareStats.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.isPlayerControlled && (val.actualClientId != 0L || val.isHostPlayerObject)) { s_ScareStats.Add(new ScareablePlayer(val)); } } s_IsEnabled = true; return true; } public override void OnMatchFinished() { s_IsEnabled = false; } [HarmonyPatch(typeof(StartOfRound), "Update")] [HarmonyPrefix] private static void PerformJumpscarePeriodically(StartOfRound __instance) { if (!s_IsEnabled || __instance.inShipPhase || __instance.shipIsLeaving) { return; } foreach (ScareablePlayer s_ScareStat in s_ScareStats) { PlayerControllerB player = s_ScareStat.Player; if (!player.isPlayerDead && !player.isInElevator) { s_ScareStat.TimeUntilNextScare -= Time.deltaTime; if (s_ScareStat.CanScare()) { s_ScareStat.AdvanceState(); IScareEvent nextScareType = s_ScareStat.GetNextScareType(); Plugin.LOGGER.LogInfo((object)("Applying Jumpscare '" + nextScareType.Name() + "' to player '" + player.playerUsername + "'")); nextScareType.Apply(s_ScareStat, s_ScareStat.Player); } } } } } public class LethalScareEvent : Jumpscare.IScareEvent { private static List<SpawnableEnemyWithRarity> s_Enemies; public double Weight => 6.5; public void Apply(Jumpscare.ScareablePlayer scareable, PlayerControllerB p) { if (s_Enemies == null) { s_Enemies = new List<SpawnableEnemyWithRarity> { Util.FindInsideEnemy<FlowermanAI>(), Util.FindInsideEnemy<SpringManAI>(), Util.FindInsideEnemy<NutcrackerEnemyAI>(), Util.FindInsideEnemy<MaskedPlayerEnemy>(), Util.FindInsideEnemy<SandSpiderAI>() }; s_Enemies.RemoveAll(delegate(SpawnableEnemyWithRarity x) { if (x != null) { return false; } Plugin.LOGGER.LogInfo((object)"LethalScareEvent :: Lethal Enemy was not found."); return true; }); } ((MonoBehaviour)p).StartCoroutine(TrackPlayerAndSpawnEnemy(p)); } private IEnumerator TrackPlayerAndSpawnEnemy(PlayerControllerB p) { Transform transform = ((Component)p).transform; Tuple<bool, Vector3>[] positions = new Tuple<bool, Vector3>[10]; for (int i = 0; i < positions.Length; i++) { positions[i] = new Tuple<bool, Vector3>(p.isInsideFactory, transform.position); yield return (object)new WaitForSeconds(Random.Range(0.1f, 0.2f)); } string text = GeneralExtensions.Join<Vector3>(positions.Select((Tuple<bool, Vector3> x) => x.Item2), (Func<Vector3, string>)((Vector3 p) => $"({p.x:F2}, {p.y:F2}, {p.z:F2})"), ", "); Plugin.LOGGER.LogInfo((object)("Jumpscare :: Tracked Player Positions '" + text + "'")); Vector3 position = transform.position; Vector3 val = Vector3.zero; float num = -1f; Tuple<bool, Vector3>[] array = positions; for (int j = 0; j < array.Length; j++) { var (flag2, val3) = array[j]; if (p.isInsideFactory == flag2) { float num2 = Vector3.Distance(position, val3); if (!(num > num2)) { val = val3; num = num2; } } } if (num < 0f) { Plugin.LOGGER.LogInfo((object)"No valid points were found for the player to spawn a dangerous enemy on"); yield break; } SpawnableEnemyWithRarity val4; if (p.isInsideFactory) { val4 = s_Enemies[Random.RandomRangeInt(0, s_Enemies.Count)]; } else { SpawnableEnemyWithRarity val5 = Util.FindOutsideEnemy<MouthDogAI>(); SpawnableEnemyWithRarity val6 = Util.FindOutsideEnemy<ForestGiantAI>(); if (val5 == null && val6 != null) { val4 = val6; } else if (val6 == null && val5 != null) { val4 = val5; } else { if (val5 == null) { Plugin.LOGGER.LogInfo((object)"LethalScareEvent :: Could not find MouthDogAI"); yield break; } val4 = ((Random.Range(0f, 1f) < 0.66f) ? val5 : val6); } } Plugin.LOGGER.LogInfo((object)("LethalScareEvent :: Spawning '" + val4.enemyType.enemyName + "' at " + $"'{val}' to scare player " + "'" + p.playerUsername + "'")); GameObject instance = Object.Instantiate<GameObject>(val4.enemyType.enemyPrefab, val + new Vector3(0f, 1f, 0f), Quaternion.Euler(Vector3.zero)); if (RandomlyScaledEntities.s_IsEnabled) { float num3 = Random.Range(0.4f, 1.35f); instance.transform.localScale = new Vector3(num3, num3, num3); } instance.GetComponentInChildren<NetworkObject>().Spawn(true); yield return (object)new WaitForSeconds(90f); if (!((Object)(object)instance == (Object)null)) { instance.GetComponentInChildren<NetworkObject>().Despawn(true); } } } public class LandmineScareEvent : Jumpscare.IScareEvent { public double Weight => 2.0; public void Apply(Jumpscare.ScareablePlayer scareable, PlayerControllerB p) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) ((MonoBehaviour)p).StartCoroutine(SpawnLandmineDelayed(((Component)p).transform.position, Random.Range(0.05f, 0.5f))); } private static IEnumerator SpawnLandmineDelayed(Vector3 pos, float delay_seconds) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) SpawnableMapObject mine = Util.FindMapObject<Landmine>(); yield return (object)new WaitForSeconds(delay_seconds); GameObject instance = Object.Instantiate<GameObject>(mine.prefabToSpawn); instance.transform.position = pos; float num = Random.Range(0.35f, 1.15f); instance.transform.localScale = new Vector3(num, 1f, num); instance.GetComponent<NetworkObject>().Spawn(true); yield return (object)new WaitForSeconds(45f); if (!((Object)(object)instance == (Object)null)) { instance.GetComponent<NetworkObject>().Despawn(true); } } } public class TurretScareEvent : Jumpscare.IScareEvent { public double Weight => 3.0; public void Apply(Jumpscare.ScareablePlayer scareable, PlayerControllerB p) { if (p.isInsideFactory) { ((MonoBehaviour)p).StartCoroutine(SpawnTurretDelayed(p, Random.Range(0.1f, 0.5f))); } } private static IEnumerator SpawnTurretDelayed(PlayerControllerB p, float delay_seconds) { Transform transform = ((Component)p).transform; Vector3 player_pos = transform.position; Quaternion player_rotate = transform.rotation; yield return (object)new WaitForSeconds(delay_seconds); if (!p.isInsideFactory) { yield break; } SpawnableMapObject val = Util.FindMapObject<Turret>(); if (val != null) { GameObject instance = Object.Instantiate<GameObject>(val.prefabToSpawn, player_pos, player_rotate); instance.GetComponentInChildren<NetworkObject>().Spawn(true); yield return (object)new WaitForSeconds(90f); if (!((Object)(object)instance == (Object)null)) { instance.GetComponentInChildren<NetworkObject>().Despawn(true); } } } } public static class LevelModifier { private static WeightedRandom<AbstractLevelEvent> s_LevelEventRandom = new WeightedRandom<AbstractLevelEvent>(); private static List<AbstractLevelEvent> s_GuaranteedLevelEvents = new List<AbstractLevelEvent>(); private static SortedSet<AbstractLevelEvent> s_ActiveEvents = new SortedSet<AbstractLevelEvent>(); public static void InitialiseLevelEvents(Assembly asm = null) { Type type = typeof(AbstractLevelEvent); List<AbstractLevelEvent> list = (from x in (asm ?? Assembly.GetExecutingAssembly()).GetTypes() where type.IsAssignableFrom(x) && !x.IsAbstract select x.GetConstructor(Type.EmptyTypes) into x where x != null select (AbstractLevelEvent)x.Invoke(null)).ToList(); HashSet<AbstractLevelEvent> hashSet = new HashSet<AbstractLevelEvent>(); HashSet<AbstractLevelEvent> hashSet2 = new HashSet<AbstractLevelEvent>(); foreach (AbstractLevelEvent item3 in list) { if (item3.IsGuaranteed()) { hashSet.Add(item3); } else { hashSet2.Add(item3); } } foreach (AbstractLevelEvent s_GuaranteedLevelEvent in s_GuaranteedLevelEvents) { if (s_GuaranteedLevelEvent.IsGuaranteed()) { hashSet.Add(s_GuaranteedLevelEvent); } else { hashSet2.Add(s_GuaranteedLevelEvent); } } AbstractLevelEvent item; double item2; foreach (WeightedParameter<AbstractLevelEvent> weightedParameter in s_LevelEventRandom.WeightedParameters) { weightedParameter.Deconstruct(out item, out item2); AbstractLevelEvent abstractLevelEvent = item; if (abstractLevelEvent.IsGuaranteed()) { hashSet.Add(abstractLevelEvent); } else { hashSet2.Add(abstractLevelEvent); } } List<WeightedParameter<AbstractLevelEvent>> list2 = new List<WeightedParameter<AbstractLevelEvent>>(); foreach (AbstractLevelEvent item4 in hashSet2) { list2.Add(new WeightedParameter<AbstractLevelEvent>(item4, item4.Weight)); } s_LevelEventRandom = new WeightedRandom<AbstractLevelEvent>(list2); s_GuaranteedLevelEvents = hashSet.ToList(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[GUARANTEED LEVEL EVENTS]"); foreach (AbstractLevelEvent s_GuaranteedLevelEvent2 in s_GuaranteedLevelEvents) { stringBuilder.AppendLine($"\t-1.00% => {s_GuaranteedLevelEvent2.Name,32}"); } stringBuilder.AppendLine("[WEIGHTED LEVEL EVENTS]"); double weightSum = s_LevelEventRandom.WeightSum; foreach (WeightedParameter<AbstractLevelEvent> weightedParameter2 in s_LevelEventRandom.WeightedParameters) { weightedParameter2.Deconstruct(out item, out item2); AbstractLevelEvent abstractLevelEvent2 = item; double weightAsPercentage = Util.GetWeightAsPercentage(item2, weightSum); stringBuilder.AppendLine($"\t{weightAsPercentage:F2}% => {abstractLevelEvent2.Name,32}, {abstractLevelEvent2.IsAdditive}"); } Plugin.LOGGER.LogInfo((object)("ALL LEVEL EVENTS ARE\n" + stringBuilder)); } public static bool AddToGuaranteed(AbstractLevelEvent instance) { if (s_GuaranteedLevelEvents.Contains(instance)) { return false; } s_GuaranteedLevelEvents.Add(instance); return true; } public static bool RemoveFromGuaranteed(AbstractLevelEvent instance) { return s_GuaranteedLevelEvents.Remove(instance); } [HarmonyPatch(typeof(RoundManager), "LoadNewLevel")] [HarmonyPrefix] public static void ModifyLevel(ref SelectableLevel newLevel) { try { Plugin.LOGGER.LogInfo((object)"LevelModifier::ModifyLevel(...) Starting"); HUDManager.Instance.AddTextToChatOnServer("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", -1); if (newLevel.sceneName == "CompanyBuilding") { return; } GameDefaults.ResetLevel(newLevel); Plugin.LOGGER.LogInfo((object)"Disabling Active Events"); foreach (AbstractLevelEvent s_ActiveEvent in s_ActiveEvents) { if (s_ActiveEvent == null) { Plugin.LOGGER.LogWarning((object)"Level Event is null?"); } else { s_ActiveEvent.OnMatchFinished(); } } s_ActiveEvents.Clear(); s_GuaranteedLevelEvents.ForEach(delegate(AbstractLevelEvent x) { s_ActiveEvents.Add(x); }); int num = Random.RandomRangeInt(2, 5); int num2 = 0; AbstractLevelEvent abstractLevelEvent; do { abstractLevelEvent = s_LevelEventRandom.Next(); if (abstractLevelEvent == null) { Plugin.LOGGER.LogWarning((object)"Level Event is null..."); continue; } bool flag = s_ActiveEvents.Add(abstractLevelEvent); if (flag) { num2++; } Plugin.LOGGER.LogInfo((object)("[LevelEvent] " + abstractLevelEvent.Name + "," + $" Additive? {abstractLevelEvent.IsAdditive}," + $" Added? {flag}," + $" Exists? {s_ActiveEvents.Contains(abstractLevelEvent)}")); } while (abstractLevelEvent != null && abstractLevelEvent.IsAdditive && num2 < num); Plugin.LOGGER.LogInfo((object)"Finalising Level Events..."); SortedSet<AbstractLevelEvent> sortedSet = new SortedSet<AbstractLevelEvent>(s_ActiveEvents); foreach (AbstractLevelEvent s_ActiveEvent2 in s_ActiveEvents) { s_ActiveEvent2.Finalise(sortedSet); } s_ActiveEvents.IntersectWith(sortedSet); Plugin.LOGGER.LogInfo((object)$"Applying '{s_ActiveEvents.Count}' Level Events"); foreach (AbstractLevelEvent s_ActiveEvent3 in s_ActiveEvents) { string text = (s_ActiveEvent3.Apply(ref newLevel) ? "Success" : "Fail"); Plugin.LOGGER.LogInfo((object)("Applying Level Event: '" + s_ActiveEvent3.Name + "' -> '" + text + "'")); } Plugin.LOGGER.LogInfo((object)Util.LevelToString(newLevel)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Level Events are: "); stringBuilder.Append(GeneralExtensions.Join<AbstractLevelEvent>((IEnumerable<AbstractLevelEvent>)s_ActiveEvents, (Func<AbstractLevelEvent, string>)((AbstractLevelEvent x) => x.ToString()), ", ")); Plugin.LOGGER.LogInfo((object)stringBuilder.ToString()); HUDManager.Instance.AddTextToChatOnServer(stringBuilder.ToString(), -1); Plugin.LOGGER.LogInfo((object)"LevelModifier::ModifyLevel(...) Finished"); } catch (Exception ex) { Plugin.LOGGER.LogError((object)("Error Applying Level Events; '" + ex.Message + "'\n" + ex.StackTrace)); } } public static void PostCurrentModifiersTo(HUDManager current_hud) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Level Events are: "); stringBuilder.Append(GeneralExtensions.Join<AbstractLevelEvent>((IEnumerable<AbstractLevelEvent>)s_ActiveEvents, (Func<AbstractLevelEvent, string>)((AbstractLevelEvent x) => x.ToString()), ", ")); current_hud.AddTextToChatOnServer(stringBuilder.ToString(), -1); } } public static class Util { public static AnimationCurve ZeroCurve() { //IL_0012: 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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown return new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 0f), new Keyframe(1f, 0f) }); } public static AnimationCurve ModerateCurve() { //IL_0012: 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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown return new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 10f), new Keyframe(1f, 100f) }); } public static AnimationCurve MaxCurve() { //IL_0012: 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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown return new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 999f), new Keyframe(1f, 999f) }); } public static AnimationCurve CloneCurve(AnimationCurve curve) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown return new AnimationCurve(((IEnumerable<Keyframe>)curve.GetKeys()).Select((Func<Keyframe, Keyframe>)((Keyframe x) => new Keyframe(((Keyframe)(ref x)).time, ((Keyframe)(ref x)).value))).ToArray()); } public static AnimationCurve CloneCurveAction(AnimationCurve curve, Func<float, float, Keyframe> action) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown return new AnimationCurve((from x in curve.GetKeys() select action(((Keyframe)(ref x)).time, ((Keyframe)(ref x)).value)).ToArray()); } public static List<Enemy> CloneEnemies(List<SpawnableEnemyWithRarity> xs) { return xs.Select((SpawnableEnemyWithRarity x) => new Enemy(x)).ToList(); } public static List<MapObject> CloneMapObjects(IEnumerable<SpawnableMapObject> xs) { return xs.Select((SpawnableMapObject x) => new MapObject(x)).ToList(); } public static SpawnableMapObject FindMapObject<T>(SelectableLevel level) { return ((IEnumerable<SpawnableMapObject>)level.spawnableMapObjects).FirstOrDefault((Func<SpawnableMapObject, bool>)delegate(SpawnableMapObject x) { if (x == null) { return false; } return !((Object)(object)x.prefabToSpawn == (Object)null) && x.prefabToSpawn.GetComponentInChildren<T>() != null; }); } public static SpawnableMapObject FindMapObject<T>() { return StartOfRound.Instance.levels.SelectMany((SelectableLevel x) => x.spawnableMapObjects).FirstOrDefault((Func<SpawnableMapObject, bool>)((SpawnableMapObject x) => x.prefabToSpawn.GetComponentInChildren<T>() != null)); } public static SpawnableEnemyWithRarity FindInsideEnemy<T>(SelectableLevel level) { SpawnableEnemyWithRarity? obj = ((IEnumerable<SpawnableEnemyWithRarity>)level.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity x) => x.enemyType.enemyPrefab.GetComponentInChildren<T>() != null)); if (obj == null) { Plugin.LOGGER.LogInfo((object)("Could not find enemy in level '" + level.sceneName + "'")); } return obj; } public static SpawnableEnemyWithRarity FindInsideEnemy<T>() { return StartOfRound.Instance.levels.SelectMany((SelectableLevel x) => x.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity x) => x.enemyType.enemyPrefab.GetComponentInChildren<T>() != null)); } public static AnimationCurve CloneCurveScaled(AnimationCurve curve, float scalar, Func<float, float> clamping_fn = null) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown if (clamping_fn == null) { clamping_fn = Mathf.Abs; } return new AnimationCurve(((IEnumerable<Keyframe>)curve.GetKeys()).Select((Func<Keyframe, Keyframe>)((Keyframe x) => new Keyframe(((Keyframe)(ref x)).time, clamping_fn(((Keyframe)(ref x)).value * scalar)))).ToArray()); } public static string CurveToString(AnimationCurve curve) { return GeneralExtensions.Join<Keyframe>((IEnumerable<Keyframe>)curve.GetKeys(), (Func<Keyframe, string>)((Keyframe x) => $"( {((Keyframe)(ref x)).time,5:F2}, {((Keyframe)(ref x)).value,5:F2} )"), ", "); } public static string LevelToString(SelectableLevel level) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[Level :: '" + level.sceneName + "']"); stringBuilder.AppendLine("\tScrap Count: " + level.minScrap + ", " + level.maxScrap); stringBuilder.AppendLine("\tScrap Value: " + level.minTotalScrapValue + ", " + level.maxTotalScrapValue); stringBuilder.AppendLine("\t[SCRAP] (Worth, MinValue, MaxValue, Weight, IsTwoHanded)\n"); stringBuilder.AppendLine(GeneralExtensions.Join<SpawnableItemWithRarity>((IEnumerable<SpawnableItemWithRarity>)level.spawnableScrap, (Func<SpawnableItemWithRarity, string>)delegate(SpawnableItemWithRarity x) { Item spawnableItem = x.spawnableItem; return string.Format("\t{0,32} => {1,4},", "'" + spawnableItem.itemName + "'", spawnableItem.creditsWorth) + $" {spawnableItem.minValue,4} <= V <= {spawnableItem.maxValue,4}," + $" {spawnableItem.weight,5}, {spawnableItem.twoHanded,5}"; }, ",\n")); stringBuilder.AppendLine("\tEnemy Power (Inside) : " + level.maxEnemyPowerCount); stringBuilder.AppendLine("\tEnemy Power (Outside): " + level.maxOutsideEnemyPowerCount); stringBuilder.AppendLine("\tEnemy Power (Daytime): " + level.maxDaytimeEnemyPowerCount); stringBuilder.AppendLine("\tSpawn Curve (Inside): " + CurveToString(level.enemySpawnChanceThroughoutDay)); stringBuilder.AppendLine("\tSpawn Curve (Outside): " + CurveToString(level.outsideEnemySpawnChanceThroughDay)); stringBuilder.AppendLine("\tSpawn Curve (Daytime): " + CurveToString(level.daytimeEnemySpawnChanceThroughDay)); stringBuilder.AppendLine("\n\t[INSIDE ENEMIES] (Rarity, MaxCount, PowerLevel, SpawnCurve)"); foreach (SpawnableEnemyWithRarity enemy in level.Enemies) { EnemyType enemyType = enemy.enemyType; stringBuilder.AppendLine($"\t\t{enemyType.enemyName,16} => {enemy.rarity,3}, {enemyType.MaxCount,3}, {enemyType.PowerLevel,3}, {CurveToString(enemyType.probabilityCurve)}"); } stringBuilder.AppendLine("\n\t[OUTSIDE ENEMIES] (Rarity, MaxCount, PowerLevel, SpawnCurve)"); foreach (SpawnableEnemyWithRarity outsideEnemy in level.OutsideEnemies) { EnemyType enemyType2 = outsideEnemy.enemyType; stringBuilder.AppendLine($"\t\t{enemyType2.enemyName,16} => {outsideEnemy.rarity}, {enemyType2.MaxCount}, {enemyType2.PowerLevel}, {CurveToString(enemyType2.probabilityCurve)}"); } stringBuilder.AppendLine("\n\t[DAYTIME ENEMIES] (Rarity, MaxCount, PowerLevel, SpawnCurve)"); foreach (SpawnableEnemyWithRarity daytimeEnemy in level.DaytimeEnemies) { EnemyType enemyType3 = daytimeEnemy.enemyType; stringBuilder.AppendLine($"\t\t{enemyType3.enemyName,16} => {daytimeEnemy.rarity}, {enemyType3.MaxCount}, {enemyType3.PowerLevel}, {CurveToString(enemyType3.probabilityCurve)}"); } stringBuilder.AppendLine("\n\t[MAP OBJECTS] (SpawnCurve, AwayFromWall)"); SpawnableMapObject[] spawnableMapObjects = level.spawnableMapObjects; foreach (SpawnableMapObject val in spawnableMapObjects) { stringBuilder.AppendLine($"\t\t{((Object)val.prefabToSpawn).name,16} => {CurveToString(val.numberToSpawn)}, {val.spawnFacingAwayFromWall}"); } stringBuilder.AppendLine("\n\t[OUTSIDE MAP OBJECTS]"); SpawnableOutsideObjectWithRarity[] spawnableOutsideObjects = level.spawnableOutsideObjects; foreach (SpawnableOutsideObjectWithRarity val2 in spawnableOutsideObjects) { SpawnableOutsideObject spawnableObject = val2.spawnableObject; stringBuilder.AppendLine($"\t\t{((Object)spawnableObject.prefabToSpawn).name,16} => {CurveToString(val2.randomAmount)}, {spawnableObject.spawnFacingAwayFromWall}"); } return stringBuilder.ToString(); } public static double GetWeightAsPercentage(double w, double sum) { if (!(w < 0.0)) { return w / sum * 100.0; } return -1.0; } public static SpawnableEnemyWithRarity FindOutsideEnemy<T>(SelectableLevel level) { SpawnableEnemyWithRarity? obj = ((IEnumerable<SpawnableEnemyWithRarity>)level.OutsideEnemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity x) => x.enemyType.enemyPrefab.GetComponentInChildren<T>() != null)); if (obj == null) { Plugin.LOGGER.LogInfo((object)("Could not find outside enemy in level '" + level.sceneName + "'")); } return obj; } public static SpawnableEnemyWithRarity FindOutsideEnemy<T>() { return StartOfRound.Instance.levels.SelectMany((SelectableLevel x) => x.OutsideEnemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity x) => x.enemyType.enemyPrefab.GetComponentInChildren<T>() != null)); } public static bool EnemyIs<T>(SpawnableEnemyWithRarity obj) { if (obj == null) { return false; } if ((Object)(object)obj.enemyType == (Object)null) { return false; } if ((Object)(object)obj.enemyType.enemyPrefab == (Object)null) { return false; } return obj.enemyType.enemyPrefab.GetComponentInChildren<T>() != null; } public static List<SpawnableScrap> CloneScrap(IEnumerable<SpawnableItemWithRarity> scrap) { return scrap.Select((SpawnableItemWithRarity x) => new SpawnableScrap(x)).ToList(); } public static void ResetEnemyWhere(IEnumerable<SpawnableEnemyWithRarity> xs, Func<SpawnableEnemyWithRarity, bool> predicate) { CollectionExtensions.Do<SpawnableEnemyWithRarity>(xs.Where(predicate), (Action<SpawnableEnemyWithRarity>)delegate(SpawnableEnemyWithRarity x) { x.rarity = 0; x.enemyType.MaxCount = 0; x.enemyType.probabilityCurve = ZeroCurve(); }); } public static void ZeroEnemy(SpawnableEnemyWithRarity enemy) { enemy.rarity = 0; enemy.enemyType.MaxCount = 0; enemy.enemyType.probabilityCurve = ZeroCurve(); } public static SpawnableEnemyWithRarity RandomInsideEnemy(SelectableLevel level) { int index = Random.RandomRangeInt(0, level.Enemies.Count); return level.Enemies[index]; } public static SpawnableEnemyWithRarity RandomOutsideEnemy(SelectableLevel level) { int index = Random.RandomRangeInt(0, level.Enemies.Count); return level.OutsideEnemies[index]; } } public static class GameDefaults { private static bool HasInitialised = false; public static readonly Dictionary<string, Level> s_AllLevels = new Dictionary<string, Level>(); public static readonly Dictionary<string, Enemy> s_AllInsideEnemies = new Dictionary<string, Enemy>(); public static readonly Dictionary<string, Enemy> s_AllOutsideEnemies = new Dictionary<string, Enemy>(); public static readonly Dictionary<string, Enemy> s_AllDaytimeEnemies = new Dictionary<string, Enemy>(); public static readonly HashSet<MapObject> s_AllMapObjects = new HashSet<MapObject>(); public static bool ResetLevel(SelectableLevel level) { if (!s_AllLevels.TryGetValue(level.sceneName, out var value)) { Plugin.LOGGER.LogWarning((object)("Level " + level.sceneName + " does not exist in mapping.")); return false; } value.Reset(level); return true; } [HarmonyPatch(typeof(StartOfRound), "StartGame")] [HarmonyPrefix] public static void InitialiseDefaults(StartOfRound __instance) { Plugin.LOGGER.LogInfo((object)"GameDefaults::InitialiseDefaults(...) Starting"); if (HasInitialised) { return; } SelectableLevel[] levels = __instance.levels; foreach (SelectableLevel val in levels) { Plugin.LOGGER.LogInfo((object)("Storing Defaults For: '" + val.sceneName + "'")); Level level = new Level(val); s_AllLevels.TryAdd(level.SceneName, level); level.InsideEnemies.ForEach(delegate(Enemy x) { s_AllInsideEnemies.TryAdd(x.Name, x); }); level.OutsideEnemies.ForEach(delegate(Enemy x) { s_AllOutsideEnemies.TryAdd(x.Name, x); }); level.DaytimeEnemies.ForEach(delegate(Enemy x) { s_AllDaytimeEnemies.TryAdd(x.Name, x); }); level.MapObjects.ForEach(delegate(MapObject x) { s_AllMapObjects.Add(x); }); } levels = __instance.levels; foreach (SelectableLevel val2 in levels) { foreach (Enemy enemy in s_AllInsideEnemies.Select((KeyValuePair<string, Enemy> x) => x.Value)) { if (val2.Enemies.All((SpawnableEnemyWithRarity x) => x.enemyType.enemyName != enemy.Name)) { val2.Enemies.Add(enemy.Impl); } } } levels = __instance.levels; foreach (SelectableLevel val3 in levels) { List<SpawnableMapObject> list = new List<SpawnableMapObject>(val3.spawnableMapObjects); foreach (MapObject obj in s_AllMapObjects) { if (list.All((SpawnableMapObject x) => ((Object)x.prefabToSpawn).name != ((Object)obj.Prefab).name)) { list.Add(obj.Impl); } } val3.spawnableMapObjects = list.ToArray(); } levels = __instance.levels; for (int i = 0; i < levels.Length; i++) { foreach (SpawnableItemWithRarity item in levels[i].spawnableScrap) { Item spawnableItem = item.spawnableItem; item.spawnableItem.maxValue = Math.Clamp(spawnableItem.maxValue * 10, spawnableItem.minValue, 99999); } } levels = __instance.levels; foreach (SelectableLevel level2 in levels) { Plugin.LOGGER.LogInfo((object)Util.LevelToString(level2)); } HasInitialised = true; Plugin.LOGGER.LogInfo((object)"GameDefaults::InitialiseDefaults() Finished"); } } public abstract class AbstractLevelEvent : IComparable<AbstractLevelEvent> { private const double BASE_WEIGHT = 100.0; private const double WEIGHT_VERY_HIGH = 100.0; public const double WEIGHT_HIGH = 66.66666666666667; public const double WEIGHT_NORMAL = 50.0; public const double WEIGHT_MEDIUM = 40.0; public const double WEIGHT_LOW = 33.333333333333336; public const double WEIGHT_VERY_LOW = 20.0; public const double WEIGHT_EXTREMELY_LOW = 12.5; public const int ORDERING_LOW = -1; public const int ORDERING_HIGH = 1; public readonly string Name; public readonly double Weight; public readonly bool IsAdditive; public readonly int Ordering; private readonly bool IsNaturalOrdering; protected readonly HashSet<string> OrderingTags; private static int s_ColourIndex = 0; private static readonly string[] s_Colours = new string[19] { "#66C7F4", "#FF1053", "#A8C256", "#FED766", "#FFFFFF", "#B497D6", "#75F4F4", "#CE1483", "#06D6A0", "#92AFD7", "#F283B6", "#97CC04", "#B5FFE9", "#6699CC", "#3BC14A", "#92DCE5", "#E2A0FF", "#C1DF1F", "#D972FF" }; protected AbstractLevelEvent(string name, double weight, bool is_additive, int ordering = -1, bool natural_ordering = true, params string[] ordering_tags) { Name = name; Weight = weight; IsAdditive = is_additive; Ordering = ordering; IsNaturalOrdering = natural_ordering; OrderingTags = new HashSet<string>(); foreach (string item in ordering_tags) { OrderingTags.Add(item); } } public abstract bool Apply(ref SelectableLevel level); public virtual void Finalise(SortedSet<AbstractLevelEvent> events) { } public virtual void OnMatchFinished() { } public bool IsGuaranteed() { return Weight < 0.0; } protected bool HasAllOf(params string[] tags) { return tags.All((string tag) => OrderingTags.Contains(tag)); } protected bool HasOneOf(params string[] tags) { return tags.Any((string x) => OrderingTags.Contains(x)); } protected static string NextColour() { string result = s_Colours[s_ColourIndex]; s_ColourIndex = (s_ColourIndex + 1) % s_Colours.Length; return result; } public override string ToString() { return "<color=" + NextColour() + ">" + Name + "</color>"; } public virtual int CompareTo(AbstractLevelEvent other) { if (Name == other.Name) { return 0; } if (!other.IsNaturalOrdering) { return other.CompareTo(this) * -1; } return Ordering; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is AbstractLevelEvent abstractLevelEvent) { return abstractLevelEvent.Name == Name; } return false; } public override int GetHashCode() { return Name.GetHashCode(); } } public class Enemy { public readonly string Name; public readonly SpawnableEnemyWithRarity Impl; public readonly GameObject Prefab; public readonly EnemyType Type; public readonly int Rarity; public readonly int MaxCount; public readonly AnimationCurve SpawnCurve; public readonly AnimationCurve FalloffCurve; public readonly bool IsDaytimeEnemy; public readonly bool IsOutsideEnemy; public Enemy(SpawnableEnemyWithRarity enemy) { Name = enemy.enemyType.enemyName; Impl = enemy; Prefab = enemy.enemyType.enemyPrefab; Type = enemy.enemyType; Rarity = enemy.rarity; MaxCount = enemy.enemyType.MaxCount; SpawnCurve = Util.CloneCurve(enemy.enemyType.probabilityCurve); FalloffCurve = Util.CloneCurve(enemy.enemyType.numberSpawnedFalloff); IsDaytimeEnemy = enemy.enemyType.isDaytimeEnemy; IsOutsideEnemy = enemy.enemyType.isOutsideEnemy; } public void Reset(SpawnableEnemyWithRarity enemy) { enemy.rarity = Rarity; enemy.enemyType.MaxCount = MaxCount; enemy.enemyType.probabilityCurve = Util.CloneCurve(SpawnCurve); enemy.enemyType.numberSpawnedFalloff = Util.CloneCurve(FalloffCurve); enemy.enemyType.isDaytimeEnemy = IsDaytimeEnemy; enemy.enemyType.isOutsideEnemy = IsOutsideEnemy; } public override int GetHashCode() { return Name.GetHashCode(); } } public class MapObject { public readonly GameObject Prefab; public readonly AnimationCurve SpawnCurve; public readonly SpawnableMapObject Impl; public MapObject(SpawnableMapObject obj) { Prefab = obj.prefabToSpawn; SpawnCurve = Util.CloneCurve(obj.numberToSpawn); Impl = obj; } public void Reset(SpawnableMapObject obj) { obj.numberToSpawn = Util.CloneCurve(SpawnCurve); } public override int GetHashCode() { return ((object)Impl).GetHashCode(); } } public class SpawnableScrap { public readonly Item Impl; public readonly int Rarity; public readonly bool IsScrap; public readonly int CreditsWorth; public readonly int HighestSalePercentage; public readonly int MaxValue; public readonly int MinValue; public string ItemName => Impl.itemName; public SpawnableScrap(SpawnableItemWithRarity item) { Impl = item.spawnableItem; Rarity = item.rarity; IsScrap = item.spawnableItem.isScrap; CreditsWorth = item.spawnableItem.creditsWorth; HighestSalePercentage = item.spawnableItem.highestSalePercentage; MaxValue = item.spawnableItem.maxValue; MinValue = item.spawnableItem.minValue; } public void Reset(SpawnableItemWithRarity item) { item.spawnableItem = Impl; item.rarity = Rarity; item.spawnableItem.isScrap = IsScrap; item.spawnableItem.creditsWorth = CreditsWorth; item.spawnableItem.highestSalePercentage = HighestSalePercentage; item.spawnableItem.maxValue = MaxValue; item.spawnableItem.minValue = MinValue; } public override int GetHashCode() { return ((object)Impl).GetHashCode(); } public override string ToString() { return $"{ItemName,32}, {Rarity,3}," + $" [{MinValue,3} .. {MaxValue,3}], {CreditsWorth,3}"; } } public class Level { public readonly string SceneName; public readonly SelectableLevel Impl; public readonly int MinScrap; public readonly int MaxScrap; public readonly int MinScrapValue; public readonly int MaxScrapValue; public readonly int MaxEnemyPowerCount; public readonly int MaxOutsideEnemyPowerCount; public readonly int MaxDaytimeEnemyPowerCount; public readonly AnimationCurve EnemySpawnChanceThroughoutDay; public readonly AnimationCurve OutsideEnemySpawnChanceThroughDay; public readonly AnimationCurve DaytimeEnemySpawnChanceThroughDay; public readonly float SpawnProbabilityRange; public readonly float DaytimeEnemiesProbabilityRange; public readonly List<Enemy> InsideEnemies; public readonly List<Enemy> OutsideEnemies; public readonly List<Enemy> DaytimeEnemies; public readonly List<MapObject> MapObjects; public readonly List<SpawnableScrap> Scrap; public Level(SelectableLevel level) { SceneName = level.sceneName; Impl = level; MinScrap = level.minScrap; MaxScrap = level.maxScrap; MinScrapValue = level.minTotalScrapValue; MaxScrapValue = level.maxTotalScrapValue; MaxEnemyPowerCount = level.maxEnemyPowerCount; MaxOutsideEnemyPowerCount = level.maxOutsideEnemyPowerCount; MaxDaytimeEnemyPowerCount = level.maxDaytimeEnemyPowerCount; EnemySpawnChanceThroughoutDay = Util.CloneCurve(level.enemySpawnChanceThroughoutDay); OutsideEnemySpawnChanceThroughDay = Util.CloneCurve(level.outsideEnemySpawnChanceThroughDay); DaytimeEnemySpawnChanceThroughDay = Util.CloneCurve(level.daytimeEnemySpawnChanceThroughDay); SpawnProbabilityRange = level.spawnProbabilityRange; DaytimeEnemiesProbabilityRange = level.daytimeEnemiesProbabilityRange; InsideEnemies = Util.CloneEnemies(level.Enemies); OutsideEnemies = Util.CloneEnemies(level.OutsideEnemies); DaytimeEnemies = Util.CloneEnemies(level.DaytimeEnemies); MapObjects = Util.CloneMapObjects(level.spawnableMapObjects); Scrap = Util.CloneScrap(level.spawnableScrap); } public void Reset(SelectableLevel level) { level.minScrap = MinScrap; level.maxScrap = MaxScrap; level.minTotalScrapValue = MinScrapValue; level.maxTotalScrapValue = MaxScrapValue; level.maxEnemyPowerCount = MaxEnemyPowerCount; level.maxOutsideEnemyPowerCount = MaxOutsideEnemyPowerCount; level.maxDaytimeEnemyPowerCount = MaxDaytimeEnemyPowerCount; level.enemySpawnChanceThroughoutDay = Util.CloneCurve(EnemySpawnChanceThroughoutDay); level.outsideEnemySpawnChanceThroughDay = Util.CloneCurve(OutsideEnemySpawnChanceThroughDay); level.daytimeEnemySpawnChanceThroughDay = Util.CloneCurve(DaytimeEnemySpawnChanceThroughDay); level.spawnProbabilityRange = SpawnProbabilityRange; level.daytimeEnemiesProbabilityRange = DaytimeEnemiesProbabilityRange; level.Enemies.ForEach(delegate(SpawnableEnemyWithRarity a) { ResetEnemyOrZeroOut(a, InsideEnemies); }); level.DaytimeEnemies.ForEach(delegate(SpawnableEnemyWithRarity a) { ResetEnemyOrZeroOut(a, DaytimeEnemies); }); level.OutsideEnemies.ForEach(delegate(SpawnableEnemyWithRarity a) { ResetEnemyOrZeroOut(a, OutsideEnemies); }); SpawnableMapObject[] spawnableMapObjects = level.spawnableMapObjects; foreach (SpawnableMapObject obj in spawnableMapObjects) { MapObject mapObject = MapObjects.FirstOrDefault((MapObject x) => ((Object)obj.prefabToSpawn).name == ((Object)x.Prefab).name); if (mapObject == null) { obj.numberToSpawn = Util.ZeroCurve(); } else { mapObject.Reset(obj); } } foreach (SpawnableItemWithRarity scrap in level.spawnableScrap) { Scrap.FirstOrDefault((SpawnableScrap x) => scrap.spawnableItem.itemName == x.ItemName)?.Reset(scrap); } static void ResetEnemyOrZeroOut(SpawnableEnemyWithRarity enemy, IEnumerable<Enemy> enemies) { Enemy enemy2 = enemies.FirstOrDefault((Enemy x) => x.Name == enemy.enemyType.enemyName); if (enemy2 == null) { enemy.rarity = 0; enemy.enemyType.MaxCount = 0;