Decompiled source of LCCustomDifficulty v1.3.0
LCCustomDifficulty.dll
Decompiled 11 months 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;